VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp@ 49891

Last change on this file since 49891 was 49891, checked in by vboxsync, 11 years ago

Merged private draganddrop branch into trunk.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.9 KB
Line 
1/* $Id: VBoxGuestR3LibDragAndDrop.cpp 49891 2013-12-12 20:09:20Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Drag & Drop.
4 */
5
6/*
7 * Copyright (C) 2011-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/path.h>
32#include <iprt/dir.h>
33#include <iprt/file.h>
34#include <iprt/uri.h>
35#include <iprt/thread.h>
36
37#include <iprt/cpp/list.h>
38#include <iprt/cpp/ministring.h>
39
40#include "VBGLR3Internal.h"
41#include "VBox/HostServices/DragAndDropSvc.h"
42
43/* Here all the communication with the host over HGCM is handled platform
44 * neutral. Also the receiving of URIs content (directory trees and files) is
45 * done here. So the platform code of the guests, should not take care of that.
46 *
47 * Todo:
48 * - Sending dirs/files in the G->H case
49 * - Maybe the EOL converting of text mime-types (not fully sure, eventually
50 * better done on the host side)
51 */
52
53/******************************************************************************
54 * Private internal functions *
55 ******************************************************************************/
56
57static int vbglR3DnDCreateDropDir(char* pszDropDir, size_t cbSize)
58{
59 AssertPtrReturn(pszDropDir, VERR_INVALID_POINTER);
60 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
61
62 /** @todo On Windows we also could use the registry to override
63 * this path, on Posix a dotfile and/or a guest property
64 * can be used. */
65
66 /* Get the users temp directory. Don't use the user's root directory (or
67 * something inside it) because we don't know for how long/if the data will
68 * be kept after the guest OS used it. */
69 int rc = RTPathTemp(pszDropDir, cbSize);
70 if (RT_FAILURE(rc))
71 return rc;
72
73 /* Append our base drop directory. */
74 rc = RTPathAppend(pszDropDir, cbSize, "VirtualBox Dropped Files");
75 if (RT_FAILURE(rc))
76 return rc;
77
78 /* Create it when necessary. */
79 if (!RTDirExists(pszDropDir))
80 {
81 rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
82 if (RT_FAILURE(rc))
83 return rc;
84 }
85
86 /* The actually drop directory consist of the current time stamp and a
87 * unique number when necessary. */
88 char pszTime[64];
89 RTTIMESPEC time;
90 if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
91 return VERR_BUFFER_OVERFLOW;
92#ifdef RT_OS_WINDOWS
93 /* Filter out characters not allowed on Windows platforms, put in by
94 RTTimeSpecToString(). */
95 /** @todo Use something like RTPathSanitize() when available. Later. */
96 RTUNICP aCpSet[] =
97 { ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_',
98 0xa0, 0xd7af, '\0' };
99 RTStrPurgeComplementSet(pszTime, aCpSet, '_' /* Replacement */);
100#endif
101
102 rc = RTPathAppend(pszDropDir, cbSize, pszTime);
103 if (RT_FAILURE(rc))
104 return rc;
105
106 /* Create it (only accessible by the current user) */
107 return RTDirCreateUniqueNumbered(pszDropDir, cbSize, RTFS_UNIX_IRWXU, 3, '-');
108}
109
110static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
111{
112 AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
113 AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
114
115 DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
116 RT_ZERO(Msg);
117 Msg.hdr.result = VERR_WRONG_ORDER;
118 Msg.hdr.u32ClientID = uClientId;
119 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
120 Msg.hdr.cParms = 3;
121
122 Msg.msg.SetUInt32(0);
123 Msg.num_parms.SetUInt32(0);
124 Msg.block.SetUInt32(fWait);
125
126 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
127 if (RT_SUCCESS(rc))
128 {
129 rc = Msg.hdr.result;
130 if (RT_SUCCESS(rc))
131 {
132 /* Fetch results */
133 rc = Msg.msg.GetUInt32(puMsg); AssertRC(rc);
134 rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
135 }
136 }
137
138 return rc;
139}
140
141static int vbglR3DnDHGProcessActionMessage(uint32_t uClientId,
142 uint32_t uMsg,
143 uint32_t *puScreenId,
144 uint32_t *puX,
145 uint32_t *puY,
146 uint32_t *puDefAction,
147 uint32_t *puAllActions,
148 char *pszFormats,
149 uint32_t cbFormats,
150 uint32_t *pcbFormatsRecv)
151{
152 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
153 AssertPtrReturn(puX, VERR_INVALID_POINTER);
154 AssertPtrReturn(puY, VERR_INVALID_POINTER);
155 AssertPtrReturn(puDefAction, VERR_INVALID_POINTER);
156 AssertPtrReturn(puAllActions, VERR_INVALID_POINTER);
157 AssertPtrReturn(pszFormats, VERR_INVALID_POINTER);
158 AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
159 AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
160
161 DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
162 RT_ZERO(Msg);
163 Msg.hdr.u32ClientID = uClientId;
164 Msg.hdr.u32Function = uMsg;
165 Msg.hdr.cParms = 7;
166
167 Msg.uScreenId.SetUInt32(0);
168 Msg.uX.SetUInt32(0);
169 Msg.uY.SetUInt32(0);
170 Msg.uDefAction.SetUInt32(0);
171 Msg.uAllActions.SetUInt32(0);
172 Msg.pvFormats.SetPtr(pszFormats, cbFormats);
173 Msg.cFormats.SetUInt32(0);
174
175 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
176 if (RT_SUCCESS(rc))
177 {
178 rc = Msg.hdr.result;
179 if (RT_SUCCESS(rc))
180 {
181 /* Fetch results */
182 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
183 rc = Msg.uX.GetUInt32(puX); AssertRC(rc);
184 rc = Msg.uY.GetUInt32(puY); AssertRC(rc);
185 rc = Msg.uDefAction.GetUInt32(puDefAction); AssertRC(rc);
186 rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
187 rc = Msg.cFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
188 /* A little bit paranoia */
189 AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
190 }
191 }
192
193 return rc;
194}
195
196static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId)
197{
198 DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
199 RT_ZERO(Msg);
200 Msg.hdr.u32ClientID = uClientId;
201 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
202 Msg.hdr.cParms = 0;
203
204 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
205 if (RT_SUCCESS(rc))
206 rc = Msg.hdr.result;
207
208 return rc;
209}
210
211static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
212{
213 DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
214 RT_ZERO(Msg);
215 Msg.hdr.u32ClientID = uClientId;
216 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
217 Msg.hdr.cParms = 0;
218
219 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
220 if (RT_SUCCESS(rc))
221 rc = Msg.hdr.result;
222
223 return rc;
224}
225
226static int vbglR3DnDHGProcessSendDirMessage(uint32_t uClientId,
227 char *pszDirname,
228 uint32_t cbDirname,
229 uint32_t *pcbDirnameRecv,
230 uint32_t *pfMode)
231{
232 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER);
233 AssertReturn(cbDirname, VERR_INVALID_PARAMETER);
234 AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
235 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
236
237 DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
238 RT_ZERO(Msg);
239 Msg.hdr.u32ClientID = uClientId;
240 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
241 Msg.hdr.cParms = 3;
242
243 Msg.pvName.SetPtr(pszDirname, cbDirname);
244 Msg.cName.SetUInt32(0);
245 Msg.fMode.SetUInt32(0);
246
247 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
248 if (RT_SUCCESS(rc))
249 {
250 rc = Msg.hdr.result;
251 if (RT_SUCCESS(Msg.hdr.result))
252 {
253 /* Fetch results */
254 rc = Msg.cName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
255 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
256 /* A little bit paranoia */
257 AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
258 }
259 }
260
261 return rc;
262}
263
264static int vbglR3DnDHGProcessSendFileMessage(uint32_t uClientId,
265 char *pszFilename,
266 uint32_t cbFilename,
267 uint32_t *pcbFilenameRecv,
268 void *pvData,
269 uint32_t cbData,
270 uint32_t *pcbDataRecv,
271 uint32_t *pfMode)
272{
273 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
274 AssertReturn(cbFilename, VERR_INVALID_PARAMETER);
275 AssertPtrReturn(pcbFilenameRecv, VERR_INVALID_POINTER);
276 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
277 AssertReturn(cbData, VERR_INVALID_PARAMETER);
278 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
279 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
280
281 DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
282 RT_ZERO(Msg);
283 Msg.hdr.u32ClientID = uClientId;
284 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
285 Msg.hdr.cParms = 5;
286
287 Msg.pvName.SetPtr(pszFilename, cbFilename);
288 Msg.cName.SetUInt32(0);
289 Msg.pvData.SetPtr(pvData, cbData);
290 Msg.cData.SetUInt32(0);
291 Msg.fMode.SetUInt32(0);
292
293 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
294 if (RT_SUCCESS(rc))
295 {
296 rc = Msg.hdr.result;
297 if (RT_SUCCESS(rc))
298 {
299 /* Fetch results */
300 rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
301 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
302 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
303 /* A little bit paranoia */
304 AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
305 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
306 }
307 }
308
309 return rc;
310}
311
312static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId,
313 uint32_t *puScreenId,
314 char *pszFormat,
315 uint32_t cbFormat,
316 uint32_t *pcbFormatRecv,
317 void **ppvData,
318 uint32_t cbData,
319 size_t *pcbDataRecv)
320{
321 /* Make a string list out of the uri data. */
322 RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
323 if (uriList.isEmpty())
324 return VINF_SUCCESS;
325
326 uint32_t cbTmpData = _1M * 10;
327 void *pvTmpData = RTMemAlloc(cbTmpData);
328 if (!pvTmpData)
329 return VERR_NO_MEMORY;
330
331 /* Create and query the drop target directory. */
332 char pszDropDir[RTPATH_MAX];
333 int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
334 if (RT_FAILURE(rc))
335 {
336 RTMemFree(pvTmpData);
337 return rc;
338 }
339
340 /* Patch the old drop data with the new drop directory, so the drop target
341 * can find the files. */
342 RTCList<RTCString> guestUriList;
343 for (size_t i = 0; i < uriList.size(); ++i)
344 {
345 const RTCString &strUri = uriList.at(i);
346 /* Query the path component of a file URI. If this hasn't a
347 * file scheme, null is returned. */
348 if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
349 {
350 RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
351 char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
352 if (pszNewUri)
353 {
354 guestUriList.append(pszNewUri);
355 RTStrFree(pszNewUri);
356 }
357 }
358 else
359 guestUriList.append(strUri);
360 }
361
362 /* Cleanup the old data and write the new data back to the event. */
363 RTMemFree(*ppvData);
364 RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
365 *ppvData = RTStrDupN(newData.c_str(), newData.length());
366 *pcbDataRecv = newData.length() + 1;
367
368 /* Lists for holding created files & directories in the case of a
369 * rollback. */
370 RTCList<RTCString> guestDirList;
371 RTCList<RTCString> guestFileList;
372 char pszPathname[RTPATH_MAX];
373 uint32_t cbPathname = 0;
374 bool fLoop = true;
375 do
376 {
377 uint32_t uNextMsg;
378 uint32_t cNextParms;
379 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false /* fWait */);
380 if (RT_SUCCESS(rc))
381 {
382 switch(uNextMsg)
383 {
384 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
385 {
386 uint32_t fMode = 0;
387 rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
388 pszPathname,
389 sizeof(pszPathname),
390 &cbPathname,
391 &fMode);
392 if (RT_SUCCESS(rc))
393 {
394 char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname);
395 rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
396 if (!guestDirList.contains(pszNewDir))
397 guestDirList.append(pszNewDir);
398 }
399 break;
400 }
401 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
402 {
403 uint32_t cbDataRecv;
404 uint32_t fMode = 0;
405 rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
406 pszPathname,
407 sizeof(pszPathname),
408 &cbPathname,
409 pvTmpData,
410 cbTmpData,
411 &cbDataRecv,
412 &fMode);
413 if (RT_SUCCESS(rc))
414 {
415 char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname);
416 RTFILE hFile;
417 /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
418 * create all sorts of funny races because we don't know if the guest has
419 * modified the file in between the file data send calls. */
420 rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
421 if (RT_SUCCESS(rc))
422 {
423 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
424 if (RT_SUCCESS(rc))
425 {
426 rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
427 /* Valid UNIX mode? */
428 if ( RT_SUCCESS(rc)
429 && (fMode & RTFS_UNIX_MASK))
430 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
431 }
432 RTFileClose(hFile);
433 if (!guestFileList.contains(pszNewFile))
434 guestFileList.append(pszNewFile);
435 }
436 }
437 break;
438 }
439 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
440 {
441 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
442 if (RT_SUCCESS(rc))
443 rc = VERR_CANCELLED;
444 /* Break out of the loop. */
445 }
446 default:
447 fLoop = false;
448 break;
449 }
450 }
451 else
452 {
453 if (rc == VERR_NO_DATA)
454 rc = VINF_SUCCESS;
455 break;
456 }
457
458 } while (fLoop);
459
460 RTMemFree(pvTmpData);
461
462 /* Cleanup on failure or if the user has canceled. */
463 if (RT_FAILURE(rc))
464 {
465 /* Remove any stuff created. */
466 for (size_t i = 0; i < guestFileList.size(); ++i)
467 RTFileDelete(guestFileList.at(i).c_str());
468 for (size_t i = 0; i < guestDirList.size(); ++i)
469 RTDirRemove(guestDirList.at(i).c_str());
470 RTDirRemove(pszDropDir);
471 }
472
473 return rc;
474}
475
476static int vbglR3DnDHGProcessDataMessageInternal(uint32_t uClientId,
477 uint32_t *puScreenId,
478 char *pszFormat,
479 uint32_t cbFormat,
480 uint32_t *pcbFormatRecv,
481 void *pvData,
482 uint32_t cbData,
483 uint32_t *pcbDataRecv)
484{
485 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
486 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
487 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
488 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
489 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
490 AssertReturn(cbData, VERR_INVALID_PARAMETER);
491 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
492
493 DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
494 RT_ZERO(Msg);
495 Msg.hdr.u32ClientID = uClientId;
496 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
497 Msg.hdr.cParms = 5;
498
499 Msg.uScreenId.SetUInt32(0);
500 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
501 Msg.cFormat.SetUInt32(0);
502 Msg.pvData.SetPtr(pvData, cbData);
503 Msg.cData.SetUInt32(0);
504
505 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
506 if (RT_SUCCESS(rc))
507 {
508 rc = Msg.hdr.result;
509 if ( RT_SUCCESS(rc)
510 || rc == VERR_BUFFER_OVERFLOW)
511 {
512 /* Fetch results */
513 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
514 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
515 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
516 /* A little bit paranoia */
517 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
518 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
519 }
520 }
521
522 return rc;
523}
524
525static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t uClientId,
526 void *pvData,
527 uint32_t cbData,
528 uint32_t *pcbDataRecv)
529{
530 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
531 AssertReturn(cbData, VERR_INVALID_PARAMETER);
532 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
533
534 DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
535 RT_ZERO(Msg);
536 Msg.hdr.u32ClientID = uClientId;
537 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
538 Msg.hdr.cParms = 2;
539
540 Msg.pvData.SetPtr(pvData, cbData);
541 Msg.cData.SetUInt32(0);
542
543 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
544 if (RT_SUCCESS(rc))
545 {
546 rc = Msg.hdr.result;
547 if ( RT_SUCCESS(rc)
548 || rc == VERR_BUFFER_OVERFLOW)
549 {
550 /* Fetch results */
551 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
552 /* A little bit paranoia */
553 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
554 }
555 }
556 return rc;
557}
558
559static int vbglR3DnDHGProcessSendDataMessageLoop(uint32_t uClientId,
560 uint32_t *puScreenId,
561 char *pszFormat,
562 uint32_t cbFormat,
563 uint32_t *pcbFormatRecv,
564 void **ppvData,
565 uint32_t cbData,
566 size_t *pcbDataRecv)
567{
568 uint32_t cbDataRecv = 0;
569 int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId,
570 puScreenId,
571 pszFormat,
572 cbFormat,
573 pcbFormatRecv,
574 *ppvData,
575 cbData,
576 &cbDataRecv);
577 uint32_t cbAllDataRecv = cbDataRecv;
578 while (rc == VERR_BUFFER_OVERFLOW)
579 {
580 uint32_t uNextMsg;
581 uint32_t cNextParms;
582 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
583 if (RT_SUCCESS(rc))
584 {
585 switch(uNextMsg)
586 {
587 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
588 {
589 *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData);
590 if (!*ppvData)
591 {
592 rc = VERR_NO_MEMORY;
593 break;
594 }
595 rc = vbglR3DnDHGProcessMoreDataMessageInternal(uClientId,
596 &((char*)*ppvData)[cbAllDataRecv],
597 cbData,
598 &cbDataRecv);
599 cbAllDataRecv += cbDataRecv;
600 break;
601 }
602 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
603 default:
604 {
605 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
606 if (RT_SUCCESS(rc))
607 rc = VERR_CANCELLED;
608 break;
609 }
610 }
611 }
612 }
613 if (RT_SUCCESS(rc))
614 *pcbDataRecv = cbAllDataRecv;
615
616 return rc;
617}
618
619static int vbglR3DnDHGProcessSendDataMessage(uint32_t uClientId,
620 uint32_t *puScreenId,
621 char *pszFormat,
622 uint32_t cbFormat,
623 uint32_t *pcbFormatRecv,
624 void **ppvData,
625 uint32_t cbData,
626 size_t *pcbDataRecv)
627{
628 int rc = vbglR3DnDHGProcessSendDataMessageLoop(uClientId,
629 puScreenId,
630 pszFormat,
631 cbFormat,
632 pcbFormatRecv,
633 ppvData,
634 cbData,
635 pcbDataRecv);
636 if (RT_SUCCESS(rc))
637 {
638 /* Check if this is a uri-event. If so, let VbglR3 do all the actual
639 * data transfer + file /directory creation internally without letting
640 * the caller know. */
641 if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
642 rc = vbglR3DnDHGProcessURIMessages(uClientId,
643 puScreenId,
644 pszFormat,
645 cbFormat,
646 pcbFormatRecv,
647 ppvData,
648 cbData,
649 pcbDataRecv);
650 }
651
652 return rc;
653}
654
655static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t uClientId,
656 uint32_t *puScreenId)
657{
658 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
659
660 DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
661 RT_ZERO(Msg);
662 Msg.hdr.u32ClientID = uClientId;
663 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
664 Msg.hdr.cParms = 1;
665
666 Msg.uScreenId.SetUInt32(0);
667
668 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
669 if (RT_SUCCESS(rc))
670 {
671 rc = Msg.hdr.result;
672 if (RT_SUCCESS(rc))
673 {
674 /* Fetch results */
675 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
676 }
677 }
678
679 return rc;
680}
681
682static int vbglR3DnDGHProcessDroppedMessage(uint32_t uClientId,
683 char *pszFormat,
684 uint32_t cbFormat,
685 uint32_t *pcbFormatRecv,
686 uint32_t *puAction)
687{
688 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
689 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
690 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
691 AssertPtrReturn(puAction, VERR_INVALID_POINTER);
692
693 DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
694 RT_ZERO(Msg);
695 Msg.hdr.u32ClientID = uClientId;
696 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
697 Msg.hdr.cParms = 3;
698
699 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
700 Msg.cFormat.SetUInt32(0);
701 Msg.uAction.SetUInt32(0);
702
703 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
704 if (RT_SUCCESS(rc))
705 {
706 rc = Msg.hdr.result;
707 if (RT_SUCCESS(rc))
708 {
709 /* Fetch results */
710 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
711 rc = Msg.uAction.GetUInt32(puAction); AssertRC(rc);
712 /* A little bit paranoia */
713 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
714 }
715 }
716
717 return rc;
718}
719
720/******************************************************************************
721 * Public functions *
722 ******************************************************************************/
723
724VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
725{
726 AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
727
728 /* Initialize header */
729 VBoxGuestHGCMConnectInfo Info;
730 RT_ZERO(Info.Loc.u);
731 Info.result = VERR_WRONG_ORDER;
732 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */
733 /* Initialize parameter */
734 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
735 int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
736 if (RT_FAILURE(rc)) return rc;
737 /* Do request */
738 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
739 if (RT_SUCCESS(rc))
740 {
741 rc = Info.result;
742 if (RT_SUCCESS(rc))
743 *pu32ClientId = Info.u32ClientID;
744 }
745 return rc;
746}
747
748VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
749{
750 VBoxGuestHGCMDisconnectInfo Info;
751 Info.result = VERR_WRONG_ORDER;
752 Info.u32ClientID = u32ClientId;
753
754 /* Do request */
755 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
756 if (RT_SUCCESS(rc))
757 rc = Info.result;
758
759 return rc;
760}
761
762VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent)
763{
764 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
765
766 uint32_t uMsg = 0;
767 uint32_t uNumParms = 0;
768 const uint32_t ccbFormats = _64K;
769 const uint32_t ccbData = _64K;
770 int rc = vbglR3DnDQueryNextHostMessageType(u32ClientId, &uMsg, &uNumParms,
771 true /* fWait */);
772 if (RT_SUCCESS(rc))
773 {
774 switch(uMsg)
775 {
776 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
777 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
778 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
779 {
780 pEvent->uType = uMsg;
781 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
782 if (!pEvent->pszFormats)
783 rc = VERR_NO_MEMORY;
784
785 if (RT_SUCCESS(rc))
786 rc = vbglR3DnDHGProcessActionMessage(u32ClientId,
787 uMsg,
788 &pEvent->uScreenId,
789 &pEvent->u.a.uXpos,
790 &pEvent->u.a.uYpos,
791 &pEvent->u.a.uDefAction,
792 &pEvent->u.a.uAllActions,
793 pEvent->pszFormats,
794 ccbFormats,
795 &pEvent->cbFormats);
796 break;
797 }
798 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
799 {
800 pEvent->uType = uMsg;
801 rc = vbglR3DnDHGProcessLeaveMessage(u32ClientId);
802 break;
803 }
804 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
805 {
806 pEvent->uType = uMsg;
807 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
808 if (!pEvent->pszFormats)
809 rc = VERR_NO_MEMORY;
810
811 if (RT_SUCCESS(rc))
812 {
813 pEvent->u.b.pvData = RTMemAlloc(ccbData);
814 if (!pEvent->u.b.pvData)
815 {
816 RTMemFree(pEvent->pszFormats);
817 pEvent->pszFormats = NULL;
818 rc = VERR_NO_MEMORY;
819 }
820 }
821
822 if (RT_SUCCESS(rc))
823 rc = vbglR3DnDHGProcessSendDataMessage(u32ClientId,
824 &pEvent->uScreenId,
825 pEvent->pszFormats,
826 ccbFormats,
827 &pEvent->cbFormats,
828 &pEvent->u.b.pvData,
829 ccbData,
830 &pEvent->u.b.cbData);
831 break;
832 }
833 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
834 {
835 pEvent->uType = uMsg;
836 rc = vbglR3DnDHGProcessCancelMessage(u32ClientId);
837 break;
838 }
839#ifdef VBOX_WITH_DRAG_AND_DROP_GH
840 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
841 {
842 pEvent->uType = uMsg;
843 rc = vbglR3DnDGHProcessRequestPendingMessage(u32ClientId,
844 &pEvent->uScreenId);
845 break;
846 }
847 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
848 {
849 pEvent->uType = uMsg;
850 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
851 if (!pEvent->pszFormats)
852 rc = VERR_NO_MEMORY;
853
854 if (RT_SUCCESS(rc))
855 rc = vbglR3DnDGHProcessDroppedMessage(u32ClientId,
856 pEvent->pszFormats,
857 ccbFormats,
858 &pEvent->cbFormats,
859 &pEvent->u.a.uDefAction);
860 break;
861 }
862#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
863 default:
864 AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg),
865 VERR_INVALID_PARAMETER);
866 break;
867 }
868 }
869
870 return rc;
871}
872
873VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction)
874{
875 DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
876 RT_ZERO(Msg);
877 Msg.hdr.result = VERR_WRONG_ORDER;
878 Msg.hdr.u32ClientID = u32ClientId;
879 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
880 Msg.hdr.cParms = 1;
881 /* Initialize parameter */
882 Msg.uAction.SetUInt32(uAction);
883 /* Do request */
884 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
885 if (RT_SUCCESS(rc))
886 rc = Msg.hdr.result;
887
888 return rc;
889}
890
891VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat)
892{
893 AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
894
895 DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
896 RT_ZERO(Msg);
897 Msg.hdr.result = VERR_WRONG_ORDER;
898 Msg.hdr.u32ClientID = u32ClientId;
899 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
900 Msg.hdr.cParms = 1;
901 /* Do request */
902 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
903 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
904 if (RT_SUCCESS(rc))
905 rc = Msg.hdr.result;
906
907 return rc;
908}
909
910VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
911 uint32_t uDefAction, uint32_t uAllActions,
912 const char* pcszFormat)
913{
914 AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
915
916 DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
917 RT_ZERO(Msg);
918 Msg.hdr.result = VERR_WRONG_ORDER;
919 Msg.hdr.u32ClientID = u32ClientId;
920 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
921 Msg.hdr.cParms = 3;
922 /* Initialize parameter */
923 Msg.uDefAction.SetUInt32(uDefAction);
924 Msg.uAllActions.SetUInt32(uAllActions);
925 Msg.pFormat.SetPtr((void*)pcszFormat, static_cast<uint32_t>(strlen(pcszFormat) + 1));
926 /* Do request */
927 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
928 if (RT_SUCCESS(rc))
929 rc = Msg.hdr.result;
930
931 return rc;
932}
933
934VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId, void *pvData, uint32_t cbData)
935{
936 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
937 AssertReturn(cbData, VERR_INVALID_PARAMETER);
938
939 /* Todo: URI support. Currently only data is send over to the host. For URI
940 * support basically the same as in the H->G case (see
941 * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
942 * 1. Parse the urilist
943 * 2. Recursively send "create dir" and "transfer file" msg to the host
944 * 3. Patch the urilist by removing all base dirnames
945 * 4. On the host all needs to received and the urilist patched afterwards
946 * to point to the new location
947 */
948
949 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
950 RT_ZERO(Msg);
951 Msg.hdr.result = VERR_WRONG_ORDER;
952 Msg.hdr.u32ClientID = u32ClientId;
953 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
954 Msg.hdr.cParms = 2;
955 Msg.uSize.SetUInt32(cbData);
956 int rc = VINF_SUCCESS;
957 uint32_t cbMax = _1M;
958 uint32_t cbSend = 0;
959 while(cbSend < cbData)
960 {
961 /* Initialize parameter */
962 uint32_t cbToSend = RT_MIN(cbData - cbSend, cbMax);
963 Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSend, cbToSend);
964 /* Do request */
965 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
966 if (RT_SUCCESS(rc))
967 {
968 rc = Msg.hdr.result;
969 /* Did the host cancel the event? */
970 if (rc == VERR_CANCELLED)
971 break;
972 }
973 else
974 break;
975 cbSend += cbToSend;
976// RTThreadSleep(500);
977 }
978
979 return rc;
980}
981
982VBGLR3DECL(int) VbglR3DnDGHErrorEvent(uint32_t u32ClientId, int rcOp)
983{
984 DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
985 RT_ZERO(Msg);
986 Msg.hdr.result = VERR_WRONG_ORDER;
987 Msg.hdr.u32ClientID = u32ClientId;
988 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
989 Msg.hdr.cParms = 1;
990 /* Initialize parameter */
991 Msg.uRC.SetUInt32(rcOp);
992 /* Do request */
993 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
994 if (RT_SUCCESS(rc))
995 rc = Msg.hdr.result;
996
997 return rc;
998}
Note: See TracBrowser for help on using the repository browser.

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