VirtualBox

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

Last change on this file was 103482, checked in by vboxsync, 3 months ago

Shared Clipboard: Added a ShClTransferTransformPath() function to make the paths more uniform [Assertion guarding fix]. ​bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 106.4 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 103482 2024-02-20 17:11:29Z 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.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * 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 {
1214 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1215 }
1216
1217 LogFlowFuncLeaveRC(rc);
1218 return rc;
1219}
1220
1221/**
1222 * Receives a host request to open a transfer list handle on the guest.
1223 *
1224 * @returns VBox status code.
1225 * @param pCtx Shared Clipboard command context to use for the connection.
1226 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1227 */
1228VBGLR3DECL(int) VbglR3ClipboardTransferListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1229{
1230 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1231 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1232
1233 VBoxShClListOpenMsg Msg;
1234 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1235 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1236
1237 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1238 Msg.fList.SetUInt32(0);
1239 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1240 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1241 Msg.uHandle.SetUInt64(0);
1242
1243 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1244 if (RT_SUCCESS(rc))
1245 {
1246 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1247 if (RT_SUCCESS(rc))
1248 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1249 }
1250
1251 LogFlowFuncLeaveRC(rc);
1252 return rc;
1253}
1254
1255/**
1256 * Replies to a transfer list open request from the host.
1257 *
1258 * @returns VBox status code.
1259 * @param pCtx Shared Clipboard command context to use for the connection.
1260 * @param rcReply Return code to reply to the host.
1261 * @param hList List handle of (guest) list to reply to the host.
1262 */
1263VBGLR3DECL(int) VbglR3ClipboardTransferListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1264{
1265 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1266
1267 VBoxShClReplyMsg Msg;
1268 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1269 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1270
1271 Msg.uContext.SetUInt64(pCtx->idContext);
1272 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
1273 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1274 Msg.pvPayload.SetPtr(NULL, 0);
1275
1276 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1277
1278 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1279
1280 LogFlowFuncLeaveRC(rc);
1281 return rc;
1282}
1283
1284/**
1285 * Receives a host request to close a list handle on the guest.
1286 *
1287 * @returns VBox status code.
1288 * @param pCtx Shared Clipboard command context to use for the connection.
1289 * @param phList Where to store the list handle to close, received from the host.
1290 */
1291VBGLR3DECL(int) VbglR3ClipboardTransferListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1292{
1293 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1294 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1295
1296 VBoxShClListCloseMsg Msg;
1297 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1298 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1299
1300 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1301 Msg.uHandle.SetUInt64(0);
1302
1303 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1304 if (RT_SUCCESS(rc))
1305 {
1306 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1307 if (RT_SUCCESS(rc))
1308 {
1309 rc = Msg.uHandle.GetUInt64(phList);
1310 AssertRC(rc);
1311 }
1312 }
1313
1314 LogFlowFuncLeaveRC(rc);
1315 return rc;
1316}
1317
1318/**
1319 * Replies to a transfer list handle close request from the host.
1320 *
1321 * @returns VBox status code.
1322 * @param pCtx Shared Clipboard command context to use for the connection.
1323 * @param rcReply Return code to reply to the host.
1324 * @param hList List handle the send the close reply for.
1325 */
1326VBGLR3DECL(int) VbglR3ClipboardTransferListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1327{
1328 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1329
1330 VBoxShClReplyMsg Msg;
1331 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1332 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1333
1334 Msg.uContext.SetUInt64(pCtx->idContext);
1335 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE);
1336 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1337 Msg.pvPayload.SetPtr(NULL, 0);
1338
1339 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1340
1341 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1342
1343 LogFlowFuncLeaveRC(rc);
1344 return rc;
1345}
1346
1347/**
1348 * Sends a request to close a transfer list handle to the host.
1349 *
1350 * @returns VBox status code.
1351 * @param pCtx Shared Clipboard command context to use for the connection.
1352 * @param hList List handle to request for closing on the host.
1353 */
1354VBGLR3DECL(int) VbglR3ClipboardTransferListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1355{
1356 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1357
1358 VBoxShClListCloseMsg Msg;
1359 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1360 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1361
1362 Msg.uContext.SetUInt64(pCtx->idContext);
1363 Msg.uHandle.SetUInt64(hList);
1364
1365 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1366
1367 LogFlowFuncLeaveRC(rc);
1368 return rc;
1369}
1370
1371/**
1372 * Sends a request to read a transfer list header to the host.
1373 *
1374 * @returns VBox status code.
1375 * @param pCtx Shared Clipboard command context to use for the connection.
1376 * @param hList List handle to read list header for.
1377 * @param fFlags List header read flags to use.
1378 * @param pListHdr Where to return the list header received from the host.
1379 */
1380VBGLR3DECL(int) VbglR3ClipboardTransferListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1381 PSHCLLISTHDR pListHdr)
1382{
1383 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1384 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1385
1386 VBoxShClListHdrMsg Msg;
1387 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1388 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1389
1390 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1391 Msg.ReqParms.uHandle.SetUInt64(hList);
1392 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1393
1394 Msg.fFeatures.SetUInt32(0);
1395 Msg.cbTotalSize.SetUInt32(0);
1396 Msg.cTotalObjects.SetUInt64(0);
1397 Msg.cbTotalSize.SetUInt64(0);
1398
1399 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1400 if (RT_SUCCESS(rc))
1401 {
1402 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1403 if (RT_SUCCESS(rc))
1404 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
1405 if (RT_SUCCESS(rc))
1406 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1407 }
1408
1409 LogFlowFuncLeaveRC(rc);
1410 return rc;
1411}
1412
1413/**
1414 * Receives a host request to read a transfer list header on the guest.
1415 *
1416 * @returns VBox status code.
1417 * @param pCtx Shared Clipboard command context to use for the connection.
1418 * @param phList Where to return the list handle to read list header for.
1419 * @param pfFlags Where to return the List header read flags to use.
1420 */
1421VBGLR3DECL(int) VbglR3ClipboardTransferListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1422{
1423 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1424 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1425 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1426
1427 VBoxShClListHdrReadReqMsg Msg;
1428 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1429 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1430
1431 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1432 Msg.ReqParms.uHandle.SetUInt64(0);
1433 Msg.ReqParms.fFlags.SetUInt32(0);
1434
1435 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1436 if (RT_SUCCESS(rc))
1437 {
1438 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1439 if (RT_SUCCESS(rc))
1440 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1441 if (RT_SUCCESS(rc))
1442 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1443 }
1444
1445 LogFlowFuncLeaveRC(rc);
1446 return rc;
1447}
1448
1449/**
1450 * Sends (writes) a transfer list header to the host.
1451 *
1452 * @returns VBox status code.
1453 * @param pCtx Shared Clipboard command context to use for the connection.
1454 * @param hList List handle to write list header for.
1455 * @param pListHdr List header to write.
1456 */
1457VBGLR3DECL(int) VbglR3ClipboardTransferListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1458 PSHCLLISTHDR pListHdr)
1459{
1460 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1461 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1462
1463 VBoxShClListHdrMsg Msg;
1464 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1465 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1466
1467 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1468 Msg.ReqParms.uHandle.SetUInt64(hList);
1469 Msg.ReqParms.fFlags.SetUInt32(0);
1470
1471 Msg.fFeatures.SetUInt32(0);
1472 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1473 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
1474 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1475
1476 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1477
1478 LogFlowFuncLeaveRC(rc);
1479 return rc;
1480}
1481
1482/**
1483 * Sends a request to read a transfer list entry from the host.
1484 *
1485 * @returns VBox status code.
1486 * @param pCtx Shared Clipboard command context to use for the connection.
1487 * @param hList List handle to request to read a list entry for.
1488 * @param pListEntry Where to return the list entry read from the host.
1489 */
1490VBGLR3DECL(int) VbglR3ClipboardTransferListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1491 PSHCLLISTENTRY pListEntry)
1492{
1493 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1494 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1495
1496 VBoxShClListEntryMsg Msg;
1497 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1498 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1499
1500 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
1501
1502 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1503 Msg.ReqParms.uHandle.SetUInt64(hList);
1504 Msg.ReqParms.fInfo.SetUInt32(fInfo);
1505
1506 char szName[SHCLLISTENTRY_MAX_NAME];
1507 Msg.szName.SetPtr(szName, sizeof(szName));
1508
1509 void *pvInfo = NULL;
1510 uint32_t cbInfo = 0;
1511
1512 int rc = VINF_SUCCESS;
1513
1514 if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
1515 {
1516 cbInfo = sizeof(SHCLFSOBJINFO);
1517 pvInfo = RTMemAlloc(cbInfo);
1518 if (!pvInfo)
1519 rc = VERR_NO_MEMORY;
1520 }
1521
1522 if (RT_SUCCESS(rc))
1523 {
1524 Msg.cbInfo.SetUInt32(cbInfo);
1525 Msg.pvInfo.SetPtr(pvInfo, cbInfo);
1526
1527 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1528 if (RT_SUCCESS(rc))
1529 {
1530 uint32_t cbInfoRet = 0;
1531 rc = Msg.cbInfo.GetUInt32(&cbInfoRet);
1532 if (RT_SUCCESS(rc))
1533 {
1534 AssertMsgStmt(cbInfo == cbInfoRet,
1535 ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
1536 if (RT_SUCCESS(rc))
1537 rc = ShClTransferListEntryInitEx(pListEntry, fInfo, szName, pvInfo, cbInfo);
1538 if (RT_SUCCESS(rc))
1539 {
1540 pvInfo = NULL; /* Entry took ownership of pvInfo now. */
1541 cbInfo = 0;
1542 }
1543 }
1544 }
1545 else
1546 LogRel(("Shared Clipboard: Reading list entry failed: %Rrc\n", rc));
1547 }
1548
1549 RTMemFree(pvInfo);
1550
1551 LogFlowFuncLeaveRC(rc);
1552 return rc;
1553}
1554
1555/**
1556 * Receives a host request to read a transfer list entry from the guest.
1557 *
1558 * @returns VBox status code.
1559 * @param pCtx Shared Clipboard command context to use for the connection.
1560 * @param phList Where to return the list handle to read a list entry for.
1561 * @param pfInfo Where to return the list read flags.
1562 */
1563VBGLR3DECL(int) VbglR3ClipboardTransferListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1564{
1565 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1566 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1567 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1568
1569 VBoxShClListEntryReadReqMsg Msg;
1570 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1571 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1572
1573 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1574 Msg.ReqParms.uHandle.SetUInt64(0);
1575 Msg.ReqParms.fInfo.SetUInt32(0);
1576
1577 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1578 if (RT_SUCCESS(rc))
1579 {
1580 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1581 if (RT_SUCCESS(rc))
1582 {
1583 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1584 AssertRC(rc);
1585 }
1586 if (RT_SUCCESS(rc))
1587 {
1588 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1589 AssertRC(rc);
1590 }
1591 }
1592
1593 LogFlowFuncLeaveRC(rc);
1594 return rc;
1595}
1596
1597/**
1598 * Sends (writes) a transfer list entry to the host.
1599 *
1600 * @returns VBox status code.
1601 * @param pCtx Shared Clipboard command context to use for the connection.
1602 * @param hList List handle to write a list etnry for.
1603 * @param pListEntry List entry to write.
1604 */
1605VBGLR3DECL(int) VbglR3ClipboardTransferListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1606 PSHCLLISTENTRY pListEntry)
1607{
1608 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1609 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1610
1611 VBoxShClListEntryMsg Msg;
1612 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1613 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1614
1615 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1616 Msg.ReqParms.uHandle.SetUInt64(hList);
1617 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1618
1619 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1620 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1621 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1622
1623 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1624
1625 LogFlowFuncLeaveRC(rc);
1626 return rc;
1627}
1628
1629/**
1630 * Receives a host request to open a transfer object on the guest.
1631 *
1632 * @returns VBox status code.
1633 * @param pCtx Shared Clipboard command context to use for the connection.
1634 * @param pCreateParms Where to store the object open/create parameters received from the host.
1635 */
1636VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1637{
1638 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1639 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1640
1641 VBoxShClObjOpenMsg Msg;
1642 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1643 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1644
1645 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1646 Msg.uHandle.SetUInt64(0);
1647 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1648 Msg.fCreate.SetUInt32(0);
1649
1650 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1651 if (RT_SUCCESS(rc))
1652 {
1653 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1654 if (RT_SUCCESS(rc))
1655 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1656 }
1657
1658 LogFlowFuncLeaveRC(rc);
1659 return rc;
1660}
1661
1662/**
1663 * Replies a host request to open a transfer object.
1664 *
1665 * @returns VBox status code.
1666 * @param pCtx Shared Clipboard command context to use for the connection.
1667 * @param rcReply Return code to reply to the host.
1668 * @param hObj Object handle of opened object to reply to the host.
1669 */
1670VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1671{
1672 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1673
1674 VBoxShClReplyMsg Msg;
1675 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1676 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1677
1678 Msg.uContext.SetUInt64(pCtx->idContext);
1679 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
1680 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1681 Msg.pvPayload.SetPtr(NULL, 0);
1682
1683 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1684
1685 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1686
1687 LogFlowFuncLeaveRC(rc);
1688 return rc;
1689}
1690
1691/**
1692 * Sends a transfer object open request to the host.
1693 *
1694 * @returns VBox status code.
1695 * @param pCtx Shared Clipboard command context to use for the connection.
1696 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1697 * @param phObj Where to return the object handle from the host.
1698 */
1699VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1700 PSHCLOBJHANDLE phObj)
1701{
1702 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1703 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1704 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1705
1706 int rc = ShClTransferTransformPath(pCreateParms->pszPath, pCreateParms->cbPath);
1707 AssertRCReturn(rc, rc);
1708
1709 VBoxShClObjOpenMsg Msg;
1710 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1711 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1712
1713 Msg.uContext.SetUInt64(pCtx->idContext);
1714 Msg.uHandle.SetUInt64(0);
1715 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1716 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1717
1718 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1719 if (RT_SUCCESS(rc))
1720 Msg.uHandle.GetUInt64(phObj);
1721
1722 LogFlowFuncLeaveRC(rc);
1723 return rc;
1724}
1725
1726/**
1727 * Receives a host request to close a transfer object on the guest.
1728 *
1729 * @returns VBox status code.
1730 * @param pCtx Shared Clipboard command context to use for the connection.
1731 * @param phObj Where to return the object handle to close from the host.
1732 */
1733VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1734{
1735 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1736 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1737
1738 VBoxShClObjCloseMsg Msg;
1739 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1740 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1741
1742 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1743 Msg.uHandle.SetUInt64(0);
1744
1745 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1746 if (RT_SUCCESS(rc))
1747 {
1748 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1749 if (RT_SUCCESS(rc))
1750 rc = Msg.uHandle.GetUInt64(phObj);
1751 }
1752
1753 LogFlowFuncLeaveRC(rc);
1754 return rc;
1755}
1756
1757/**
1758 * Replies to a transfer object open request from the host.
1759 *
1760 * @returns VBox status code.
1761 * @param pCtx Shared Clipboard command context to use for the connection.
1762 * @param rcReply Return code to reply to the host.
1763 * @param hObj Object handle to reply to the host.
1764 */
1765VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1766{
1767 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1768
1769 VBoxShClReplyMsg Msg;
1770 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1771 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1772
1773 Msg.uContext.SetUInt64(pCtx->idContext);
1774 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
1775 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1776 Msg.pvPayload.SetPtr(NULL, 0);
1777
1778 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1779
1780 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1781
1782 LogFlowFuncLeaveRC(rc);
1783 return rc;
1784}
1785
1786/**
1787 * Sends a request to close a transfer object to the host.
1788 *
1789 * @returns VBox status code.
1790 * @param pCtx Shared Clipboard command context to use for the connection.
1791 * @param hObj Object handle to close on the host.
1792 */
1793VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1794{
1795 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1796
1797 VBoxShClObjCloseMsg Msg;
1798 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1799 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1800
1801 Msg.uContext.SetUInt64(pCtx->idContext);
1802 Msg.uHandle.SetUInt64(hObj);
1803
1804 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1805
1806 LogFlowFuncLeaveRC(rc);
1807 return rc;
1808}
1809
1810/**
1811 * Receives a host request to read from a transfer object on the guest.
1812 *
1813 * @returns VBox status code.
1814 * @param pCtx Shared Clipboard command context to use for the connection.
1815 * @param phObj Where to return the object handle to read from.
1816 * @param pcbToRead Where to return the amount (in bytes) to read.
1817 * @param pfFlags Where to return the read flags.
1818 */
1819VBGLR3DECL(int) VbglR3ClipboardTransferObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1820 uint32_t *pfFlags)
1821{
1822 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1823 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1824 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1825 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1826
1827 VBoxShClObjReadReqMsg Msg;
1828 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1829 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1830
1831 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1832 Msg.ReqParms.uHandle.SetUInt64(0);
1833 Msg.ReqParms.cbToRead.SetUInt32(0);
1834 Msg.ReqParms.fRead.SetUInt32(0);
1835
1836 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1837 if (RT_SUCCESS(rc))
1838 {
1839 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1840 if (RT_SUCCESS(rc))
1841 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1842 if (RT_SUCCESS(rc))
1843 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1844 if (RT_SUCCESS(rc))
1845 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1846 }
1847
1848 LogFlowFuncLeaveRC(rc);
1849 return rc;
1850}
1851
1852/**
1853 * Sends a request to read from a transfer object to the host.
1854 *
1855 * @returns VBox status code.
1856 * @param pCtx Shared Clipboard command context to use for the connection.
1857 * @param hObj Object handle of object to read from.
1858 * @param pvData Buffer where to store the read object data.
1859 * @param cbData Size (in bytes) of buffer.
1860 * @param pcbRead Where to store the amount (in bytes) read from the object.
1861 */
1862VBGLR3DECL(int) VbglR3ClipboardTransferObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1863 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1864{
1865 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1866 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1867 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1868 /* pcbRead is optional. */
1869
1870 VBoxShClObjReadWriteMsg Msg;
1871 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1872 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1873
1874 Msg.uContext.SetUInt64(pCtx->idContext);
1875 Msg.uHandle.SetUInt64(hObj);
1876 Msg.cbData.SetUInt32(cbData);
1877 Msg.pvData.SetPtr(pvData, cbData);
1878 Msg.cbChecksum.SetUInt32(0);
1879 Msg.pvChecksum.SetPtr(NULL, 0);
1880
1881 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1882 if (RT_SUCCESS(rc))
1883 {
1884 /** @todo Add checksum support. */
1885
1886 if (pcbRead)
1887 {
1888 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1889 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1890 }
1891 }
1892
1893 LogFlowFuncLeaveRC(rc);
1894 return rc;
1895}
1896
1897/**
1898 * Sends a request to write to a transfer object to the host.
1899 *
1900 * @returns VBox status code.
1901 * @param pCtx Shared Clipboard command context to use for the connection.
1902 * @param hObj Object handle of object to write to.
1903 * @param pvData Buffer of data to write to object.
1904 * @param cbData Size (in bytes) of buffer.
1905 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1906 */
1907VBGLR3DECL(int) VbglR3ClipboardTransferObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1908 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1909{
1910 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1911 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1912 /* cbData can be 0. */
1913 /* pcbWritten is optional. */
1914
1915 VBoxShClObjReadWriteMsg Msg;
1916 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1917 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1918
1919 Msg.uContext.SetUInt64(pCtx->idContext);
1920 Msg.uHandle.SetUInt64(hObj);
1921 Msg.cbData.SetUInt32(cbData);
1922 Msg.pvData.SetPtr(pvData, cbData);
1923 Msg.cbChecksum.SetUInt32(0);
1924 Msg.pvChecksum.SetPtr(NULL, 0);
1925
1926 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1927 if (RT_SUCCESS(rc))
1928 {
1929 /** @todo Add checksum support. */
1930
1931 if (pcbWritten)
1932 *pcbWritten = cbData; /** @todo For now return all as being written. */
1933 }
1934
1935 LogFlowFuncLeaveRC(rc);
1936 return rc;
1937}
1938
1939
1940/*********************************************************************************************************************************
1941* Transfer interface implementations *
1942*********************************************************************************************************************************/
1943
1944/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
1945static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGRootListRead(PSHCLTXPROVIDERCTX pCtx)
1946{
1947 LogFlowFuncEnter();
1948
1949 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1950 AssertPtr(pCmdCtx);
1951
1952 int rc = VbglR3ClipboardTransferRootListRead(pCmdCtx, pCtx->pTransfer);
1953
1954 LogFlowFuncLeaveRC(rc);
1955 return rc;
1956}
1957
1958/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
1959static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1960 PSHCLLISTHANDLE phList)
1961{
1962 LogFlowFuncEnter();
1963
1964 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1965 AssertPtr(pCmdCtx);
1966
1967 int rc = VbglR3ClipboardTransferListOpenSend(pCmdCtx, pOpenParms, phList);
1968
1969 LogFlowFuncLeaveRC(rc);
1970 return rc;
1971}
1972
1973/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
1974static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1975{
1976 LogFlowFuncEnter();
1977
1978 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1979 AssertPtr(pCmdCtx);
1980
1981 int rc = VbglR3ClipboardTransferListCloseSend(pCmdCtx, hList);
1982
1983 LogFlowFuncLeaveRC(rc);
1984 return rc;
1985}
1986
1987/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
1988static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1989 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1990{
1991 LogFlowFuncEnter();
1992
1993 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1994 AssertPtr(pCmdCtx);
1995
1996 int rc = ShClTransferListHdrInit(pListHdr);
1997 if (RT_SUCCESS(rc))
1998 {
1999 if (RT_SUCCESS(rc))
2000 {
2001 rc = VbglR3ClipboardTransferListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
2002 }
2003 else
2004 ShClTransferListHdrDestroy(pListHdr);
2005 }
2006
2007 LogFlowFuncLeaveRC(rc);
2008 return rc;
2009}
2010
2011/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
2012static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGListEntryRead(PSHCLTXPROVIDERCTX pCtx,
2013 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
2014{
2015 LogFlowFuncEnter();
2016
2017 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2018 AssertPtr(pCmdCtx);
2019
2020 int rc = VbglR3ClipboardTransferListEntryRead(pCmdCtx, hList, pListEntry);
2021
2022 LogFlowFuncLeaveRC(rc);
2023 return rc;
2024}
2025
2026/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
2027static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjOpen(PSHCLTXPROVIDERCTX pCtx,
2028 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
2029{
2030 LogFlowFuncEnter();
2031
2032 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2033 AssertPtr(pCmdCtx);
2034
2035 int rc = VbglR3ClipboardTransferObjOpenSend(pCmdCtx, pCreateParms, phObj);
2036
2037 LogFlowFuncLeaveRC(rc);
2038 return rc;
2039}
2040
2041/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
2042static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
2043{
2044 LogFlowFuncEnter();
2045
2046 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2047 AssertPtr(pCmdCtx);
2048
2049 int rc = VbglR3ClipboardTransferObjCloseSend(pCmdCtx, hObj);
2050
2051 LogFlowFuncLeaveRC(rc);
2052 return rc;
2053}
2054
2055/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
2056static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceHGObjRead(PSHCLTXPROVIDERCTX pCtx,
2057 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
2058 uint32_t fFlags, uint32_t *pcbRead)
2059{
2060 LogFlowFuncEnter();
2061
2062 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
2063 AssertPtr(pCmdCtx);
2064
2065 RT_NOREF(fFlags); /* Not used yet. */
2066
2067 int rc = VbglR3ClipboardTransferObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
2068
2069 LogFlowFuncLeaveRC(rc);
2070 return rc;
2071}
2072
2073/**
2074 * Creates (and registers) a transfer on the guest side.
2075 *
2076 * @returns VBox status code.
2077 * @param pCmdCtx Command context to use.
2078 * @param pTransferCtx Transfer context to init transfer for.
2079 * @param enmDir Specifies the transfer direction of this transfer.
2080 * @param enmSource Specifies the data source of the transfer.
2081 * @param idTransfer ID of transfer to create.
2082 * @param ppTransfer Where to return the transfer object on success. Optional.
2083 */
2084static int vbglR3ClipboardTransferCreate(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2085 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer,
2086 PSHCLTRANSFER *ppTransfer)
2087{
2088 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_WRONG_ORDER);
2089
2090 RT_NOREF(pCmdCtx);
2091
2092 PSHCLTRANSFER pTransfer;
2093 int rc = ShClTransferCreate(enmDir, enmSource, &pCmdCtx->Transfers.Callbacks, &pTransfer);
2094 if (RT_SUCCESS(rc))
2095 {
2096 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
2097 if ( RT_SUCCESS(rc)
2098 && ppTransfer)
2099 *ppTransfer = pTransfer;
2100 }
2101
2102 if (RT_SUCCESS(rc))
2103 LogRel2(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
2104 else
2105 LogRel(("Shared Clipboard: Error creating transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2106
2107 LogFlowFuncLeaveRC(rc);
2108 return rc;
2109}
2110
2111/**
2112 * Initializes a transfer on the guest side.
2113 *
2114 * @returns VBox status code.
2115 * @param pCmdCtx Command context to use.
2116 * @param pTransfer Transfer to init.
2117 */
2118static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2119{
2120 LogFlowFuncEnter();
2121
2122 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2123
2124 SHCLTXPROVIDER Provider;
2125 RT_ZERO(Provider);
2126
2127 /* Assign local provider first and overwrite interface methods below if needed. */
2128 ShClTransferProviderLocalQueryInterface(&Provider);
2129
2130 /* If this is a read transfer (reading data from host), set the interface to use
2131 * our VbglR3 routines here. */
2132 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2133 {
2134 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceHGRootListRead;
2135
2136 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceHGListOpen;
2137 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceHGListClose;
2138 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceHGListHdrRead;
2139 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceHGListEntryRead;
2140
2141 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceHGObjOpen;
2142 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceHGObjClose;
2143 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceHGObjRead;
2144 }
2145 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2146 {
2147 /* Uses the local provider assigned above. */
2148 }
2149 else
2150 AssertFailed();
2151
2152 Provider.pvUser = pCmdCtx;
2153
2154 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2155 * provider functions. */
2156 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2157 if (RT_SUCCESS(rc))
2158 rc = ShClTransferInit(pTransfer);
2159
2160 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2161
2162 if (RT_SUCCESS(rc))
2163 {
2164 LogRel2(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2165 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2166 }
2167 else
2168 LogRel(("Shared Clipboard: Unable to initialize transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2169
2170 LogFlowFuncLeaveRC(rc);
2171 return rc;
2172}
2173
2174/**
2175 * Destroys a transfer on the guest side.
2176 *
2177 * @returns VBox status code.
2178 * @param pCmdCtx Command context to use.
2179 * @param pTransferCtx Transfer context to uninit transfer for.
2180 * @param idTransfer ID of transfer to initialize.
2181 */
2182static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2183{
2184 RT_NOREF(pCmdCtx);
2185
2186 LogFlowFuncEnter();
2187
2188 int rc = VINF_SUCCESS;
2189
2190 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2191 if (pTransfer)
2192 {
2193 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2194 if (RT_SUCCESS(rc))
2195 rc = ShClTransferDestroy(pTransfer);
2196
2197 if (RT_SUCCESS(rc))
2198 {
2199 LogRel(("Shared Clipboard: Transfer %RU16 successfully uninitialized\n", idTransfer));
2200 }
2201 else
2202 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU16, rc=%Rrc\n", idTransfer, rc));
2203 }
2204
2205 LogFlowFuncLeaveRC(rc);
2206 return rc;
2207}
2208
2209/**
2210 * Requests a new host -> guest transfer from the host.
2211 *
2212 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2213 * This ID will be used to initialize the transfer on the guest side then.
2214 *
2215 * @returns VBox status code.
2216 * @param pCmdCtx Command context to use.
2217 */
2218VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2219{
2220 LogFlowFuncEnter();
2221
2222 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2223
2224 int rc = vbglR3ClipboardTransferSendStatusEx(pCmdCtx, 0 /* Context ID not needed */,
2225 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2226 LogFlowFuncLeaveRC(rc);
2227 return rc;
2228}
2229
2230/**
2231 * Starts a transfer on the guest side.
2232 *
2233 * @returns VBox status code.
2234 * @param pCmdCtx Command context to use.
2235 * @param pTransferCtx Transfer context to start transfer for.
2236 * @param uTransferID ID to use for transfer to start.
2237 */
2238static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2239 SHCLTRANSFERID uTransferID)
2240{
2241 RT_NOREF(pCmdCtx);
2242
2243 LogFlowFuncEnter();
2244
2245 int rc;
2246
2247 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2248 if (pTransfer)
2249 {
2250 rc = ShClTransferStart(pTransfer);
2251 if (RT_SUCCESS(rc))
2252 {
2253 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2254 }
2255 else
2256 LogRel(("Shared Clipboard: Unable to start transfer %RU16, rc=%Rrc\n", uTransferID, rc));
2257 }
2258 else
2259 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2260
2261 /* Send a reply in any case. */
2262 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2263 RT_SUCCESS(rc)
2264 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2265 if (RT_SUCCESS(rc))
2266 rc = rc2;
2267
2268 LogFlowFuncLeaveRC(rc);
2269 return rc;
2270}
2271
2272VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2273 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2274 PVBGLR3CLIPBOARDEVENT pEvent)
2275{
2276 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2277 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2278 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2279
2280 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2281
2282 int rc;
2283 if (!pCmdCtx->fUseLegacyProtocol)
2284 {
2285 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2286
2287 switch (idMsg)
2288 {
2289 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2290 {
2291 SHCLTRANSFERDIR enmDir;
2292 SHCLTRANSFERREPORT transferReport;
2293 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2294 if (RT_SUCCESS(rc))
2295 {
2296 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2297
2298 LogRel2(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU16\n",
2299 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2300
2301 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2302
2303 switch (transferReport.uStatus)
2304 {
2305 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2306 {
2307 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2308 enmSource = SHCLSOURCE_REMOTE;
2309
2310 /* The host acknowledged our request to create a new transfer.
2311 * So create a new transfer here with the transfer ID we just got from the host.
2312 *
2313 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2314 */
2315 PSHCLTRANSFER pTransfer;
2316 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2317
2318 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2319 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2320 * back to us (see case down below).*/
2321 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2322 RT_SUCCESS(rc)
2323 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2324 if (RT_SUCCESS(rc))
2325 rc = rc2;
2326 break;
2327 }
2328
2329 case SHCLTRANSFERSTATUS_INITIALIZED:
2330 {
2331 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2332 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2333 {
2334 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2335 enmSource = SHCLSOURCE_REMOTE;
2336 }
2337 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2338 {
2339 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2340 enmSource = SHCLSOURCE_LOCAL;
2341 }
2342 else
2343 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2344
2345 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2346 {
2347 /* The host reported INITIALIZED for the transfer.
2348 * So init our local transfer as well now. */
2349 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2350 if (pTransfer)
2351 {
2352 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2353
2354 /* Only send back a reply on error -- we already reported INITIALIZED
2355 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2356 if (RT_FAILURE(rc))
2357 {
2358 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2359 SHCLTRANSFERSTATUS_ERROR, rc);
2360 AssertRC(rc2);
2361 }
2362 }
2363 else
2364 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2365 }
2366 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2367 {
2368 /* The host reported the INITIALIZED status together with the transfer ID.
2369 * So create a local transfer here with that ID. */
2370 PSHCLTRANSFER pTransfer;
2371 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2372 if (RT_SUCCESS(rc))
2373 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2374
2375 /* Send a reply in any case. */
2376 int rc2 = VbglR3ClipboardTransferSendStatus(pCmdCtx, pTransfer,
2377 RT_SUCCESS(rc)
2378 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2379 if (RT_SUCCESS(rc))
2380 rc = rc2;
2381 }
2382 else
2383 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2384
2385 break;
2386 }
2387
2388 case SHCLTRANSFERSTATUS_STARTED:
2389 {
2390 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2391 break;
2392 }
2393
2394 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2395 RT_FALL_THROUGH();
2396 case SHCLTRANSFERSTATUS_COMPLETED:
2397 RT_FALL_THROUGH();
2398 case SHCLTRANSFERSTATUS_CANCELED:
2399 RT_FALL_THROUGH();
2400 case SHCLTRANSFERSTATUS_KILLED:
2401 RT_FALL_THROUGH();
2402 case SHCLTRANSFERSTATUS_ERROR:
2403 {
2404 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2405 break;
2406 }
2407
2408 default:
2409 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU16\n",
2410 transferReport.uStatus, pEvent->u.TransferStatus.Report.rc, pEvent->u.TransferStatus.uID));
2411 rc = VERR_NOT_SUPPORTED;
2412 break;
2413 }
2414
2415 if (RT_SUCCESS(rc))
2416 {
2417 pEvent->u.TransferStatus.enmDir = enmDir;
2418 pEvent->u.TransferStatus.Report = transferReport;
2419 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2420
2421 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2422 }
2423 }
2424 break;
2425 }
2426
2427 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2428 {
2429 uint32_t fRoots;
2430 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2431
2432 /** @todo Validate / handle fRoots. */
2433
2434 if (RT_SUCCESS(rc))
2435 {
2436 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2437 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2438 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2439
2440 SHCLLISTHDR rootListHdr;
2441 ShClTransferListHdrInit(&rootListHdr);
2442
2443 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2444
2445 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2446
2447 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2448 }
2449 break;
2450 }
2451
2452 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2453 {
2454 uint64_t uIndex;
2455 uint32_t fInfo;
2456 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2457 if (RT_SUCCESS(rc))
2458 {
2459 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2460 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2461 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2462
2463 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2464 if (pEntry)
2465 {
2466 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2467 }
2468 else
2469 rc = VERR_NOT_FOUND;
2470 }
2471 break;
2472 }
2473
2474 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2475 {
2476 SHCLLISTOPENPARMS openParmsList;
2477 rc = ShClTransferListOpenParmsInit(&openParmsList);
2478 if (RT_SUCCESS(rc))
2479 {
2480 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2481 if (RT_SUCCESS(rc))
2482 {
2483 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2484 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2485 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2486
2487 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2488
2489 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2490 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2491
2492 /* Reply in any case. */
2493 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2494 AssertRC(rc2);
2495 }
2496
2497 ShClTransferListOpenParmsDestroy(&openParmsList);
2498 }
2499
2500 break;
2501 }
2502
2503 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2504 {
2505 SHCLLISTHANDLE hList;
2506 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2507 if (RT_SUCCESS(rc))
2508 {
2509 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2510 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2511 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2512
2513 rc = ShClTransferListClose(pTransfer, hList);
2514
2515 /* Reply in any case. */
2516 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2517 AssertRC(rc2);
2518 }
2519
2520 break;
2521 }
2522
2523 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2524 {
2525 /** @todo Handle filter + list features. */
2526
2527 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2528 uint32_t fFlags = 0;
2529 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2530 if (RT_SUCCESS(rc))
2531 {
2532 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2533 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2534 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2535
2536 SHCLLISTHDR hdrList;
2537 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2538 if (RT_SUCCESS(rc))
2539 {
2540 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2541
2542 ShClTransferListHdrDestroy(&hdrList);
2543 }
2544 }
2545
2546 break;
2547 }
2548
2549 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2550 {
2551 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2552
2553 SHCLLISTHANDLE hList;
2554 uint32_t fInfo;
2555 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2556 if (RT_SUCCESS(rc))
2557 {
2558 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2559 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2560 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2561
2562 SHCLLISTENTRY entryList;
2563 rc = ShClTransferListEntryInit(&entryList);
2564 if (RT_SUCCESS(rc))
2565 {
2566 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2567 if (RT_SUCCESS(rc))
2568 {
2569 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2570 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2571
2572 RT_NOREF(pObjInfo);
2573
2574 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2575
2576 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2577
2578 ShClTransferListEntryDestroy(&entryList);
2579 }
2580 }
2581 }
2582
2583 break;
2584 }
2585
2586 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2587 {
2588 SHCLOBJOPENCREATEPARMS openParms;
2589 rc = ShClTransferObjOpenParmsInit(&openParms);
2590 if (RT_SUCCESS(rc))
2591 {
2592 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2593 if (RT_SUCCESS(rc))
2594 {
2595 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2596 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2597 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2598
2599 SHCLOBJHANDLE hObj;
2600 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2601
2602 /* Reply in any case. */
2603 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2604 AssertRC(rc2);
2605 }
2606
2607 ShClTransferObjOpenParmsDestroy(&openParms);
2608 }
2609
2610 break;
2611 }
2612
2613 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2614 {
2615 SHCLOBJHANDLE hObj;
2616 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2617 if (RT_SUCCESS(rc))
2618 {
2619 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2620 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2621 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2622
2623 rc = ShClTransferObjClose(pTransfer, hObj);
2624
2625 /* Reply in any case. */
2626 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2627 AssertRC(rc2);
2628 }
2629
2630 break;
2631 }
2632
2633 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2634 {
2635 SHCLOBJHANDLE hObj;
2636 uint32_t cbBuf;
2637 uint32_t fFlags;
2638 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2639 if (RT_SUCCESS(rc))
2640 {
2641 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2642 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2643 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2644
2645 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2646
2647 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2648
2649 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2650 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2651
2652 void *pvBuf = RTMemAlloc(cbToRead);
2653 if (pvBuf)
2654 {
2655 uint32_t cbRead;
2656 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2657 if (RT_SUCCESS(rc))
2658 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2659
2660 RTMemFree(pvBuf);
2661 }
2662 else
2663 rc = VERR_NO_MEMORY;
2664 }
2665
2666 break;
2667 }
2668
2669 default:
2670 {
2671 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2672 if (RT_FAILURE(rc))
2673 fErrorSent = true;
2674 break;
2675 }
2676 }
2677
2678 if ( !fErrorSent
2679 && RT_FAILURE(rc))
2680 {
2681 /* Report transfer-specific error back to the host. */
2682 int rc2 = vbglR3ClipboardTransferSendStatusEx(pCmdCtx, pCmdCtx->idContext, SHCLTRANSFERSTATUS_ERROR, rc);
2683 AssertRC(rc2);
2684 }
2685 }
2686 else
2687 {
2688 /*
2689 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2690 * !HACK ALERT! cParms is the format flag or flags.
2691 */
2692 rc = VINF_SUCCESS;
2693 switch (idMsg)
2694 {
2695 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2696 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2697 pEvent->u.fReportedFormats = cParms;
2698 break;
2699
2700 case VBOX_SHCL_HOST_MSG_READ_DATA:
2701 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2702 pEvent->u.fReadData = cParms;
2703 break;
2704
2705 case VBOX_SHCL_HOST_MSG_QUIT:
2706 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2707 break;
2708
2709 default:
2710 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2711 rc = VERR_NOT_SUPPORTED;
2712 break;
2713 }
2714 }
2715
2716 LogFlowFuncLeaveRC(rc);
2717 return rc;
2718}
2719
2720#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2721
2722VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2723{
2724 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2725 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2726
2727 RT_NOREF(cParms);
2728
2729 int rc;
2730 if (!pCtx->fUseLegacyProtocol)
2731 {
2732 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2733 switch (idMsg)
2734 {
2735 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2736 {
2737 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2738 if (RT_SUCCESS(rc))
2739 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2740 break;
2741 }
2742
2743 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2744 {
2745 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2746 if (RT_SUCCESS(rc))
2747 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2748 break;
2749 }
2750
2751 case VBOX_SHCL_HOST_MSG_READ_DATA:
2752 {
2753 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2754 if (RT_SUCCESS(rc))
2755 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2756 break;
2757 }
2758
2759 case VBOX_SHCL_HOST_MSG_QUIT:
2760 {
2761 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2762 rc = VINF_SUCCESS;
2763 break;
2764 }
2765
2766 default:
2767 {
2768 /** @todo r=bird: BUGBUG - need a skip command here! */
2769 rc = VERR_NOT_SUPPORTED;
2770 break;
2771 }
2772 }
2773
2774 if (RT_SUCCESS(rc))
2775 {
2776 /* Copy over our command context to the event. */
2777 pEvent->cmdCtx = *pCtx;
2778 }
2779 else
2780 {
2781 /* Report error back to the host. */
2782 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2783 AssertRC(rc2);
2784 }
2785 }
2786 else
2787 {
2788 /*
2789 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2790 * !HACK ALERT! cParms is the format flag or flags.
2791 */
2792 rc = VINF_SUCCESS;
2793 switch (idMsg)
2794 {
2795 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2796 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2797 pEvent->u.fReportedFormats = cParms;
2798 break;
2799
2800 case VBOX_SHCL_HOST_MSG_READ_DATA:
2801 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2802 pEvent->u.fReadData = cParms;
2803 break;
2804
2805 case VBOX_SHCL_HOST_MSG_QUIT:
2806 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2807 break;
2808
2809 default:
2810 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2811 rc = VERR_NOT_SUPPORTED;
2812 break;
2813 }
2814 pEvent->cmdCtx = *pCtx;
2815 }
2816
2817 LogFlowFuncLeaveRC(rc);
2818 return rc;
2819}
2820
2821/**
2822 * Frees (destroys) a formerly allocated Shared Clipboard event.
2823 *
2824 * @returns IPRT status code.
2825 * @param pEvent Event to free (destroy).
2826 */
2827VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2828{
2829 if (!pEvent)
2830 return;
2831
2832 /* Some messages require additional cleanup. */
2833 switch (pEvent->enmType)
2834 {
2835 default:
2836 break;
2837 }
2838
2839 RTMemFree(pEvent);
2840 pEvent = NULL;
2841}
2842
2843/**
2844 * Reports (advertises) guest clipboard formats to the host.
2845 *
2846 * Legacy function, do not use anymore.
2847 *
2848 * @returns VBox status code.
2849 * @param idClient The client id returned by VbglR3ClipboardConnect().
2850 * @param fFormats The formats to report.
2851 */
2852VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2853{
2854 struct
2855 {
2856 VBGLIOCHGCMCALL Hdr;
2857 VBoxShClParmReportFormats Parms;
2858 } Msg;
2859
2860 RT_ZERO(Msg);
2861
2862 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2863 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2864
2865 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2866
2867 LogFlowFuncLeaveRC(rc);
2868 return rc;
2869}
2870
2871/**
2872 * Sends guest clipboard data to the host.
2873 *
2874 * Legacy function kept for compatibility, do not use anymore.
2875 *
2876 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2877 * from the host.
2878 *
2879 * @returns VBox status code.
2880 * @param idClient The client id returned by VbglR3ClipboardConnect().
2881 * @param fFormat The format of the data.
2882 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2883 * is zero.
2884 * @param cbData Number of bytes of data to send. Zero is valid.
2885 */
2886VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2887{
2888 LogFlowFuncEnter();
2889
2890 struct
2891 {
2892 VBGLIOCHGCMCALL Hdr;
2893 VBoxShClParmDataWriteOld Parms;
2894 } Msg;
2895
2896 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2897 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2898 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2899
2900 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2901
2902 LogFlowFuncLeaveRC(rc);
2903 return rc;
2904}
2905
2906/**
2907 * Sends guest clipboard data to the host.
2908 *
2909 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2910 * from the host.
2911 *
2912 * @returns VBox status code.
2913 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2914 * @param fFormat Clipboard format to send.
2915 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2916 * is zero.
2917 * @param cbData Number of bytes of data to send. Zero is valid.
2918 */
2919VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2920{
2921 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2922 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2923
2924 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2925
2926 int rc;
2927 if (pCtx->fUseLegacyProtocol)
2928 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2929 else
2930 {
2931 struct
2932 {
2933 VBGLIOCHGCMCALL Hdr;
2934 VBoxShClParmDataWrite Parms;
2935 } Msg;
2936
2937 RT_ZERO(Msg);
2938
2939 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2940 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2941 Msg.Parms.f32Format.SetUInt32(fFormat);
2942 Msg.Parms.pData.SetPtr(pvData, cbData);
2943
2944 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2945
2946 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2947 }
2948
2949 LogFlowFuncLeaveRC(rc);
2950 return rc;
2951}
2952
2953/**
2954 * Writes an error to the host.
2955 *
2956 * @returns IPRT status code.
2957 * @param idClient The client id returned by VbglR3ClipboardConnect().
2958 * @param rcErr Error (IPRT-style) to send.
2959 */
2960VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2961{
2962 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2963
2964 VBoxShClWriteErrorMsg Msg;
2965 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2966
2967 /** @todo Context ID not used yet. */
2968 Msg.uContext.SetUInt64(0);
2969 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2970
2971 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2972
2973 if (RT_FAILURE(rc))
2974 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2975 if (rc == VERR_NOT_SUPPORTED)
2976 rc = VINF_SUCCESS;
2977
2978 if (RT_FAILURE(rc))
2979 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2980
2981 LogFlowFuncLeaveRC(rc);
2982 return rc;
2983}
2984
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use