VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp@ 103480

最後變更 在這個檔案從103480是 103480,由 vboxsync 提交於 13 月 前

Shared Clipboard: Added a ShClTransferTransformPath() function to make the paths more uniform. bugref:9437

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keyword 設為 Id
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 106.4 KB
 
1/* $Id: VBoxGuestR3LibClipboard.cpp 103480 2024-02-20 15:21:35Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <VBox/GuestHost/SharedClipboard.h>
42#include <VBox/GuestHost/clipboard-helper.h>
43#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
44# include <VBox/GuestHost/SharedClipboard-transfers.h>
45#endif
46#include <VBox/HostServices/VBoxClipboardSvc.h>
47#include <VBox/err.h>
48#include <iprt/assert.h>
49#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
50# include <iprt/dir.h>
51# include <iprt/file.h>
52# include <iprt/path.h>
53#endif
54#include <iprt/string.h>
55#include <iprt/cpp/ministring.h>
56
57#ifdef LOG_GROUP
58 #undef LOG_GROUP
59#endif
60#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
61#include <VBox/log.h>
62
63#include "VBoxGuestR3LibInternal.h"
64
65
66/*
67 * Function naming convention:
68 *
69 * FunctionNameRecv = Receives a host message (request).
70 * FunctionNameReply = Replies to a host message (request).
71 * FunctionNameSend = Sends a guest message to the host.
72 */
73
74
75/*********************************************************************************************************************************
76* Prototypes *
77*********************************************************************************************************************************/
78
79
80/**
81 * Connects to the Shared Clipboard service, legacy version, do not use anymore.
82 *
83 * @returns VBox status code
84 * @param pidClient Where to put the client id on success. The client id
85 * must be passed to all the other clipboard calls.
86 */
87VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
88{
89 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
90 if (RT_FAILURE(rc))
91 {
92 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
93 LogRel(("Shared Clipboard: Unabled to connect, as host service was not found, skipping\n"));
94 else
95 LogRel(("Shared Clipboard: Unabled to connect to host service, rc=%Rrc\n", rc));
96 }
97 LogFlowFuncLeaveRC(rc);
98 return rc;
99}
100
101
102/**
103 * Connects to the Shared Clipboard service, extended version.
104 *
105 * @returns VBox status code.
106 * @param pCtx Command context. This will be initialized by this
107 * call.
108 * @param fGuestFeatures The guest features supported by this client,
109 * VBOX_SHCL_GF_0_XXX.
110 */
111VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures)
112{
113 /*
114 * Intialize the context structure.
115 */
116 pCtx->idClient = 0;
117 pCtx->fGuestFeatures = fGuestFeatures;
118 pCtx->fHostFeatures = 0;
119 pCtx->fUseLegacyProtocol = true;
120 pCtx->idContext = 0;
121
122#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
123 /* Init callback table. */
124 RT_ZERO(pCtx->Transfers.Callbacks);
125 /* Indicate that this guest supports Shared Clipboard file transfers. */
126 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS;
127# ifdef RT_OS_WINDOWS
128 /* Indicate that on Windows guest OSes we have our own IDataObject implementation which
129 * integrates nicely into the guest's Windows Explorer showing / handling the Shared Clipboard file transfers. */
130 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS_FRONTEND;
131# endif
132 pCtx->Transfers.cbChunkSize = VBOX_SHCL_DEFAULT_CHUNK_SIZE; /** @todo Make this configurable. */
133 pCtx->Transfers.cbMaxChunkSize = VBOX_SHCL_MAX_CHUNK_SIZE; /** @todo Ditto. */
134#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
135
136 /*
137 * First step is connecting to the HGCM service.
138 */
139 int rc = VbglR3ClipboardConnect(&pCtx->idClient);
140 if (RT_SUCCESS(rc))
141 {
142 /*
143 * Next is reporting our features. If this fails, assume older host.
144 */
145 rc = VbglR3ClipboardReportFeatures(pCtx->idClient, pCtx->fGuestFeatures, &pCtx->fHostFeatures);
146 if (RT_SUCCESS(rc))
147 {
148 LogRel2(("Shared Clipboard: Guest features: %#RX64 - Host features: %#RX64\n",
149 pCtx->fGuestFeatures, pCtx->fHostFeatures));
150
151 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID)
152 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_CONTEXT_ID) )
153 {
154 pCtx->fUseLegacyProtocol = false;
155
156#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
157 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)
158 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_TRANSFERS) )
159 {
160 VBoxShClParmNegotiateChunkSize MsgChunkSize;
161 RT_ZERO(MsgChunkSize);
162 do
163 {
164 VBGL_HGCM_HDR_INIT(&MsgChunkSize.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE,
165 VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE);
166 MsgChunkSize.cb32MaxChunkSize.SetUInt32(pCtx->Transfers.cbMaxChunkSize);
167 MsgChunkSize.cb32ChunkSize.SetUInt32(0); /* If set to 0, let the host choose. */
168 rc = VbglR3HGCMCall(&MsgChunkSize.hdr, sizeof(MsgChunkSize));
169 } while (rc == VERR_INTERRUPTED);
170 if (RT_SUCCESS(rc))
171 {
172 Assert(MsgChunkSize.cb32ChunkSize.type == VMMDevHGCMParmType_32bit);
173 pCtx->Transfers.cbChunkSize = RT_MIN(MsgChunkSize.cb32ChunkSize.u.value32, pCtx->Transfers.cbChunkSize);
174 Assert(MsgChunkSize.cb32MaxChunkSize.type == VMMDevHGCMParmType_32bit);
175 pCtx->Transfers.cbMaxChunkSize = RT_MIN(MsgChunkSize.cb32MaxChunkSize.u.value32, pCtx->Transfers.cbMaxChunkSize);
176
177 LogRel2(("Shared Clipboard: Using chunk size %RU32 (maximum is %RU32)\n",
178 pCtx->Transfers.cbChunkSize, pCtx->Transfers.cbMaxChunkSize));
179 }
180 }
181 else
182 {
183 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
184 LogRel(("Shared Clipboard: Host does not support transfers\n"));
185 }
186#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
187 }
188 else
189 {
190 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID))
191 LogRel(("Shared Clipboard: Host does not support context IDs, using legacy protocol\n"));
192
193 pCtx->fUseLegacyProtocol = true;
194 }
195 }
196 else
197 {
198 AssertLogRelMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED,
199 ("Reporting features failed: %Rrc\n", rc));
200 pCtx->fUseLegacyProtocol = true;
201 }
202 }
203
204 LogFlowFuncLeaveRC(rc);
205 return rc;
206}
207
208
209/**
210 * Reports features to the host and retrieve host feature set.
211 *
212 * @returns VBox status code.
213 * @param idClient The client ID returned by VbglR3ClipboardConnect().
214 * @param fGuestFeatures Features to report, VBOX_SHCL_GF_XXX.
215 * @param pfHostFeatures Where to store the features VBOX_SHCL_HF_XXX.
216 */
217VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures)
218{
219 int rc;
220 do
221 {
222 struct
223 {
224 VBGLIOCHGCMCALL Hdr;
225 HGCMFunctionParameter f64Features0;
226 HGCMFunctionParameter f64Features1;
227 } Msg;
228
229 RT_ZERO(Msg);
230
231 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FEATURES, 2);
232 VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures);
233 VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_SHCL_GF_1_MUST_BE_ONE);
234
235 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
236 if (RT_SUCCESS(rc))
237 {
238 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
239 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
240 if (Msg.f64Features1.u.value64 & VBOX_SHCL_GF_1_MUST_BE_ONE)
241 rc = VERR_NOT_SUPPORTED;
242 else if (pfHostFeatures)
243 *pfHostFeatures = Msg.f64Features0.u.value64;
244 break;
245 }
246 } while (rc == VERR_INTERRUPTED);
247 return rc;
248
249}
250
251
252/**
253 * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
254 *
255 * @returns VBox status code.
256 * @param idClient The client id returned by VbglR3ClipboardConnect().
257 */
258VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
259{
260 return VbglR3HGCMDisconnect(idClient);
261}
262
263
264/**
265 * Disconnects from the Shared Clipboard service, extended version.
266 *
267 * @returns VBox status code.
268 * @param pCtx Shared Clipboard command context to use for the connection.
269 */
270VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
271{
272 int rc = VbglR3ClipboardDisconnect(pCtx->idClient);
273 if (RT_SUCCESS(rc))
274 {
275 pCtx->idClient = 0;
276 }
277
278 LogFlowFuncLeaveRC(rc);
279 return rc;
280}
281
282
283/**
284 * Receives reported formats from the host.
285 *
286 * @returns VBox status code.
287 * @param pCtx Shared Clipboard command context to use for the
288 * connection.
289 * @param pfFormats Where to store the received formats from the host.
290 */
291static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATS pfFormats)
292{
293 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
294 AssertPtrReturn(pfFormats, VERR_INVALID_POINTER);
295
296 *pfFormats = 0;
297
298 struct
299 {
300 VBGLIOCHGCMCALL Hdr;
301 HGCMFunctionParameter id64Context;
302 HGCMFunctionParameter f32Formats;
303 } Msg;
304
305 RT_ZERO(Msg);
306
307 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
308 Msg.id64Context.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
309 Msg.f32Formats.SetUInt32(0);
310
311 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
312 if (RT_SUCCESS(rc))
313 {
314 rc = Msg.f32Formats.GetUInt32(pfFormats);
315 AssertRC(rc);
316 }
317
318 LogFlowFuncLeaveRC(rc);
319 return rc;
320}
321
322
323/**
324 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA_CID message.
325 *
326 * @returns VBox status code.
327 * @param pCtx Shared Clipboard command context to use for the connection.
328 * @param pfFormat Where to return the requested format.
329 */
330static int vbglR3ClipboardFetchReadDataCid(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
331{
332 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
333 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
334
335 struct
336 {
337 VBGLIOCHGCMCALL Hdr;
338 HGCMFunctionParameter id64Context;
339 HGCMFunctionParameter f32Format;
340 } Msg;
341
342 RT_ZERO(Msg);
343
344 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
345 Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
346 Msg.f32Format.SetUInt32(0);
347
348 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
349 if (RT_SUCCESS(rc))
350 {
351 rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
352 AssertRC(rc);
353 int rc2 = Msg.f32Format.GetUInt32(pfFormat);
354 AssertRCStmt(rc2, rc = rc2);
355 }
356
357 LogFlowFuncLeaveRC(rc);
358 return rc;
359}
360
361
362/**
363 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA message.
364 *
365 * @returns VBox status code.
366 * @param pCtx Shared Clipboard command context to use for the connection.
367 * @param pfFormat Where to return the requested format.
368 */
369static int vbglR3ClipboardFetchReadData(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
370{
371 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
372 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
373
374 struct
375 {
376 VBGLIOCHGCMCALL Hdr;
377 HGCMFunctionParameter id32Msg;
378 HGCMFunctionParameter f32Format;
379 } Msg;
380
381 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
382 Msg.id32Msg.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
383 Msg.f32Format.SetUInt32(0);
384
385 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
386 if (RT_SUCCESS(rc))
387 {
388 rc = Msg.f32Format.GetUInt32(pfFormat);
389 AssertRC(rc);
390 }
391
392 LogFlowFuncLeaveRC(rc);
393 return rc;
394}
395
396
397/**
398 * Get a host message, legacy version (which does not have VBOX_SHCL_GUEST_FN_MSG_GET). Do not use anymore.
399 *
400 * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
401 * to not break compatibility with older additions / VBox versions.
402 *
403 * This will block until a message becomes available.
404 *
405 * @returns VBox status code.
406 * @param idClient The client id returned by VbglR3ClipboardConnect().
407 * @param pidMsg Where to store the message id.
408 * @param pfFormats Where to store the format(s) the message applies to.
409 */
410VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
411{
412 VBoxShClGetHostMsgOld Msg;
413
414 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
415 VbglHGCMParmUInt32Set(&Msg.msg, 0);
416 VbglHGCMParmUInt32Set(&Msg.formats, 0);
417
418 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
419 if (RT_SUCCESS(rc))
420 {
421 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
422 if (RT_SUCCESS(rc))
423 {
424 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
425 if (RT_SUCCESS(rc2))
426 return rc;
427 }
428 rc = rc2;
429 }
430 *pidMsg = UINT32_MAX - 1;
431 *pfFormats = UINT32_MAX;
432 return rc;
433}
434
435
436/**
437 * Reads data from the host clipboard.
438 *
439 * @returns VBox status code.
440 * @retval VINF_BUFFER_OVERFLOW if there is more data available than the caller provided buffer space for.
441 * @param idClient The client id returned by VbglR3ClipboardConnect().
442 * @param fFormat The format we're requesting the data in.
443 * @param pvData Where to store the data.
444 * @param cbData The size of the buffer pointed to by \a pvData.
445 * This also indicates the maximum size to read.
446 * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData.
447 */
448VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pvData, uint32_t cbData,
449 uint32_t *pcbRead)
450{
451 LogFlowFunc(("fFormat=%#x, pvData=%p, cbData=%RU32\n", fFormat, pvData, cbData));
452
453 struct
454 {
455 VBGLIOCHGCMCALL Hdr;
456 VBoxShClParmDataRead Parms;
457 } Msg;
458
459 RT_ZERO(Msg);
460
461 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_DATA_READ);
462 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
463 VbglHGCMParmPtrSet( &Msg.Parms.pData, pvData, cbData);
464 VbglHGCMParmUInt32Set(&Msg.Parms.cb32Needed, 0);
465
466 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
467 if (RT_SUCCESS(rc))
468 {
469 uint32_t cbRead;
470 rc = VbglHGCMParmUInt32Get(&Msg.Parms.cb32Needed, &cbRead);
471 if (RT_SUCCESS(rc))
472 {
473 LogFlowFunc(("cbRead=%RU32\n", cbRead));
474
475 if (cbRead > cbData)
476 rc = VINF_BUFFER_OVERFLOW;
477
478 *pcbRead = cbRead;
479 }
480 }
481
482 LogFlowFuncLeaveRC(rc);
483 return rc;
484}
485
486
487/**
488 * Reads clipboard data from the host clipboard.
489 *
490 * @returns VBox status code.
491 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
492 *
493 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
494 * @param uFormat Clipboard format of clipboard data to be read.
495 * @param ppvData Buffer where return the newly allocated read clipboard data on success.
496 * Needs to be free'd by the caller.
497 * @param pcbData Size (in bytes) of clipboard data read on success.
498 */
499VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx,
500 SHCLFORMAT uFormat, void **ppvData, uint32_t *pcbData)
501{
502 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
503 AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
504 AssertReturn(pcbData, VERR_INVALID_PARAMETER);
505
506 int rc;
507
508 uint32_t cbRead = 0;
509 uint32_t cbData = _4K;
510
511 void *pvData = RTMemAlloc(cbData);
512 if (pvData)
513 {
514 rc = VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, &cbRead);
515
516 /*
517 * A return value of VINF_BUFFER_OVERFLOW tells us to try again with a
518 * larger buffer. The size of the buffer needed is placed in *pcb.
519 * So we start all over again.
520 */
521 if ( rc == VINF_BUFFER_OVERFLOW
522 && cbRead)
523 {
524 /* cbRead contains the size required. */
525 pvData = RTMemReallocZ(pvData, cbData, cbRead);
526 cbData = cbRead;
527 if (pvData)
528 {
529 rc = VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, &cbRead);
530 if (RT_SUCCESS(rc))
531 {
532 if (cbRead != cbData) /* The data size must match now. */
533 rc = VERR_MISMATCH;
534 }
535 else
536 {
537 if (rc == VINF_BUFFER_OVERFLOW)
538 rc = VERR_BUFFER_OVERFLOW;
539 }
540 }
541 else
542 rc = VERR_NO_MEMORY;
543 }
544
545 if (RT_SUCCESS(rc))
546 {
547 *pcbData = cbRead; /* Actual bytes read. */
548 *ppvData = pvData;
549 }
550 }
551 else
552 rc = VERR_NO_MEMORY;
553
554 if (!cbRead)
555 rc = VERR_SHCLPB_NO_DATA;
556
557 if (RT_FAILURE(rc))
558 {
559 RTMemFree(pvData);
560 LogRel(("Shared Clipboard: Reading clipboard data in format %#x from host failed with %Rrc\n", uFormat, rc));
561 }
562
563 return rc;
564}
565
566
567/**
568 * Query the host features.
569 *
570 * @returns VBox status code.
571 * @param idClient The client ID returned by VbglR3ClipboardConnect().
572 * @param pfHostFeatures Where to store the host feature, VBOX_SHCL_HF_XXX.
573 */
574VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures)
575{
576 int rc;
577 do
578 {
579 struct
580 {
581 VBGLIOCHGCMCALL Hdr;
582 HGCMFunctionParameter f64Features0;
583 HGCMFunctionParameter f64Features1;
584 } Msg;
585 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_QUERY_FEATURES, 2);
586 VbglHGCMParmUInt64Set(&Msg.f64Features0, 0);
587 VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63));
588
589 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
590 if (RT_SUCCESS(rc))
591 {
592 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
593 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
594 if (Msg.f64Features1.u.value64 & RT_BIT_64(63))
595 rc = VERR_NOT_SUPPORTED;
596 else if (pfHostFeatures)
597 *pfHostFeatures = Msg.f64Features0.u.value64;
598 break;
599 }
600 } while (rc == VERR_INTERRUPTED);
601 return rc;
602
603}
604
605/**
606 * Peeks at the next host message, extended version.
607 *
608 * This glosses over the difference between new (6.1) and old (1.3.2) host
609 * service versions, however it does so by abusing @a pcParameters, so don't use
610 * it directly when in legacy mode, always pass it on to
611 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
612 *
613 * @returns VBox status code.
614 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
615 * caller just have to repeat this call.
616 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
617 * @retval VERR_TRY_AGAIN if no new message is available.
618 *
619 * @param pCtx Shared Clipboard command context to use for the connection.
620 * @param fWait Wait for new messages to arrive if \c true, return immediately if \c false.
621 * @param pidMsg Where to store the message id.
622 * @param pcParameters Where to store the number of parameters which will
623 * be received in a second call to the host.
624 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
625 * for the VM restore check. Optional.
626 *
627 * @note Restore check is only performed optimally with a 6.0 host.
628 */
629static int vbglR3ClipboardMsgPeekEx(PVBGLR3SHCLCMDCTX pCtx, bool fWait, uint32_t *pidMsg,
630 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
631{
632 AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
633 AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
634
635 struct
636 {
637 VBGLIOCHGCMCALL Hdr;
638 HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
639 HGCMFunctionParameter cParameters;
640 } Msg;
641 int rc;
642
643 RT_ZERO(Msg);
644
645 if (!pCtx->fUseLegacyProtocol)
646 {
647 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient,
648 fWait ? VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT
649 : VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT, 2);
650 VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
651 VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
652 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
653 Log4Func(("VbglR3HGCMCall -> %Rrc\n", rc));
654 if (RT_SUCCESS(rc))
655 {
656 AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
657 && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
658 ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
659 VERR_INTERNAL_ERROR_3);
660
661 *pidMsg = (uint32_t)Msg.idMsg.u.value64;
662 *pcParameters = Msg.cParameters.u.value32;
663 return rc;
664 }
665
666 /*
667 * If restored, update pidRestoreCheck.
668 */
669 if (rc == VERR_VM_RESTORED && pidRestoreCheck)
670 *pidRestoreCheck = Msg.idMsg.u.value64;
671 }
672 else
673 {
674 /*
675 * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
676 * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
677 * VbglR3ClipboardEventGetNextEx, so that's fine...
678 */
679 rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
680 if (RT_SUCCESS(rc))
681 return rc;
682 }
683
684 /*
685 * If interrupted we must cancel the call so it doesn't prevent us from making another one.
686 */
687 if (rc == VERR_INTERRUPTED)
688 {
689 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
690 int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
691 AssertRC(rc2);
692 }
693
694 *pidMsg = UINT32_MAX - 1;
695 *pcParameters = UINT32_MAX - 2;
696 return rc;
697}
698
699/**
700 * Peeks at the next host message, waiting for one to turn up.
701 *
702 * This glosses over the difference between new (6.1) and old (1.3.2) host
703 * service versions, however it does so by abusing @a pcParameters, so don't use
704 * it directly when in legacy mode, always pass it on to
705 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
706 *
707 * @returns VBox status code.
708 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
709 * caller just have to repeat this call.
710 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
711 *
712 * @param pCtx Shared Clipboard command context to use for the connection.
713 * @param pidMsg Where to store the message id.
714 * @param pcParameters Where to store the number of parameters which will
715 * be received in a second call to the host.
716 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
717 * for the VM restore check. Optional.
718 *
719 * @note Restore check is only performed optimally with a 6.0 host.
720 */
721VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
722 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
723{
724 return vbglR3ClipboardMsgPeekEx(pCtx, true /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
725}
726
727/**
728 * Peeks at the next host message, returning immediately.
729 *
730 * This glosses over the difference between new (6.1) and old (1.3.2) host
731 * service versions, however it does so by abusing @a pcParameters, so don't use
732 * it directly when in legacy mode, always pass it on to
733 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
734 *
735 * @returns VBox status code.
736 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
737 * caller just have to repeat this call.
738 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
739 * @retval VERR_TRY_AGAIN if no new message is available.
740 *
741 * @param pCtx Shared Clipboard command context to use for the connection.
742 * @param pidMsg Where to store the message id.
743 * @param pcParameters Where to store the number of parameters which will
744 * be received in a second call to the host.
745 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
746 * for the VM restore check. Optional.
747 *
748 * @note Restore check is only performed optimally with a 6.0 host.
749 */
750VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
751 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
752{
753 return vbglR3ClipboardMsgPeekEx(pCtx, false /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
754}
755
756#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
757
758/**
759 * Reads a transfer root list header from the host.
760 *
761 * @returns VBox status code.
762 * @param pCtx Shared Clipboard command context to use for the connection.
763 * @param pRootListHdr Where to store the received root list header.
764 */
765static int vbglR3ClipboardTransferRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
766{
767 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
768 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
769
770 VBoxShClRootListHdrMsg Msg;
771
772 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
773 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
774
775 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
776 Msg.ReqParms.fRoots.SetUInt32(0);
777
778 Msg.cRoots.SetUInt64(0);
779
780 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
781 if (RT_SUCCESS(rc))
782 {
783 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fFeatures); AssertRC(rc);
784 if (RT_SUCCESS(rc))
785 {
786 rc = Msg.cRoots.GetUInt64(&pRootListHdr->cEntries);
787 AssertRC(rc);
788
789 pRootListHdr->cbTotalSize = 0; /* Unused for the root list header. */
790 }
791 }
792 else
793 LogRel(("Shared Clipboard: Reading root list header failed: %Rrc\n", rc));
794
795 LogFlowFuncLeaveRC(rc);
796 return rc;
797}
798
799/**
800 * Reads a transfer root list entry from the host.
801 *
802 * @returns VBox status code.
803 * @param pCtx Shared Clipboard command context to use for the connection.
804 * @param uIndex Index of root list entry to read.
805 * @param pRootListEntry Where to store the root list entry read from the host.
806 */
807static int vbglR3ClipboardTransferRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint64_t uIndex, PSHCLLISTENTRY pRootListEntry)
808{
809 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
810 AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
811
812 VBoxShClRootListEntryMsg Msg;
813
814 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
815 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
816
817 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
818
819 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
820 Msg.Parms.fInfo.SetUInt32(fInfo);
821 Msg.Parms.uIndex.SetUInt64(uIndex);
822
823 char szName[SHCLLISTENTRY_MAX_NAME];
824 Msg.szName.SetPtr(szName, sizeof(szName));
825
826 void *pvInfo = NULL;
827 uint32_t cbInfo = 0;
828
829 int rc = VINF_SUCCESS;
830
831 if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
832 {
833 cbInfo = sizeof(SHCLFSOBJINFO);
834 pvInfo = RTMemAlloc(cbInfo);
835 if (!pvInfo)
836 rc = VERR_NO_MEMORY;
837 }
838
839 if (RT_SUCCESS(rc))
840 {
841 Msg.cbInfo.SetUInt32(cbInfo);
842 Msg.pvInfo.SetPtr(pvInfo, cbInfo);
843
844 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
845 if (RT_SUCCESS(rc))
846 {
847 uint32_t fInfoRet;
848 rc = Msg.Parms.fInfo.GetUInt32(&fInfoRet);
849 if (RT_SUCCESS(rc))
850 {
851 AssertMsgStmt((fInfoRet & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO,
852 ("Host returned unknown root entry info flags (%#x)\n", fInfoRet), rc = VERR_INVALID_PARAMETER);
853 if (RT_SUCCESS(rc))
854 {
855 uint32_t cbInfoRet = 0;
856 rc = Msg.cbInfo.GetUInt32(&cbInfoRet);
857 if (RT_SUCCESS(rc))
858 {
859 AssertMsgStmt(cbInfo == cbInfoRet,
860 ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
861 if (RT_SUCCESS(rc))
862 rc = ShClTransferListEntryInitEx(pRootListEntry, fInfo, szName, pvInfo, cbInfo);
863 if (RT_SUCCESS(rc))
864 {
865 pvInfo = NULL; /* Entry took ownership of pvInfo now. */
866 cbInfo = 0;
867 }
868 }
869 }
870 }
871 }
872 else
873 LogRel(("Shared Clipboard: Reading root list entry failed: %Rrc\n", rc));
874 }
875
876 RTMemFree(pvInfo);
877
878 LogFlowFuncLeaveRC(rc);
879 return rc;
880}
881
882/**
883 * Reads the transfer root list from the host.
884 *
885 * @returns VBox status code.
886 * @param pCtx Shared Clipboard command context to use for the connection.
887 * @param pTransfer Transfer to read root list for.
888 * Must be in INITIALIZED state.
889 */
890VBGLR3DECL(int) VbglR3ClipboardTransferRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer)
891{
892 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
893 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
894
895 SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
896 AssertMsgReturn( enmSts == SHCLTRANSFERSTATUS_INITIALIZED
897 || enmSts == SHCLTRANSFERSTATUS_STARTED,
898 ("Can't read root list -- wrong transfer status (%#x)\n", enmSts), VERR_WRONG_ORDER);
899
900 SHCLLISTHDR Hdr;
901 int rc = vbglR3ClipboardTransferRootListHdrRead(pCtx, &Hdr);
902 if (RT_SUCCESS(rc))
903 {
904 LogFlowFunc(("cEntries=%RU64, cTotalSize=%RU64\n", Hdr.cEntries, Hdr.cbTotalSize));
905
906 if (!Hdr.cEntries) /* Should never happen (tm). */
907 {
908#ifdef DEBUG_andy
909 AssertFailed();
910#endif
911 LogRel(("Shared Clipboard: Warning: Transfer %RU32 has no entries\n", ShClTransferGetID(pTransfer)));
912 }
913
914 for (uint64_t i = 0; i < Hdr.cEntries; i++)
915 {
916 PSHCLLISTENTRY pEntry = NULL;
917 rc = ShClTransferListEntryAlloc(&pEntry);
918 if (RT_SUCCESS(rc))
919 {
920 rc = vbglR3ClipboardTransferRootListEntryRead(pCtx, i, pEntry);
921 if (RT_SUCCESS(rc))
922 rc = ShClTransferListAddEntry(&pTransfer->lstRoots, pEntry, true /* fAppend */);
923 }
924
925 if (RT_FAILURE(rc))
926 {
927 ShClTransferListEntryFree(pEntry);
928 break;
929 }
930 }
931 }
932 else
933 LogRel(("Shared Clipboard: Reading root list for transfer %RU16 failed: %Rrc\n", ShClTransferGetID(pTransfer), rc));
934
935 LogFlowFuncLeaveRC(rc);
936 return rc;
937}
938
939/**
940 * Receives a transfer status from the host.
941 *
942 * @returns VBox status code.
943 * @param pCtx Shared Clipboard command context to use for the connection.
944 * @param pEnmDir Where to store the transfer direction for the reported transfer.
945 * @param pReport Where to store the transfer (status) report.
946 */
947VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
948 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
949{
950 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
951 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
952 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
953
954 VBoxShClTransferStatusMsg Msg;
955 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
956 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
957
958 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
959 Msg.enmDir.SetUInt32(0);
960 Msg.enmStatus.SetUInt32(0);
961 Msg.rc.SetUInt32(0);
962 Msg.fFlags.SetUInt32(0);
963
964 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
965 if (RT_SUCCESS(rc))
966 {
967 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
968 if (RT_SUCCESS(rc))
969 {
970 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
971 AssertRC(rc);
972 }
973 if (RT_SUCCESS(rc))
974 {
975 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
976 AssertRC(rc);
977 }
978 if (RT_SUCCESS(rc))
979 {
980 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
981 AssertRC(rc);
982 }
983 if (RT_SUCCESS(rc))
984 {
985 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
986 AssertRC(rc);
987 }
988 }
989
990 LogFlowFuncLeaveRC(rc);
991 return rc;
992}
993
994/**
995 * Sends a transfer status to the host, extended version.
996 *
997 * @returns VBox status code.
998 * @param pCtx Shared Clipboard command context to use for the connection.
999 * @param uCID Context ID to use.
1000 * The transfer ID is part of this.
1001 * @param uStatus Tranfer status to send.
1002 * @param rcTransfer Result code (rc) to send.
1003 */
1004static int vbglR3ClipboardTransferSendStatusEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t uCID,
1005 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
1006{
1007 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1008
1009 VBoxShClReplyMsg Msg;
1010 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1011 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1012
1013 Msg.uContext.SetUInt64(uCID);
1014 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS);
1015 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
1016 Msg.pvPayload.SetPtr(NULL, 0);
1017
1018 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
1019
1020 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
1021
1022 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1023
1024 LogFlowFuncLeaveRC(rc);
1025 return rc;
1026}
1027
1028/**
1029 * Sends a transfer status to the host.
1030 *
1031 * @returns VBox status code.
1032 * @param pCtx Shared Clipboard command context to use for the connection.
1033 * @param pTransfer Transfer of report to reply to.
1034 * @param uStatus Tranfer status to reply.
1035 * @param rcTransfer Result code (rc) to reply.
1036 */
1037VBGLR3DECL(int) VbglR3ClipboardTransferSendStatus(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
1038 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
1039{
1040 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1041 RT_NOREF(pTransfer); /* Currently not used (yet). */
1042
1043 int rc = vbglR3ClipboardTransferSendStatusEx(pCtx, pCtx->idContext, uStatus, rcTransfer);
1044
1045 LogFlowFuncLeaveRC(rc);
1046 return rc;
1047}
1048
1049/**
1050 * Receives a host request to read a transfer root list header from the guest.
1051 *
1052 * @returns VBox status code.
1053 * @param pCtx Shared Clipboard command context to use for the connection.
1054 * @param pfRoots Where to store the root list header flags to use, requested by the host.
1055 */
1056VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
1057{
1058 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1059 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
1060
1061 VBoxShClRootListReadReqMsg Msg;
1062 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1063 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
1064
1065 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
1066 Msg.ReqParms.fRoots.SetUInt32(0);
1067
1068 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1069 if (RT_SUCCESS(rc))
1070 {
1071 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
1072 if (RT_SUCCESS(rc))
1073 {
1074 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
1075 AssertRC(rc);
1076 }
1077 }
1078
1079 LogFlowFuncLeaveRC(rc);
1080 return rc;
1081}
1082
1083/**
1084 * Replies to a transfer root list header request.
1085 *
1086 * @returns VBox status code.
1087 * @param pCtx Shared Clipboard command context to use for the connection.
1088 * @param pRootListHdr Root lsit header to reply to the host.
1089 */
1090VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
1091{
1092 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1093 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
1094
1095 VBoxShClRootListHdrMsg Msg;
1096 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1097 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
1098
1099 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1100 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures);
1101
1102 Msg.cRoots.SetUInt64(pRootListHdr->cEntries);
1103
1104 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1105
1106 LogFlowFuncLeaveRC(rc);
1107 return rc;
1108}
1109
1110/**
1111 * Receives a host request to read a transfer root list entry from the guest.
1112 *
1113 * @returns VBox status code.
1114 * @param pCtx Shared Clipboard command context to use for the connection.
1115 * @param puIndex Where to return the index of the root list entry the host wants to read.
1116 * @param pfInfo Where to return the read flags the host wants to use.
1117 */
1118VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint64_t *puIndex, uint32_t *pfInfo)
1119{
1120 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1121 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
1122 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1123
1124 VBoxShClRootListEntryReadReqMsg Msg;
1125 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1126 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
1127
1128 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
1129 Msg.Parms.fInfo.SetUInt32(0);
1130 Msg.Parms.uIndex.SetUInt64(0);
1131
1132 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1133 if (RT_SUCCESS(rc))
1134 {
1135 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
1136 if (RT_SUCCESS(rc))
1137 {
1138 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
1139 AssertRC(rc);
1140 }
1141 if (RT_SUCCESS(rc))
1142 {
1143 rc = Msg.Parms.uIndex.GetUInt64(puIndex);
1144 AssertRC(rc);
1145 }
1146 }
1147
1148 LogFlowFuncLeaveRC(rc);
1149 return rc;
1150}
1151
1152/**
1153 * Replies to a transfer root list entry read request from the host.
1154 *
1155 * @returns VBox status code.
1156 * @param pCtx Shared Clipboard command context to use for the connection.
1157 * @param uIndex Index of root list entry to reply.
1158 * @param pEntry Actual root list entry to reply.
1159 */
1160VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry)
1161{
1162 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1163 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1164
1165 VBoxShClRootListEntryMsg Msg;
1166 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1167 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
1168
1169 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
1170 Msg.Parms.fInfo.SetUInt32(pEntry->fInfo);
1171 Msg.Parms.uIndex.SetUInt64(uIndex);
1172
1173 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
1174 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
1175 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
1176
1177 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1178
1179 LogFlowFuncLeaveRC(rc);
1180 return rc;
1181}
1182
1183/**
1184 * Sends a request to open a transfer list handle to the host.
1185 *
1186 * @returns VBox status code.
1187 * @param pCtx Shared Clipboard command context to use for the connection.
1188 * @param pOpenParms List open parameters to use for the open request.
1189 * @param phList Where to return the list handle received from the host.
1190 */
1191VBGLR3DECL(int) VbglR3ClipboardTransferListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1192 PSHCLLISTHANDLE phList)
1193{
1194 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1195 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1196 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1197
1198 int rc = ShClTransferTransformPath(pOpenParms->pszPath, pOpenParms->cbPath);
1199 AssertRCReturn(rc, rc);
1200
1201 VBoxShClListOpenMsg Msg;
1202 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1203 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1204
1205 Msg.uContext.SetUInt64(pCtx->idContext);
1206 Msg.fList.SetUInt32(0);
1207 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1208 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1209 Msg.uHandle.SetUInt64(0);
1210
1211 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1212 if (RT_SUCCESS(rc))
1213 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1214
1215 LogFlowFuncLeaveRC(rc);
1216 return rc;
1217}
1218
1219/**
1220 * Receives a host request to open a transfer list handle on the guest.
1221 *
1222 * @returns VBox status code.
1223 * @param pCtx Shared Clipboard command context to use for the connection.
1224 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1225 */
1226VBGLR3DECL(int) VbglR3ClipboardTransferListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1227{
1228 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1229 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1230
1231 VBoxShClListOpenMsg Msg;
1232 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1233 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1234
1235 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1236 Msg.fList.SetUInt32(0);
1237 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1238 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1239 Msg.uHandle.SetUInt64(0);
1240
1241 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1242 if (RT_SUCCESS(rc))
1243 {
1244 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1245 if (RT_SUCCESS(rc))
1246 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1247 }
1248
1249 LogFlowFuncLeaveRC(rc);
1250 return rc;
1251}
1252
1253/**
1254 * Replies to a transfer list open request from the host.
1255 *
1256 * @returns VBox status code.
1257 * @param pCtx Shared Clipboard command context to use for the connection.
1258 * @param rcReply Return code to reply to the host.
1259 * @param hList List handle of (guest) list to reply to the host.
1260 */
1261VBGLR3DECL(int) VbglR3ClipboardTransferListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1262{
1263 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1264
1265 VBoxShClReplyMsg Msg;
1266 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1267 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1268
1269 Msg.uContext.SetUInt64(pCtx->idContext);
1270 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
1271 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1272 Msg.pvPayload.SetPtr(NULL, 0);
1273
1274 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1275
1276 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1277
1278 LogFlowFuncLeaveRC(rc);
1279 return rc;
1280}
1281
1282/**
1283 * Receives a host request to close a list handle on the guest.
1284 *
1285 * @returns VBox status code.
1286 * @param pCtx Shared Clipboard command context to use for the connection.
1287 * @param phList Where to store the list handle to close, received from the host.
1288 */
1289VBGLR3DECL(int) VbglR3ClipboardTransferListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1290{
1291 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1292 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1293
1294 VBoxShClListCloseMsg Msg;
1295 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1296 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1297
1298 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1299 Msg.uHandle.SetUInt64(0);
1300
1301 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1302 if (RT_SUCCESS(rc))
1303 {
1304 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1305 if (RT_SUCCESS(rc))
1306 {
1307 rc = Msg.uHandle.GetUInt64(phList);
1308 AssertRC(rc);
1309 }
1310 }
1311
1312 LogFlowFuncLeaveRC(rc);
1313 return rc;
1314}
1315
1316/**
1317 * Replies to a transfer list handle close request from the host.
1318 *
1319 * @returns VBox status code.
1320 * @param pCtx Shared Clipboard command context to use for the connection.
1321 * @param rcReply Return code to reply to the host.
1322 * @param hList List handle the send the close reply for.
1323 */
1324VBGLR3DECL(int) VbglR3ClipboardTransferListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1325{
1326 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1327
1328 VBoxShClReplyMsg Msg;
1329 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1330 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1331
1332 Msg.uContext.SetUInt64(pCtx->idContext);
1333 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE);
1334 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1335 Msg.pvPayload.SetPtr(NULL, 0);
1336
1337 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1338
1339 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1340
1341 LogFlowFuncLeaveRC(rc);
1342 return rc;
1343}
1344
1345/**
1346 * Sends a request to close a transfer list handle to the host.
1347 *
1348 * @returns VBox status code.
1349 * @param pCtx Shared Clipboard command context to use for the connection.
1350 * @param hList List handle to request for closing on the host.
1351 */
1352VBGLR3DECL(int) VbglR3ClipboardTransferListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1353{
1354 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1355
1356 VBoxShClListCloseMsg Msg;
1357 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1358 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1359
1360 Msg.uContext.SetUInt64(pCtx->idContext);
1361 Msg.uHandle.SetUInt64(hList);
1362
1363 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1364
1365 LogFlowFuncLeaveRC(rc);
1366 return rc;
1367}
1368
1369/**
1370 * Sends a request to read a transfer list header to the host.
1371 *
1372 * @returns VBox status code.
1373 * @param pCtx Shared Clipboard command context to use for the connection.
1374 * @param hList List handle to read list header for.
1375 * @param fFlags List header read flags to use.
1376 * @param pListHdr Where to return the list header received from the host.
1377 */
1378VBGLR3DECL(int) VbglR3ClipboardTransferListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1379 PSHCLLISTHDR pListHdr)
1380{
1381 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1382 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1383
1384 VBoxShClListHdrMsg Msg;
1385 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1386 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1387
1388 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1389 Msg.ReqParms.uHandle.SetUInt64(hList);
1390 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1391
1392 Msg.fFeatures.SetUInt32(0);
1393 Msg.cbTotalSize.SetUInt32(0);
1394 Msg.cTotalObjects.SetUInt64(0);
1395 Msg.cbTotalSize.SetUInt64(0);
1396
1397 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1398 if (RT_SUCCESS(rc))
1399 {
1400 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1401 if (RT_SUCCESS(rc))
1402 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
1403 if (RT_SUCCESS(rc))
1404 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1405 }
1406
1407 LogFlowFuncLeaveRC(rc);
1408 return rc;
1409}
1410
1411/**
1412 * Receives a host request to read a transfer list header on the guest.
1413 *
1414 * @returns VBox status code.
1415 * @param pCtx Shared Clipboard command context to use for the connection.
1416 * @param phList Where to return the list handle to read list header for.
1417 * @param pfFlags Where to return the List header read flags to use.
1418 */
1419VBGLR3DECL(int) VbglR3ClipboardTransferListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1420{
1421 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1422 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1423 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1424
1425 VBoxShClListHdrReadReqMsg Msg;
1426 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1427 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1428
1429 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1430 Msg.ReqParms.uHandle.SetUInt64(0);
1431 Msg.ReqParms.fFlags.SetUInt32(0);
1432
1433 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1434 if (RT_SUCCESS(rc))
1435 {
1436 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1437 if (RT_SUCCESS(rc))
1438 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1439 if (RT_SUCCESS(rc))
1440 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1441 }
1442
1443 LogFlowFuncLeaveRC(rc);
1444 return rc;
1445}
1446
1447/**
1448 * Sends (writes) a transfer list header to the host.
1449 *
1450 * @returns VBox status code.
1451 * @param pCtx Shared Clipboard command context to use for the connection.
1452 * @param hList List handle to write list header for.
1453 * @param pListHdr List header to write.
1454 */
1455VBGLR3DECL(int) VbglR3ClipboardTransferListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1456 PSHCLLISTHDR pListHdr)
1457{
1458 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1459 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1460
1461 VBoxShClListHdrMsg Msg;
1462 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1463 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1464
1465 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1466 Msg.ReqParms.uHandle.SetUInt64(hList);
1467 Msg.ReqParms.fFlags.SetUInt32(0);
1468
1469 Msg.fFeatures.SetUInt32(0);
1470 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1471 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
1472 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1473
1474 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1475
1476 LogFlowFuncLeaveRC(rc);
1477 return rc;
1478}
1479
1480/**
1481 * Sends a request to read a transfer list entry from the host.
1482 *
1483 * @returns VBox status code.
1484 * @param pCtx Shared Clipboard command context to use for the connection.
1485 * @param hList List handle to request to read a list entry for.
1486 * @param pListEntry Where to return the list entry read from the host.
1487 */
1488VBGLR3DECL(int) VbglR3ClipboardTransferListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1489 PSHCLLISTENTRY pListEntry)
1490{
1491 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1492 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1493
1494 VBoxShClListEntryMsg Msg;
1495 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1496 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1497
1498 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
1499
1500 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1501 Msg.ReqParms.uHandle.SetUInt64(hList);
1502 Msg.ReqParms.fInfo.SetUInt32(fInfo);
1503
1504 char szName[SHCLLISTENTRY_MAX_NAME];
1505 Msg.szName.SetPtr(szName, sizeof(szName));
1506
1507 void *pvInfo = NULL;
1508 uint32_t cbInfo = 0;
1509
1510 int rc = VINF_SUCCESS;
1511
1512 if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
1513 {
1514 cbInfo = sizeof(SHCLFSOBJINFO);
1515 pvInfo = RTMemAlloc(cbInfo);
1516 if (!pvInfo)
1517 rc = VERR_NO_MEMORY;
1518 }
1519
1520 if (RT_SUCCESS(rc))
1521 {
1522 Msg.cbInfo.SetUInt32(cbInfo);
1523 Msg.pvInfo.SetPtr(pvInfo, cbInfo);
1524
1525 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1526 if (RT_SUCCESS(rc))
1527 {
1528 uint32_t cbInfoRet = 0;
1529 rc = Msg.cbInfo.GetUInt32(&cbInfoRet);
1530 if (RT_SUCCESS(rc))
1531 {
1532 AssertMsgStmt(cbInfo == cbInfoRet,
1533 ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
1534 if (RT_SUCCESS(rc))
1535 rc = ShClTransferListEntryInitEx(pListEntry, fInfo, szName, pvInfo, cbInfo);
1536 if (RT_SUCCESS(rc))
1537 {
1538 pvInfo = NULL; /* Entry took ownership of pvInfo now. */
1539 cbInfo = 0;
1540 }
1541 }
1542 }
1543 else
1544 LogRel(("Shared Clipboard: Reading list entry failed: %Rrc\n", rc));
1545 }
1546
1547 RTMemFree(pvInfo);
1548
1549 LogFlowFuncLeaveRC(rc);
1550 return rc;
1551}
1552
1553/**
1554 * Receives a host request to read a transfer list entry from the guest.
1555 *
1556 * @returns VBox status code.
1557 * @param pCtx Shared Clipboard command context to use for the connection.
1558 * @param phList Where to return the list handle to read a list entry for.
1559 * @param pfInfo Where to return the list read flags.
1560 */
1561VBGLR3DECL(int) VbglR3ClipboardTransferListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1562{
1563 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1564 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1565 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1566
1567 VBoxShClListEntryReadReqMsg Msg;
1568 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1569 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1570
1571 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1572 Msg.ReqParms.uHandle.SetUInt64(0);
1573 Msg.ReqParms.fInfo.SetUInt32(0);
1574
1575 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1576 if (RT_SUCCESS(rc))
1577 {
1578 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1579 if (RT_SUCCESS(rc))
1580 {
1581 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1582 AssertRC(rc);
1583 }
1584 if (RT_SUCCESS(rc))
1585 {
1586 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1587 AssertRC(rc);
1588 }
1589 }
1590
1591 LogFlowFuncLeaveRC(rc);
1592 return rc;
1593}
1594
1595/**
1596 * Sends (writes) a transfer list entry to the host.
1597 *
1598 * @returns VBox status code.
1599 * @param pCtx Shared Clipboard command context to use for the connection.
1600 * @param hList List handle to write a list etnry for.
1601 * @param pListEntry List entry to write.
1602 */
1603VBGLR3DECL(int) VbglR3ClipboardTransferListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1604 PSHCLLISTENTRY pListEntry)
1605{
1606 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1607 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1608
1609 VBoxShClListEntryMsg Msg;
1610 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1611 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1612
1613 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1614 Msg.ReqParms.uHandle.SetUInt64(hList);
1615 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1616
1617 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1618 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1619 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1620
1621 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1622
1623 LogFlowFuncLeaveRC(rc);
1624 return rc;
1625}
1626
1627/**
1628 * Receives a host request to open a transfer object on the guest.
1629 *
1630 * @returns VBox status code.
1631 * @param pCtx Shared Clipboard command context to use for the connection.
1632 * @param pCreateParms Where to store the object open/create parameters received from the host.
1633 */
1634VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1635{
1636 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1637 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1638
1639 VBoxShClObjOpenMsg Msg;
1640 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1641 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1642
1643 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1644 Msg.uHandle.SetUInt64(0);
1645 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1646 Msg.fCreate.SetUInt32(0);
1647
1648 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1649 if (RT_SUCCESS(rc))
1650 {
1651 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1652 if (RT_SUCCESS(rc))
1653 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1654 }
1655
1656 LogFlowFuncLeaveRC(rc);
1657 return rc;
1658}
1659
1660/**
1661 * Replies a host request to open a transfer object.
1662 *
1663 * @returns VBox status code.
1664 * @param pCtx Shared Clipboard command context to use for the connection.
1665 * @param rcReply Return code to reply to the host.
1666 * @param hObj Object handle of opened object to reply to the host.
1667 */
1668VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1669{
1670 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1671
1672 VBoxShClReplyMsg Msg;
1673 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1674 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1675
1676 Msg.uContext.SetUInt64(pCtx->idContext);
1677 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
1678 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1679 Msg.pvPayload.SetPtr(NULL, 0);
1680
1681 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1682
1683 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1684
1685 LogFlowFuncLeaveRC(rc);
1686 return rc;
1687}
1688
1689/**
1690 * Sends a transfer object open request to the host.
1691 *
1692 * @returns VBox status code.
1693 * @param pCtx Shared Clipboard command context to use for the connection.
1694 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1695 * @param phObj Where to return the object handle from the host.
1696 */
1697VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1698 PSHCLOBJHANDLE phObj)
1699{
1700 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1701 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1702 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1703
1704 int rc = ShClTransferTransformPath(pCreateParms->pszPath, pCreateParms->cbPath);
1705 AssertRCReturn(rc, rc);
1706
1707 VBoxShClObjOpenMsg Msg;
1708 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1709 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1710
1711 Msg.uContext.SetUInt64(pCtx->idContext);
1712 Msg.uHandle.SetUInt64(0);
1713 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1714 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1715
1716 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1717 if (RT_SUCCESS(rc))
1718 Msg.uHandle.GetUInt64(phObj);
1719
1720 LogFlowFuncLeaveRC(rc);
1721 return rc;
1722}
1723
1724/**
1725 * Receives a host request to close a transfer object on the guest.
1726 *
1727 * @returns VBox status code.
1728 * @param pCtx Shared Clipboard command context to use for the connection.
1729 * @param phObj Where to return the object handle to close from the host.
1730 */
1731VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1732{
1733 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1734 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1735
1736 VBoxShClObjCloseMsg Msg;
1737 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1738 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1739
1740 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1741 Msg.uHandle.SetUInt64(0);
1742
1743 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1744 if (RT_SUCCESS(rc))
1745 {
1746 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1747 if (RT_SUCCESS(rc))
1748 rc = Msg.uHandle.GetUInt64(phObj);
1749 }
1750
1751 LogFlowFuncLeaveRC(rc);
1752 return rc;
1753}
1754
1755/**
1756 * Replies to a transfer object open request from the host.
1757 *
1758 * @returns VBox status code.
1759 * @param pCtx Shared Clipboard command context to use for the connection.
1760 * @param rcReply Return code to reply to the host.
1761 * @param hObj Object handle to reply to the host.
1762 */
1763VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1764{
1765 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1766
1767 VBoxShClReplyMsg Msg;
1768 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1769 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1770
1771 Msg.uContext.SetUInt64(pCtx->idContext);
1772 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
1773 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1774 Msg.pvPayload.SetPtr(NULL, 0);
1775
1776 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1777
1778 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1779
1780 LogFlowFuncLeaveRC(rc);
1781 return rc;
1782}
1783
1784/**
1785 * Sends a request to close a transfer object to the host.
1786 *
1787 * @returns VBox status code.
1788 * @param pCtx Shared Clipboard command context to use for the connection.
1789 * @param hObj Object handle to close on the host.
1790 */
1791VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1792{
1793 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1794
1795 VBoxShClObjCloseMsg Msg;
1796 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1797 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1798
1799 Msg.uContext.SetUInt64(pCtx->idContext);
1800 Msg.uHandle.SetUInt64(hObj);
1801
1802 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1803
1804 LogFlowFuncLeaveRC(rc);
1805 return rc;
1806}
1807
1808/**
1809 * Receives a host request to read from a transfer object on the guest.
1810 *
1811 * @returns VBox status code.
1812 * @param pCtx Shared Clipboard command context to use for the connection.
1813 * @param phObj Where to return the object handle to read from.
1814 * @param pcbToRead Where to return the amount (in bytes) to read.
1815 * @param pfFlags Where to return the read flags.
1816 */
1817VBGLR3DECL(int) VbglR3ClipboardTransferObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1818 uint32_t *pfFlags)
1819{
1820 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1821 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1822 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1823 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1824
1825 VBoxShClObjReadReqMsg Msg;
1826 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1827 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1828
1829 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1830 Msg.ReqParms.uHandle.SetUInt64(0);
1831 Msg.ReqParms.cbToRead.SetUInt32(0);
1832 Msg.ReqParms.fRead.SetUInt32(0);
1833
1834 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1835 if (RT_SUCCESS(rc))
1836 {
1837 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1838 if (RT_SUCCESS(rc))
1839 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1840 if (RT_SUCCESS(rc))
1841 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1842 if (RT_SUCCESS(rc))
1843 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1844 }
1845
1846 LogFlowFuncLeaveRC(rc);
1847 return rc;
1848}
1849
1850/**
1851 * Sends a request to read from a transfer object to the host.
1852 *
1853 * @returns VBox status code.
1854 * @param pCtx Shared Clipboard command context to use for the connection.
1855 * @param hObj Object handle of object to read from.
1856 * @param pvData Buffer where to store the read object data.
1857 * @param cbData Size (in bytes) of buffer.
1858 * @param pcbRead Where to store the amount (in bytes) read from the object.
1859 */
1860VBGLR3DECL(int) VbglR3ClipboardTransferObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1861 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1862{
1863 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1864 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1865 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1866 /* pcbRead is optional. */
1867
1868 VBoxShClObjReadWriteMsg Msg;
1869 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1870 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1871
1872 Msg.uContext.SetUInt64(pCtx->idContext);
1873 Msg.uHandle.SetUInt64(hObj);
1874 Msg.cbData.SetUInt32(cbData);
1875 Msg.pvData.SetPtr(pvData, cbData);
1876 Msg.cbChecksum.SetUInt32(0);
1877 Msg.pvChecksum.SetPtr(NULL, 0);
1878
1879 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1880 if (RT_SUCCESS(rc))
1881 {
1882 /** @todo Add checksum support. */
1883
1884 if (pcbRead)
1885 {
1886 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1887 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1888 }
1889 }
1890
1891 LogFlowFuncLeaveRC(rc);
1892 return rc;
1893}
1894
1895/**
1896 * Sends a request to write to a transfer object to the host.
1897 *
1898 * @returns VBox status code.
1899 * @param pCtx Shared Clipboard command context to use for the connection.
1900 * @param hObj Object handle of object to write to.
1901 * @param pvData Buffer of data to write to object.
1902 * @param cbData Size (in bytes) of buffer.
1903 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1904 */
1905VBGLR3DECL(int) VbglR3ClipboardTransferObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1906 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1907{
1908 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1909 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1910 /* cbData can be 0. */
1911 /* pcbWritten is optional. */
1912
1913 VBoxShClObjReadWriteMsg Msg;
1914 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1915 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1916
1917 Msg.uContext.SetUInt64(pCtx->idContext);
1918 Msg.uHandle.SetUInt64(hObj);
1919 Msg.cbData.SetUInt32(cbData);
1920 Msg.pvData.SetPtr(pvData, cbData);
1921 Msg.cbChecksum.SetUInt32(0);
1922 Msg.pvChecksum.SetPtr(NULL, 0);
1923
1924 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1925 if (RT_SUCCESS(rc))
1926 {
1927 /** @todo Add checksum support. */
1928
1929 if (pcbWritten)
1930 *pcbWritten = cbData; /** @todo For now return all as being written. */
1931 }
1932
1933 LogFlowFuncLeaveRC(rc);
1934 return rc;
1935}
1936
1937
1938/*********************************************************************************************************************************
1939* Transfer interface implementations *
1940*********************************************************************************************************************************/
1941
1942/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
1943static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGRootListRead(PSHCLTXPROVIDERCTX pCtx)
1944{
1945 LogFlowFuncEnter();
1946
1947 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1948 AssertPtr(pCmdCtx);
1949
1950 int rc = VbglR3ClipboardTransferRootListRead(pCmdCtx, pCtx->pTransfer);
1951
1952 LogFlowFuncLeaveRC(rc);
1953 return rc;
1954}
1955
1956/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
1957static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1958 PSHCLLISTHANDLE phList)
1959{
1960 LogFlowFuncEnter();
1961
1962 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1963 AssertPtr(pCmdCtx);
1964
1965 int rc = VbglR3ClipboardTransferListOpenSend(pCmdCtx, pOpenParms, phList);
1966
1967 LogFlowFuncLeaveRC(rc);
1968 return rc;
1969}
1970
1971/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
1972static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1973{
1974 LogFlowFuncEnter();
1975
1976 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1977 AssertPtr(pCmdCtx);
1978
1979 int rc = VbglR3ClipboardTransferListCloseSend(pCmdCtx, hList);
1980
1981 LogFlowFuncLeaveRC(rc);
1982 return rc;
1983}
1984
1985/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
1986static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1987 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1988{
1989 LogFlowFuncEnter();
1990
1991 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1992 AssertPtr(pCmdCtx);
1993
1994 int rc = ShClTransferListHdrInit(pListHdr);
1995 if (RT_SUCCESS(rc))
1996 {
1997 if (RT_SUCCESS(rc))
1998 {
1999 rc = VbglR3ClipboardTransferListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
2000 }
2001 else
2002 ShClTransferListHdrDestroy(pListHdr);
2003 }
2004
2005 LogFlowFuncLeaveRC(rc);
2006 return rc;
2007}
2008
2009/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
2010static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListEntryRead(PSHCLTXPROVIDERCTX pCtx,
2011 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
2012{
2013 LogFlowFuncEnter();
2014
2015 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2016 AssertPtr(pCmdCtx);
2017
2018 int rc = VbglR3ClipboardTransferListEntryRead(pCmdCtx, hList, pListEntry);
2019
2020 LogFlowFuncLeaveRC(rc);
2021 return rc;
2022}
2023
2024/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
2025static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjOpen(PSHCLTXPROVIDERCTX pCtx,
2026 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
2027{
2028 LogFlowFuncEnter();
2029
2030 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2031 AssertPtr(pCmdCtx);
2032
2033 int rc = VbglR3ClipboardTransferObjOpenSend(pCmdCtx, pCreateParms, phObj);
2034
2035 LogFlowFuncLeaveRC(rc);
2036 return rc;
2037}
2038
2039/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
2040static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
2041{
2042 LogFlowFuncEnter();
2043
2044 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2045 AssertPtr(pCmdCtx);
2046
2047 int rc = VbglR3ClipboardTransferObjCloseSend(pCmdCtx, hObj);
2048
2049 LogFlowFuncLeaveRC(rc);
2050 return rc;
2051}
2052
2053/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
2054static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjRead(PSHCLTXPROVIDERCTX pCtx,
2055 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
2056 uint32_t fFlags, uint32_t *pcbRead)
2057{
2058 LogFlowFuncEnter();
2059
2060 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2061 AssertPtr(pCmdCtx);
2062
2063 RT_NOREF(fFlags); /* Not used yet. */
2064
2065 int rc = VbglR3ClipboardTransferObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
2066
2067 LogFlowFuncLeaveRC(rc);
2068 return rc;
2069}
2070
2071/**
2072 * Creates (and registers) a transfer on the guest side.
2073 *
2074 * @returns VBox status code.
2075 * @param pCmdCtx Command context to use.
2076 * @param pTransferCtx Transfer context to init transfer for.
2077 * @param enmDir Specifies the transfer direction of this transfer.
2078 * @param enmSource Specifies the data source of the transfer.
2079 * @param idTransfer ID of transfer to create.
2080 * @param ppTransfer Where to return the transfer object on success. Optional.
2081 */
2082static int vbglR3ClipboardTransferCreate(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2083 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer,
2084 PSHCLTRANSFER *ppTransfer)
2085{
2086 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_WRONG_ORDER);
2087
2088 RT_NOREF(pCmdCtx);
2089
2090 PSHCLTRANSFER pTransfer;
2091 int rc = ShClTransferCreate(enmDir, enmSource, &pCmdCtx->Transfers.Callbacks, &pTransfer);
2092 if (RT_SUCCESS(rc))
2093 {
2094 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
2095 if ( RT_SUCCESS(rc)
2096 && ppTransfer)
2097 *ppTransfer = pTransfer;
2098 }
2099
2100 if (RT_SUCCESS(rc))
2101 LogRel2(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
2102 else
2103 LogRel(("Shared Clipboard: Error creating transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2104
2105 LogFlowFuncLeaveRC(rc);
2106 return rc;
2107}
2108
2109/**
2110 * Initializes a transfer on the guest side.
2111 *
2112 * @returns VBox status code.
2113 * @param pCmdCtx Command context to use.
2114 * @param pTransfer Transfer to init.
2115 */
2116static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2117{
2118 LogFlowFuncEnter();
2119
2120 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2121
2122 SHCLTXPROVIDER Provider;
2123 RT_ZERO(Provider);
2124
2125 /* Assign local provider first and overwrite interface methods below if needed. */
2126 ShClTransferProviderLocalQueryInterface(&Provider);
2127
2128 /* If this is a read transfer (reading data from host), set the interface to use
2129 * our VbglR3 routines here. */
2130 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2131 {
2132 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceHGRootListRead;
2133
2134 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceHGListOpen;
2135 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceHGListClose;
2136 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceHGListHdrRead;
2137 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceHGListEntryRead;
2138
2139 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceHGObjOpen;
2140 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceHGObjClose;
2141 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceHGObjRead;
2142 }
2143 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2144 {
2145 /* Uses the local provider assigned above. */
2146 }
2147 else
2148 AssertFailed();
2149
2150 Provider.pvUser = pCmdCtx;
2151
2152 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2153 * provider functions. */
2154 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2155 if (RT_SUCCESS(rc))
2156 rc = ShClTransferInit(pTransfer);
2157
2158 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2159
2160 if (RT_SUCCESS(rc))
2161 {
2162 LogRel2(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2163 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2164 }
2165 else
2166 LogRel(("Shared Clipboard: Unable to initialize transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2167
2168 LogFlowFuncLeaveRC(rc);
2169 return rc;
2170}
2171
2172/**
2173 * Destroys a transfer on the guest side.
2174 *
2175 * @returns VBox status code.
2176 * @param pCmdCtx Command context to use.
2177 * @param pTransferCtx Transfer context to uninit transfer for.
2178 * @param idTransfer ID of transfer to initialize.
2179 */
2180static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2181{
2182 RT_NOREF(pCmdCtx);
2183
2184 LogFlowFuncEnter();
2185
2186 int rc = VINF_SUCCESS;
2187
2188 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2189 if (pTransfer)
2190 {
2191 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2192 if (RT_SUCCESS(rc))
2193 rc = ShClTransferDestroy(pTransfer);
2194
2195 if (RT_SUCCESS(rc))
2196 {
2197 LogRel(("Shared Clipboard: Transfer %RU16 successfully uninitialized\n", idTransfer));
2198 }
2199 else
2200 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2201 }
2202
2203 LogFlowFuncLeaveRC(rc);
2204 return rc;
2205}
2206
2207/**
2208 * Requests a new host -> guest transfer from the host.
2209 *
2210 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2211 * This ID will be used to initialize the transfer on the guest side then.
2212 *
2213 * @returns VBox status code.
2214 * @param pCmdCtx Command context to use.
2215 */
2216VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2217{
2218 LogFlowFuncEnter();
2219
2220 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2221
2222 int rc = vbglR3ClipboardTransferSendStatusEx(pCmdCtx, 0 /* Context ID not needed */,
2223 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2224 LogFlowFuncLeaveRC(rc);
2225 return rc;
2226}
2227
2228/**
2229 * Starts a transfer on the guest side.
2230 *
2231 * @returns VBox status code.
2232 * @param pCmdCtx Command context to use.
2233 * @param pTransferCtx Transfer context to start transfer for.
2234 * @param uTransferID ID to use for transfer to start.
2235 */
2236static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2237 SHCLTRANSFERID uTransferID)
2238{
2239 RT_NOREF(pCmdCtx);
2240
2241 LogFlowFuncEnter();
2242
2243 int rc;
2244
2245 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2246 if (pTransfer)
2247 {
2248 rc = ShClTransferStart(pTransfer);
2249 if (RT_SUCCESS(rc))
2250 {
2251 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2252 }
2253 else
2254 LogRel(("Shared Clipboard: Unable to start transfer %RU16, rc=%Rrc\n", uTransferID, rc));
2255 }
2256 else
2257 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2258
2259 /* Send a reply in any case. */
2260 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2261 RT_SUCCESS(rc)
2262 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2263 if (RT_SUCCESS(rc))
2264 rc = rc2;
2265
2266 LogFlowFuncLeaveRC(rc);
2267 return rc;
2268}
2269
2270VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2271 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2272 PVBGLR3CLIPBOARDEVENT pEvent)
2273{
2274 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2275 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2276 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2277
2278 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2279
2280 int rc;
2281 if (!pCmdCtx->fUseLegacyProtocol)
2282 {
2283 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2284
2285 switch (idMsg)
2286 {
2287 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2288 {
2289 SHCLTRANSFERDIR enmDir;
2290 SHCLTRANSFERREPORT transferReport;
2291 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2292 if (RT_SUCCESS(rc))
2293 {
2294 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2295
2296 LogRel2(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU16\n",
2297 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2298
2299 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2300
2301 switch (transferReport.uStatus)
2302 {
2303 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2304 {
2305 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2306 enmSource = SHCLSOURCE_REMOTE;
2307
2308 /* The host acknowledged our request to create a new transfer.
2309 * So create a new transfer here with the transfer ID we just got from the host.
2310 *
2311 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2312 */
2313 PSHCLTRANSFER pTransfer;
2314 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2315
2316 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2317 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2318 * back to us (see case down below).*/
2319 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2320 RT_SUCCESS(rc)
2321 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2322 if (RT_SUCCESS(rc))
2323 rc = rc2;
2324 break;
2325 }
2326
2327 case SHCLTRANSFERSTATUS_INITIALIZED:
2328 {
2329 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2330 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2331 {
2332 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2333 enmSource = SHCLSOURCE_REMOTE;
2334 }
2335 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2336 {
2337 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2338 enmSource = SHCLSOURCE_LOCAL;
2339 }
2340 else
2341 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2342
2343 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2344 {
2345 /* The host reported INITIALIZED for the transfer.
2346 * So init our local transfer as well now. */
2347 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2348 if (pTransfer)
2349 {
2350 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2351
2352 /* Only send back a reply on error -- we already reported INITIALIZED
2353 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2354 if (RT_FAILURE(rc))
2355 {
2356 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2357 SHCLTRANSFERSTATUS_ERROR, rc);
2358 AssertRC(rc2);
2359 }
2360 }
2361 else
2362 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2363 }
2364 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2365 {
2366 /* The host reported the INITIALIZED status together with the transfer ID.
2367 * So create a local transfer here with that ID. */
2368 PSHCLTRANSFER pTransfer;
2369 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2370 if (RT_SUCCESS(rc))
2371 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2372
2373 /* Send a reply in any case. */
2374 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2375 RT_SUCCESS(rc)
2376 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2377 if (RT_SUCCESS(rc))
2378 rc = rc2;
2379 }
2380 else
2381 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2382
2383 break;
2384 }
2385
2386 case SHCLTRANSFERSTATUS_STARTED:
2387 {
2388 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2389 break;
2390 }
2391
2392 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2393 RT_FALL_THROUGH();
2394 case SHCLTRANSFERSTATUS_COMPLETED:
2395 RT_FALL_THROUGH();
2396 case SHCLTRANSFERSTATUS_CANCELED:
2397 RT_FALL_THROUGH();
2398 case SHCLTRANSFERSTATUS_KILLED:
2399 RT_FALL_THROUGH();
2400 case SHCLTRANSFERSTATUS_ERROR:
2401 {
2402 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2403 break;
2404 }
2405
2406 default:
2407 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU16\n",
2408 transferReport.uStatus, pEvent->u.TransferStatus.Report.rc, pEvent->u.TransferStatus.uID));
2409 rc = VERR_NOT_SUPPORTED;
2410 break;
2411 }
2412
2413 if (RT_SUCCESS(rc))
2414 {
2415 pEvent->u.TransferStatus.enmDir = enmDir;
2416 pEvent->u.TransferStatus.Report = transferReport;
2417 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2418
2419 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2420 }
2421 }
2422 break;
2423 }
2424
2425 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2426 {
2427 uint32_t fRoots;
2428 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2429
2430 /** @todo Validate / handle fRoots. */
2431
2432 if (RT_SUCCESS(rc))
2433 {
2434 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2435 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2436 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2437
2438 SHCLLISTHDR rootListHdr;
2439 ShClTransferListHdrInit(&rootListHdr);
2440
2441 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2442
2443 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2444
2445 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2446 }
2447 break;
2448 }
2449
2450 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2451 {
2452 uint64_t uIndex;
2453 uint32_t fInfo;
2454 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2455 if (RT_SUCCESS(rc))
2456 {
2457 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2458 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2459 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2460
2461 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2462 if (pEntry)
2463 {
2464 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2465 }
2466 else
2467 rc = VERR_NOT_FOUND;
2468 }
2469 break;
2470 }
2471
2472 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2473 {
2474 SHCLLISTOPENPARMS openParmsList;
2475 rc = ShClTransferListOpenParmsInit(&openParmsList);
2476 if (RT_SUCCESS(rc))
2477 {
2478 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2479 if (RT_SUCCESS(rc))
2480 {
2481 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2482 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2483 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2484
2485 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2486
2487 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2488 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2489
2490 /* Reply in any case. */
2491 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2492 AssertRC(rc2);
2493 }
2494
2495 ShClTransferListOpenParmsDestroy(&openParmsList);
2496 }
2497
2498 break;
2499 }
2500
2501 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2502 {
2503 SHCLLISTHANDLE hList;
2504 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2505 if (RT_SUCCESS(rc))
2506 {
2507 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2508 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2509 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2510
2511 rc = ShClTransferListClose(pTransfer, hList);
2512
2513 /* Reply in any case. */
2514 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2515 AssertRC(rc2);
2516 }
2517
2518 break;
2519 }
2520
2521 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2522 {
2523 /** @todo Handle filter + list features. */
2524
2525 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2526 uint32_t fFlags = 0;
2527 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2528 if (RT_SUCCESS(rc))
2529 {
2530 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2531 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2532 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2533
2534 SHCLLISTHDR hdrList;
2535 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2536 if (RT_SUCCESS(rc))
2537 {
2538 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2539
2540 ShClTransferListHdrDestroy(&hdrList);
2541 }
2542 }
2543
2544 break;
2545 }
2546
2547 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2548 {
2549 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2550
2551 SHCLLISTHANDLE hList;
2552 uint32_t fInfo;
2553 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2554 if (RT_SUCCESS(rc))
2555 {
2556 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2557 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2558 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2559
2560 SHCLLISTENTRY entryList;
2561 rc = ShClTransferListEntryInit(&entryList);
2562 if (RT_SUCCESS(rc))
2563 {
2564 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2565 if (RT_SUCCESS(rc))
2566 {
2567 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2568 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2569
2570 RT_NOREF(pObjInfo);
2571
2572 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2573
2574 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2575
2576 ShClTransferListEntryDestroy(&entryList);
2577 }
2578 }
2579 }
2580
2581 break;
2582 }
2583
2584 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2585 {
2586 SHCLOBJOPENCREATEPARMS openParms;
2587 rc = ShClTransferObjOpenParmsInit(&openParms);
2588 if (RT_SUCCESS(rc))
2589 {
2590 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2591 if (RT_SUCCESS(rc))
2592 {
2593 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2594 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2595 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2596
2597 SHCLOBJHANDLE hObj;
2598 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2599
2600 /* Reply in any case. */
2601 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2602 AssertRC(rc2);
2603 }
2604
2605 ShClTransferObjOpenParmsDestroy(&openParms);
2606 }
2607
2608 break;
2609 }
2610
2611 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2612 {
2613 SHCLOBJHANDLE hObj;
2614 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2615 if (RT_SUCCESS(rc))
2616 {
2617 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2618 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2619 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2620
2621 rc = ShClTransferObjClose(pTransfer, hObj);
2622
2623 /* Reply in any case. */
2624 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2625 AssertRC(rc2);
2626 }
2627
2628 break;
2629 }
2630
2631 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2632 {
2633 SHCLOBJHANDLE hObj;
2634 uint32_t cbBuf;
2635 uint32_t fFlags;
2636 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2637 if (RT_SUCCESS(rc))
2638 {
2639 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2640 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2641 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2642
2643 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2644
2645 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2646
2647 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2648 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2649
2650 void *pvBuf = RTMemAlloc(cbToRead);
2651 if (pvBuf)
2652 {
2653 uint32_t cbRead;
2654 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2655 if (RT_SUCCESS(rc))
2656 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2657
2658 RTMemFree(pvBuf);
2659 }
2660 else
2661 rc = VERR_NO_MEMORY;
2662 }
2663
2664 break;
2665 }
2666
2667 default:
2668 {
2669 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2670 if (RT_FAILURE(rc))
2671 fErrorSent = true;
2672 break;
2673 }
2674 }
2675
2676 if ( !fErrorSent
2677 && RT_FAILURE(rc))
2678 {
2679 /* Report transfer-specific error back to the host. */
2680 int rc2 = vbglR3ClipboardTransferSendStatusEx(pCmdCtx, pCmdCtx->idContext, SHCLTRANSFERSTATUS_ERROR, rc);
2681 AssertRC(rc2);
2682 }
2683 }
2684 else
2685 {
2686 /*
2687 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2688 * !HACK ALERT! cParms is the format flag or flags.
2689 */
2690 rc = VINF_SUCCESS;
2691 switch (idMsg)
2692 {
2693 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2694 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2695 pEvent->u.fReportedFormats = cParms;
2696 break;
2697
2698 case VBOX_SHCL_HOST_MSG_READ_DATA:
2699 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2700 pEvent->u.fReadData = cParms;
2701 break;
2702
2703 case VBOX_SHCL_HOST_MSG_QUIT:
2704 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2705 break;
2706
2707 default:
2708 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2709 rc = VERR_NOT_SUPPORTED;
2710 break;
2711 }
2712 }
2713
2714 LogFlowFuncLeaveRC(rc);
2715 return rc;
2716}
2717
2718#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2719
2720VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2721{
2722 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2723 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2724
2725 RT_NOREF(cParms);
2726
2727 int rc;
2728 if (!pCtx->fUseLegacyProtocol)
2729 {
2730 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2731 switch (idMsg)
2732 {
2733 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2734 {
2735 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2736 if (RT_SUCCESS(rc))
2737 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2738 break;
2739 }
2740
2741 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2742 {
2743 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2744 if (RT_SUCCESS(rc))
2745 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2746 break;
2747 }
2748
2749 case VBOX_SHCL_HOST_MSG_READ_DATA:
2750 {
2751 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2752 if (RT_SUCCESS(rc))
2753 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2754 break;
2755 }
2756
2757 case VBOX_SHCL_HOST_MSG_QUIT:
2758 {
2759 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2760 rc = VINF_SUCCESS;
2761 break;
2762 }
2763
2764 default:
2765 {
2766 /** @todo r=bird: BUGBUG - need a skip command here! */
2767 rc = VERR_NOT_SUPPORTED;
2768 break;
2769 }
2770 }
2771
2772 if (RT_SUCCESS(rc))
2773 {
2774 /* Copy over our command context to the event. */
2775 pEvent->cmdCtx = *pCtx;
2776 }
2777 else
2778 {
2779 /* Report error back to the host. */
2780 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2781 AssertRC(rc2);
2782 }
2783 }
2784 else
2785 {
2786 /*
2787 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2788 * !HACK ALERT! cParms is the format flag or flags.
2789 */
2790 rc = VINF_SUCCESS;
2791 switch (idMsg)
2792 {
2793 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2794 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2795 pEvent->u.fReportedFormats = cParms;
2796 break;
2797
2798 case VBOX_SHCL_HOST_MSG_READ_DATA:
2799 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2800 pEvent->u.fReadData = cParms;
2801 break;
2802
2803 case VBOX_SHCL_HOST_MSG_QUIT:
2804 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2805 break;
2806
2807 default:
2808 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2809 rc = VERR_NOT_SUPPORTED;
2810 break;
2811 }
2812 pEvent->cmdCtx = *pCtx;
2813 }
2814
2815 LogFlowFuncLeaveRC(rc);
2816 return rc;
2817}
2818
2819/**
2820 * Frees (destroys) a formerly allocated Shared Clipboard event.
2821 *
2822 * @returns IPRT status code.
2823 * @param pEvent Event to free (destroy).
2824 */
2825VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2826{
2827 if (!pEvent)
2828 return;
2829
2830 /* Some messages require additional cleanup. */
2831 switch (pEvent->enmType)
2832 {
2833 default:
2834 break;
2835 }
2836
2837 RTMemFree(pEvent);
2838 pEvent = NULL;
2839}
2840
2841/**
2842 * Reports (advertises) guest clipboard formats to the host.
2843 *
2844 * Legacy function, do not use anymore.
2845 *
2846 * @returns VBox status code.
2847 * @param idClient The client id returned by VbglR3ClipboardConnect().
2848 * @param fFormats The formats to report.
2849 */
2850VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2851{
2852 struct
2853 {
2854 VBGLIOCHGCMCALL Hdr;
2855 VBoxShClParmReportFormats Parms;
2856 } Msg;
2857
2858 RT_ZERO(Msg);
2859
2860 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2861 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2862
2863 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2864
2865 LogFlowFuncLeaveRC(rc);
2866 return rc;
2867}
2868
2869/**
2870 * Sends guest clipboard data to the host.
2871 *
2872 * Legacy function kept for compatibility, do not use anymore.
2873 *
2874 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2875 * from the host.
2876 *
2877 * @returns VBox status code.
2878 * @param idClient The client id returned by VbglR3ClipboardConnect().
2879 * @param fFormat The format of the data.
2880 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2881 * is zero.
2882 * @param cbData Number of bytes of data to send. Zero is valid.
2883 */
2884VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2885{
2886 LogFlowFuncEnter();
2887
2888 struct
2889 {
2890 VBGLIOCHGCMCALL Hdr;
2891 VBoxShClParmDataWriteOld Parms;
2892 } Msg;
2893
2894 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2895 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2896 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2897
2898 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2899
2900 LogFlowFuncLeaveRC(rc);
2901 return rc;
2902}
2903
2904/**
2905 * Sends guest clipboard data to the host.
2906 *
2907 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2908 * from the host.
2909 *
2910 * @returns VBox status code.
2911 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2912 * @param fFormat Clipboard format to send.
2913 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2914 * is zero.
2915 * @param cbData Number of bytes of data to send. Zero is valid.
2916 */
2917VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2918{
2919 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2920 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2921
2922 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2923
2924 int rc;
2925 if (pCtx->fUseLegacyProtocol)
2926 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2927 else
2928 {
2929 struct
2930 {
2931 VBGLIOCHGCMCALL Hdr;
2932 VBoxShClParmDataWrite Parms;
2933 } Msg;
2934
2935 RT_ZERO(Msg);
2936
2937 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2938 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2939 Msg.Parms.f32Format.SetUInt32(fFormat);
2940 Msg.Parms.pData.SetPtr(pvData, cbData);
2941
2942 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2943
2944 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2945 }
2946
2947 LogFlowFuncLeaveRC(rc);
2948 return rc;
2949}
2950
2951/**
2952 * Writes an error to the host.
2953 *
2954 * @returns IPRT status code.
2955 * @param idClient The client id returned by VbglR3ClipboardConnect().
2956 * @param rcErr Error (IPRT-style) to send.
2957 */
2958VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2959{
2960 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2961
2962 VBoxShClWriteErrorMsg Msg;
2963 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2964
2965 /** @todo Context ID not used yet. */
2966 Msg.uContext.SetUInt64(0);
2967 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2968
2969 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2970
2971 if (RT_FAILURE(rc))
2972 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2973 if (rc == VERR_NOT_SUPPORTED)
2974 rc = VINF_SUCCESS;
2975
2976 if (RT_FAILURE(rc))
2977 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2978
2979 LogFlowFuncLeaveRC(rc);
2980 return rc;
2981}
2982
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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