VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp@ 55772

Last change on this file since 55772 was 53434, checked in by vboxsync, 10 years ago

Additions/common and x11: improve error handling related to mode hint passing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 36.0 KB
Line 
1/* $Id: VBoxGuestR3LibGuestProp.cpp 53434 2014-12-03 15:20:59Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, guest properties.
4 */
5
6/*
7 * Copyright (C) 2007-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#if defined(VBOX_VBGLR3_XFREE86) || defined(VBOX_VBGLR3_XORG)
28# define VBOX_VBGLR3_XSERVER
29#endif
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/string.h>
35#ifndef VBOX_VBGLR3_XSERVER
36# include <iprt/cpp/mem.h>
37#endif
38#include <iprt/assert.h>
39#include <iprt/stdarg.h>
40#include <VBox/log.h>
41#include <VBox/HostServices/GuestPropertySvc.h>
42
43#include "VBGLR3Internal.h"
44
45#ifdef VBOX_VBGLR3_XFREE86
46/* Rather than try to resolve all the header file conflicts, I will just
47 prototype what we need here. */
48extern "C" char* xf86strcpy(char*,const char*);
49# undef strcpy
50# define strcpy xf86strcpy
51extern "C" void* xf86memchr(const void*,int,xf86size_t);
52# undef memchr
53# define memchr xf86memchr
54extern "C" void* xf86memset(const void*,int,xf86size_t);
55# undef memset
56# define memset xf86memset
57
58#endif /* VBOX_VBGLR3_XFREE86 */
59
60#ifdef VBOX_VBGLR3_XSERVER
61
62# undef RTSTrEnd
63# define RTStrEnd xf86RTStrEnd
64
65DECLINLINE(char const *) RTStrEnd(char const *pszString, size_t cchMax)
66{
67 /* Avoid potential issues with memchr seen in glibc.
68 * See sysdeps/x86_64/memchr.S in glibc versions older than 2.11 */
69 while (cchMax > RTSTR_MEMCHR_MAX)
70 {
71 char const *pszRet = (char const *)memchr(pszString, '\0', RTSTR_MEMCHR_MAX);
72 if (RT_LIKELY(pszRet))
73 return pszRet;
74 pszString += RTSTR_MEMCHR_MAX;
75 cchMax -= RTSTR_MEMCHR_MAX;
76 }
77 return (char const *)memchr(pszString, '\0', cchMax);
78}
79
80DECLINLINE(char *) RTStrEnd(char *pszString, size_t cchMax)
81{
82 /* Avoid potential issues with memchr seen in glibc.
83 * See sysdeps/x86_64/memchr.S in glibc versions older than 2.11 */
84 while (cchMax > RTSTR_MEMCHR_MAX)
85 {
86 char *pszRet = (char *)memchr(pszString, '\0', RTSTR_MEMCHR_MAX);
87 if (RT_LIKELY(pszRet))
88 return pszRet;
89 pszString += RTSTR_MEMCHR_MAX;
90 cchMax -= RTSTR_MEMCHR_MAX;
91 }
92 return (char *)memchr(pszString, '\0', cchMax);
93}
94
95#endif /* VBOX_VBGLR3_XSERVER */
96
97/*******************************************************************************
98* Structures and Typedefs *
99*******************************************************************************/
100/**
101 * Structure containing information needed to enumerate through guest
102 * properties.
103 *
104 * @remarks typedef in VBoxGuestLib.h.
105 */
106struct VBGLR3GUESTPROPENUM
107{
108 /** @todo add a magic and validate the handle. */
109 /** The buffer containing the raw enumeration data */
110 char *pchBuf;
111 /** The end of the buffer */
112 char *pchBufEnd;
113 /** Pointer to the next entry to enumerate inside the buffer */
114 char *pchNext;
115};
116
117using namespace guestProp;
118
119/**
120 * Connects to the guest property service.
121 *
122 * @returns VBox status code
123 * @returns VERR_NOT_SUPPORTED if guest properties are not available on the host.
124 * @param pu32ClientId Where to put the client id on success. The client id
125 * must be passed to all the other calls to the service.
126 */
127VBGLR3DECL(int) VbglR3GuestPropConnect(uint32_t *pu32ClientId)
128{
129 VBoxGuestHGCMConnectInfo Info;
130 Info.result = VERR_WRONG_ORDER;
131 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
132 RT_ZERO(Info.Loc.u);
133 strcpy(Info.Loc.u.host.achName, "VBoxGuestPropSvc");
134 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */
135
136 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
137 if (RT_SUCCESS(rc))
138 {
139 rc = Info.result;
140 if (RT_SUCCESS(rc))
141 *pu32ClientId = Info.u32ClientID;
142 if (rc == VERR_NOT_IMPLEMENTED || rc == VERR_HGCM_SERVICE_NOT_FOUND)
143 rc = VERR_NOT_SUPPORTED;
144 }
145 return rc;
146}
147
148
149/**
150 * Disconnect from the guest property service.
151 *
152 * @returns VBox status code.
153 * @param u32ClientId The client id returned by VbglR3InfoSvcConnect().
154 */
155VBGLR3DECL(int) VbglR3GuestPropDisconnect(uint32_t u32ClientId)
156{
157 VBoxGuestHGCMDisconnectInfo Info;
158 Info.result = VERR_WRONG_ORDER;
159 Info.u32ClientID = u32ClientId;
160
161 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
162 if (RT_SUCCESS(rc))
163 rc = Info.result;
164 return rc;
165}
166
167
168/**
169 * Write a property value.
170 *
171 * @returns VBox status code.
172 * @param u32ClientId The client id returned by VbglR3InvsSvcConnect().
173 * @param pszName The property to save to. Utf8
174 * @param pszValue The value to store. Utf8. If this is NULL then
175 * the property will be removed.
176 * @param pszFlags The flags for the property
177 */
178VBGLR3DECL(int) VbglR3GuestPropWrite(uint32_t u32ClientId, const char *pszName, const char *pszValue, const char *pszFlags)
179{
180 int rc;
181
182 if (pszValue != NULL)
183 {
184 SetProperty Msg;
185
186 Msg.hdr.result = VERR_WRONG_ORDER;
187 Msg.hdr.u32ClientID = u32ClientId;
188 Msg.hdr.u32Function = SET_PROP_VALUE;
189 Msg.hdr.cParms = 3;
190 VbglHGCMParmPtrSetString(&Msg.name, pszName);
191 VbglHGCMParmPtrSetString(&Msg.value, pszValue);
192 VbglHGCMParmPtrSetString(&Msg.flags, pszFlags);
193 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
194 if (RT_SUCCESS(rc))
195 rc = Msg.hdr.result;
196 }
197 else
198 {
199 DelProperty Msg;
200
201 Msg.hdr.result = VERR_WRONG_ORDER;
202 Msg.hdr.u32ClientID = u32ClientId;
203 Msg.hdr.u32Function = DEL_PROP;
204 Msg.hdr.cParms = 1;
205 VbglHGCMParmPtrSetString(&Msg.name, pszName);
206 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
207 if (RT_SUCCESS(rc))
208 rc = Msg.hdr.result;
209 }
210 return rc;
211}
212
213
214/**
215 * Write a property value.
216 *
217 * @returns VBox status code.
218 *
219 * @param u32ClientId The client id returned by VbglR3InvsSvcConnect().
220 * @param pszName The property to save to. Must be valid UTF-8.
221 * @param pszValue The value to store. Must be valid UTF-8.
222 * If this is NULL then the property will be removed.
223 *
224 * @note if the property already exists and pszValue is not NULL then the
225 * property's flags field will be left unchanged
226 */
227VBGLR3DECL(int) VbglR3GuestPropWriteValue(uint32_t u32ClientId, const char *pszName, const char *pszValue)
228{
229 int rc;
230
231 if (pszValue != NULL)
232 {
233 SetPropertyValue Msg;
234
235 Msg.hdr.result = VERR_WRONG_ORDER;
236 Msg.hdr.u32ClientID = u32ClientId;
237 Msg.hdr.u32Function = SET_PROP_VALUE;
238 Msg.hdr.cParms = 2;
239 VbglHGCMParmPtrSetString(&Msg.name, pszName);
240 VbglHGCMParmPtrSetString(&Msg.value, pszValue);
241 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
242 if (RT_SUCCESS(rc))
243 rc = Msg.hdr.result;
244 }
245 else
246 {
247 DelProperty Msg;
248
249 Msg.hdr.result = VERR_WRONG_ORDER;
250 Msg.hdr.u32ClientID = u32ClientId;
251 Msg.hdr.u32Function = DEL_PROP;
252 Msg.hdr.cParms = 1;
253 VbglHGCMParmPtrSetString(&Msg.name, pszName);
254 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
255 if (RT_SUCCESS(rc))
256 rc = Msg.hdr.result;
257 }
258 return rc;
259}
260
261#ifndef VBOX_VBGLR3_XSERVER
262/**
263 * Write a property value where the value is formatted in RTStrPrintfV fashion.
264 *
265 * @returns The same as VbglR3GuestPropWriteValue with the addition of VERR_NO_STR_MEMORY.
266 *
267 * @param u32ClientId The client ID returned by VbglR3InvsSvcConnect().
268 * @param pszName The property to save to. Must be valid UTF-8.
269 * @param pszValueFormat The value format. This must be valid UTF-8 when fully formatted.
270 * @param va The format arguments.
271 */
272VBGLR3DECL(int) VbglR3GuestPropWriteValueV(uint32_t u32ClientId, const char *pszName, const char *pszValueFormat, va_list va)
273{
274 /*
275 * Format the value and pass it on to the setter.
276 */
277 int rc = VERR_NO_STR_MEMORY;
278 char *pszValue;
279 if (RTStrAPrintfV(&pszValue, pszValueFormat, va) >= 0)
280 {
281 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, pszValue);
282 RTStrFree(pszValue);
283 }
284 return rc;
285}
286
287
288/**
289 * Write a property value where the value is formatted in RTStrPrintf fashion.
290 *
291 * @returns The same as VbglR3GuestPropWriteValue with the addition of VERR_NO_STR_MEMORY.
292 *
293 * @param u32ClientId The client ID returned by VbglR3InvsSvcConnect().
294 * @param pszName The property to save to. Must be valid UTF-8.
295 * @param pszValueFormat The value format. This must be valid UTF-8 when fully formatted.
296 * @param ... The format arguments.
297 */
298VBGLR3DECL(int) VbglR3GuestPropWriteValueF(uint32_t u32ClientId, const char *pszName, const char *pszValueFormat, ...)
299{
300 va_list va;
301 va_start(va, pszValueFormat);
302 int rc = VbglR3GuestPropWriteValueV(u32ClientId, pszName, pszValueFormat, va);
303 va_end(va);
304 return rc;
305}
306#endif /* VBOX_VBGLR3_XSERVER */
307
308/**
309 * Retrieve a property.
310 *
311 * @returns VBox status code.
312 * @retval VINF_SUCCESS on success, pszValue, pu64Timestamp and pszFlags
313 * containing valid data.
314 * @retval VERR_BUFFER_OVERFLOW if the scratch buffer @a pcBuf is not large
315 * enough. In this case the size needed will be placed in
316 * @a pcbBufActual if it is not NULL.
317 * @retval VERR_NOT_FOUND if the key wasn't found.
318 *
319 * @param u32ClientId The client id returned by VbglR3GuestPropConnect().
320 * @param pszName The value to read. Utf8
321 * @param pvBuf A scratch buffer to store the data retrieved into.
322 * The returned data is only valid for it's lifetime.
323 * @a ppszValue will point to the start of this buffer.
324 * @param cbBuf The size of @a pcBuf
325 * @param ppszValue Where to store the pointer to the value retrieved.
326 * Optional.
327 * @param pu64Timestamp Where to store the timestamp. Optional.
328 * @param pszFlags Where to store the pointer to the flags. Optional.
329 * @param pcbBufActual If @a pcBuf is not large enough, the size needed.
330 * Optional.
331 */
332VBGLR3DECL(int) VbglR3GuestPropRead(uint32_t u32ClientId, const char *pszName,
333 void *pvBuf, uint32_t cbBuf,
334 char **ppszValue, uint64_t *pu64Timestamp,
335 char **ppszFlags,
336 uint32_t *pcbBufActual)
337{
338 /*
339 * Create the GET_PROP message and call the host.
340 */
341 GetProperty Msg;
342
343 Msg.hdr.result = VERR_WRONG_ORDER;
344 Msg.hdr.u32ClientID = u32ClientId;
345 Msg.hdr.u32Function = GET_PROP;
346 Msg.hdr.cParms = 4;
347 VbglHGCMParmPtrSetString(&Msg.name, pszName);
348 VbglHGCMParmPtrSet(&Msg.buffer, pvBuf, cbBuf);
349 VbglHGCMParmUInt64Set(&Msg.timestamp, 0);
350 VbglHGCMParmUInt32Set(&Msg.size, 0);
351
352 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
353 if (RT_SUCCESS(rc))
354 rc = Msg.hdr.result;
355
356 /*
357 * The cbBufActual parameter is also returned on overflow so the call can
358 * adjust his/her buffer.
359 */
360 if ( rc == VERR_BUFFER_OVERFLOW
361 || pcbBufActual != NULL)
362 {
363 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, pcbBufActual);
364 AssertRCReturn(rc2, RT_FAILURE(rc) ? rc : rc2);
365 }
366 if (RT_FAILURE(rc))
367 return rc;
368
369 /*
370 * Buffer layout: Value\0Flags\0.
371 *
372 * If the caller cares about any of these strings, make sure things are
373 * properly terminated (paranoia).
374 */
375 if ( RT_SUCCESS(rc)
376 && (ppszValue != NULL || ppszFlags != NULL))
377 {
378 /* Validate / skip 'Name'. */
379 char *pszFlags = RTStrEnd((char *)pvBuf, cbBuf) + 1;
380 AssertPtrReturn(pszFlags, VERR_TOO_MUCH_DATA);
381 if (ppszValue)
382 *ppszValue = (char *)pvBuf;
383
384 if (ppszFlags)
385 {
386 /* Validate 'Flags'. */
387 char *pszEos = RTStrEnd(pszFlags, cbBuf - (pszFlags - (char *)pvBuf));
388 AssertPtrReturn(pszEos, VERR_TOO_MUCH_DATA);
389 *ppszFlags = pszFlags;
390 }
391 }
392
393 /* And the timestamp, if requested. */
394 if (pu64Timestamp != NULL)
395 {
396 rc = VbglHGCMParmUInt64Get(&Msg.timestamp, pu64Timestamp);
397 AssertRCReturn(rc, rc);
398 }
399
400 return VINF_SUCCESS;
401}
402
403#ifndef VBOX_VBGLR3_XSERVER
404/**
405 * Retrieve a property value, allocating space for it.
406 *
407 * @returns VBox status code.
408 * @retval VINF_SUCCESS on success, *ppszValue containing valid data.
409 * @retval VERR_NOT_FOUND if the key wasn't found.
410 * @retval VERR_TOO_MUCH_DATA if we were unable to determine the right size
411 * to allocate for the buffer. This can happen as the result of a
412 * race between our allocating space and the host changing the
413 * property value.
414 *
415 * @param u32ClientId The client id returned by VbglR3GuestPropConnect().
416 * @param pszName The value to read. Must be valid UTF-8.
417 * @param ppszValue Where to store the pointer to the value returned.
418 * This is always set to NULL or to the result, even
419 * on failure.
420 */
421VBGLR3DECL(int) VbglR3GuestPropReadValueAlloc(uint32_t u32ClientId,
422 const char *pszName,
423 char **ppszValue)
424{
425 /*
426 * Quick input validation.
427 */
428 AssertPtr(ppszValue);
429 *ppszValue = NULL;
430 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
431
432 /*
433 * There is a race here between our reading the property size and the
434 * host changing the value before we read it. Try up to ten times and
435 * report the problem if that fails.
436 */
437 char *pszValue = NULL;
438 void *pvBuf = NULL;
439 uint32_t cchBuf = MAX_VALUE_LEN;
440 int rc = VERR_BUFFER_OVERFLOW;
441 for (unsigned i = 0; i < 10 && rc == VERR_BUFFER_OVERFLOW; ++i)
442 {
443 /* We leave a bit of space here in case the maximum value is raised. */
444 cchBuf += 1024;
445 void *pvTmpBuf = RTMemRealloc(pvBuf, cchBuf);
446 if (pvTmpBuf)
447 {
448 pvBuf = pvTmpBuf;
449 rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cchBuf,
450 &pszValue, NULL, NULL, &cchBuf);
451 }
452 else
453 rc = VERR_NO_MEMORY;
454 }
455 if (RT_SUCCESS(rc))
456 {
457 Assert(pszValue == (char *)pvBuf);
458 *ppszValue = pszValue;
459 }
460 else
461 {
462 RTMemFree(pvBuf);
463 if (rc == VERR_BUFFER_OVERFLOW)
464 /* VERR_BUFFER_OVERFLOW has a different meaning here as a
465 * return code, but we need to report the race. */
466 rc = VERR_TOO_MUCH_DATA;
467 }
468
469 return rc;
470}
471
472
473/**
474 * Free the memory used by VbglR3GuestPropReadValueAlloc for returning a
475 * value.
476 *
477 * @param pszValue the memory to be freed. NULL pointers will be ignored.
478 */
479VBGLR3DECL(void) VbglR3GuestPropReadValueFree(char *pszValue)
480{
481 RTMemFree(pszValue);
482}
483#endif /* VBOX_VBGLR3_XSERVER */
484
485/**
486 * Retrieve a property value, using a user-provided buffer to store it.
487 *
488 * @returns VBox status code.
489 * @retval VINF_SUCCESS on success, pszValue containing valid data.
490 * @retval VERR_BUFFER_OVERFLOW and the size needed in pcchValueActual if the
491 * buffer provided was too small
492 * @retval VERR_NOT_FOUND if the key wasn't found.
493 *
494 * @note There is a race here between obtaining the size of the buffer
495 * needed to hold the value and the value being updated.
496 *
497 * @param u32ClientId The client id returned by VbglR3GuestPropConnect().
498 * @param pszName The value to read. Utf8
499 * @param pszValue Where to store the value retrieved.
500 * @param cchValue The size of the buffer pointed to by @a pszValue
501 * @param pcchValueActual Where to store the size of the buffer needed if
502 * the buffer supplied is too small. Optional.
503 */
504VBGLR3DECL(int) VbglR3GuestPropReadValue(uint32_t u32ClientId, const char *pszName,
505 char *pszValue, uint32_t cchValue,
506 uint32_t *pcchValueActual)
507{
508 void *pvBuf = pszValue;
509 uint32_t cchValueActual;
510 int rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cchValue,
511 &pszValue, NULL, NULL, &cchValueActual);
512 if (pcchValueActual != NULL)
513 *pcchValueActual = cchValueActual;
514 return rc;
515}
516
517
518#ifndef VBOX_VBGLR3_XSERVER
519/**
520 * Raw API for enumerating guest properties which match a given pattern.
521 *
522 * @returns VBox status code.
523 * @retval VINF_SUCCESS on success and pcBuf points to a packed array
524 * of the form <name>, <value>, <timestamp string>, <flags>,
525 * terminated by four empty strings. pcbBufActual will contain the
526 * total size of the array.
527 * @retval VERR_BUFFER_OVERFLOW if the buffer provided was too small. In
528 * this case pcbBufActual will contain the size of the buffer needed.
529 * @returns IPRT error code in other cases, and pchBufActual is undefined.
530 *
531 * @param u32ClientId The client ID returned by VbglR3GuestPropConnect
532 * @param paszPatterns A packed array of zero terminated strings, terminated
533 * by an empty string.
534 * @param pcBuf The buffer to store the results to.
535 * @param cbBuf The size of the buffer
536 * @param pcbBufActual Where to store the size of the returned data on
537 * success or the buffer size needed if @a pcBuf is too
538 * small.
539 */
540VBGLR3DECL(int) VbglR3GuestPropEnumRaw(uint32_t u32ClientId,
541 const char *pszzPatterns,
542 char *pcBuf,
543 uint32_t cbBuf,
544 uint32_t *pcbBufActual)
545{
546 EnumProperties Msg;
547
548 Msg.hdr.result = VERR_WRONG_ORDER;
549 Msg.hdr.u32ClientID = u32ClientId;
550 Msg.hdr.u32Function = ENUM_PROPS;
551 Msg.hdr.cParms = 3;
552 /* Get the length of the patterns array... */
553 size_t cchPatterns = 0;
554 for (size_t cchCurrent = strlen(pszzPatterns); cchCurrent != 0;
555 cchCurrent = strlen(pszzPatterns + cchPatterns))
556 cchPatterns += cchCurrent + 1;
557 /* ...including the terminator. */
558 ++cchPatterns;
559 VbglHGCMParmPtrSet(&Msg.patterns, (char *)pszzPatterns, (uint32_t)cchPatterns);
560 VbglHGCMParmPtrSet(&Msg.strings, pcBuf, cbBuf);
561 VbglHGCMParmUInt32Set(&Msg.size, 0);
562
563 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
564 if (RT_SUCCESS(rc))
565 rc = Msg.hdr.result;
566 if ( pcbBufActual
567 && ( RT_SUCCESS(rc)
568 || rc == VERR_BUFFER_OVERFLOW))
569 {
570 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, pcbBufActual);
571 if (RT_FAILURE(rc2))
572 rc = rc2;
573 }
574 return rc;
575}
576
577
578/**
579 * Start enumerating guest properties which match a given pattern.
580 * This function creates a handle which can be used to continue enumerating.
581 *
582 * @returns VBox status code.
583 * @retval VINF_SUCCESS on success, *ppHandle points to a handle for continuing
584 * the enumeration and *ppszName, *ppszValue, *pu64Timestamp and
585 * *ppszFlags are set.
586 * @retval VERR_TOO_MUCH_DATA if it was not possible to determine the amount
587 * of local space needed to store all the enumeration data. This is
588 * due to a race between allocating space and the host adding new
589 * data, so retrying may help here. Other parameters are left
590 * uninitialised
591 *
592 * @param u32ClientId The client id returned by VbglR3InfoSvcConnect().
593 * @param papszPatterns The patterns against which the properties are
594 * matched. Pass NULL if everything should be matched.
595 * @param cPatterns The number of patterns in @a papszPatterns. 0 means
596 * match everything.
597 * @param ppHandle where the handle for continued enumeration is stored
598 * on success. This must be freed with
599 * VbglR3GuestPropEnumFree when it is no longer needed.
600 * @param ppszName Where to store the next property name. This will be
601 * set to NULL if there are no more properties to
602 * enumerate. This pointer should not be freed. Optional.
603 * @param ppszValue Where to store the next property value. This will be
604 * set to NULL if there are no more properties to
605 * enumerate. This pointer should not be freed. Optional.
606 * @param pu64Timestamp Where to store the next property timestamp. This
607 * will be set to zero if there are no more properties
608 * to enumerate. Optional.
609 * @param ppszFlags Where to store the next property flags. This will be
610 * set to NULL if there are no more properties to
611 * enumerate. This pointer should not be freed. Optional.
612 *
613 * @remarks While all output parameters are optional, you need at least one to
614 * figure out when to stop.
615 */
616VBGLR3DECL(int) VbglR3GuestPropEnum(uint32_t u32ClientId,
617 char const * const *papszPatterns,
618 uint32_t cPatterns,
619 PVBGLR3GUESTPROPENUM *ppHandle,
620 char const **ppszName,
621 char const **ppszValue,
622 uint64_t *pu64Timestamp,
623 char const **ppszFlags)
624{
625 /* Create the handle. */
626 RTCMemAutoPtr<VBGLR3GUESTPROPENUM, VbglR3GuestPropEnumFree> Handle;
627 Handle = (PVBGLR3GUESTPROPENUM)RTMemAllocZ(sizeof(VBGLR3GUESTPROPENUM));
628 if (!Handle)
629 return VERR_NO_MEMORY;
630
631 /* Get the length of the pattern string, including the final terminator. */
632 size_t cchPatterns = 1;
633 for (uint32_t i = 0; i < cPatterns; ++i)
634 cchPatterns += strlen(papszPatterns[i]) + 1;
635
636 /* Pack the pattern array */
637 RTCMemAutoPtr<char> Patterns;
638 Patterns = (char *)RTMemAlloc(cchPatterns);
639 size_t off = 0;
640 for (uint32_t i = 0; i < cPatterns; ++i)
641 {
642 size_t cb = strlen(papszPatterns[i]) + 1;
643 memcpy(&Patterns[off], papszPatterns[i], cb);
644 off += cb;
645 }
646 Patterns[off] = '\0';
647
648 /* Randomly chosen initial size for the buffer to hold the enumeration
649 * information. */
650 uint32_t cchBuf = 4096;
651 RTCMemAutoPtr<char> Buf;
652
653 /* In reading the guest property data we are racing against the host
654 * adding more of it, so loop a few times and retry on overflow. */
655 int rc = VINF_SUCCESS;
656 for (int i = 0; i < 10; ++i)
657 {
658 if (!Buf.realloc(cchBuf))
659 {
660 rc = VERR_NO_MEMORY;
661 break;
662 }
663 rc = VbglR3GuestPropEnumRaw(u32ClientId, Patterns.get(),
664 Buf.get(), cchBuf, &cchBuf);
665 if (rc != VERR_BUFFER_OVERFLOW)
666 break;
667 cchBuf += 4096; /* Just to increase our chances */
668 }
669 if (RT_SUCCESS(rc))
670 {
671 /*
672 * Transfer ownership of the buffer to the handle structure and
673 * call VbglR3GuestPropEnumNext to retrieve the first entry.
674 */
675 Handle->pchNext = Handle->pchBuf = Buf.release();
676 Handle->pchBufEnd = Handle->pchBuf + cchBuf;
677
678 const char *pszNameTmp;
679 if (!ppszName)
680 ppszName = &pszNameTmp;
681 rc = VbglR3GuestPropEnumNext(Handle.get(), ppszName, ppszValue,
682 pu64Timestamp, ppszFlags);
683 if (RT_SUCCESS(rc))
684 *ppHandle = Handle.release();
685 }
686 else if (rc == VERR_BUFFER_OVERFLOW)
687 rc = VERR_TOO_MUCH_DATA;
688 return rc;
689}
690
691
692/**
693 * Get the next guest property.
694 *
695 * See @a VbglR3GuestPropEnum.
696 *
697 * @returns VBox status code.
698 *
699 * @param pHandle Handle obtained from @a VbglR3GuestPropEnum.
700 * @param ppszName Where to store the next property name. This will be
701 * set to NULL if there are no more properties to
702 * enumerate. This pointer should not be freed. Optional.
703 * @param ppszValue Where to store the next property value. This will be
704 * set to NULL if there are no more properties to
705 * enumerate. This pointer should not be freed. Optional.
706 * @param pu64Timestamp Where to store the next property timestamp. This
707 * will be set to zero if there are no more properties
708 * to enumerate. Optional.
709 * @param ppszFlags Where to store the next property flags. This will be
710 * set to NULL if there are no more properties to
711 * enumerate. This pointer should not be freed. Optional.
712 *
713 * @remarks While all output parameters are optional, you need at least one to
714 * figure out when to stop.
715 */
716VBGLR3DECL(int) VbglR3GuestPropEnumNext(PVBGLR3GUESTPROPENUM pHandle,
717 char const **ppszName,
718 char const **ppszValue,
719 uint64_t *pu64Timestamp,
720 char const **ppszFlags)
721{
722 /*
723 * The VBGLR3GUESTPROPENUM structure contains a buffer containing the raw
724 * properties data and a pointer into the buffer which tracks how far we
725 * have parsed so far. The buffer contains packed strings in groups of
726 * four - name, value, timestamp (as a decimal string) and flags. It is
727 * terminated by four empty strings. We can rely on this layout unless
728 * the caller has been poking about in the structure internals, in which
729 * case they must take responsibility for the results.
730 *
731 * Layout:
732 * Name\0Value\0Timestamp\0Flags\0
733 */
734 char *pchNext = pHandle->pchNext; /* The cursor. */
735 char *pchEnd = pHandle->pchBufEnd; /* End of buffer, for size calculations. */
736
737 char *pszName = pchNext;
738 char *pszValue = pchNext = RTStrEnd(pchNext, pchEnd - pchNext) + 1;
739 AssertPtrReturn(pchNext, VERR_PARSE_ERROR); /* 0x1 is also an invalid pointer :) */
740
741 char *pszTimestamp = pchNext = RTStrEnd(pchNext, pchEnd - pchNext) + 1;
742 AssertPtrReturn(pchNext, VERR_PARSE_ERROR);
743
744 char *pszFlags = pchNext = RTStrEnd(pchNext, pchEnd - pchNext) + 1;
745 AssertPtrReturn(pchNext, VERR_PARSE_ERROR);
746
747 /*
748 * Don't move the index pointer if we found the terminating "\0\0\0\0" entry.
749 * Don't try convert the timestamp either.
750 */
751 uint64_t u64Timestamp;
752 if (*pszName != '\0')
753 {
754 pchNext = RTStrEnd(pchNext, pchEnd - pchNext) + 1;
755 AssertPtrReturn(pchNext, VERR_PARSE_ERROR);
756
757 /* Convert the timestamp string into a number. */
758 int rc = RTStrToUInt64Full(pszTimestamp, 0, &u64Timestamp);
759 AssertRCSuccessReturn(rc, VERR_PARSE_ERROR);
760
761 pHandle->pchNext = pchNext;
762 AssertPtr(pchNext);
763 }
764 else
765 {
766 u64Timestamp = 0;
767 AssertMsgReturn(!*pszValue && !*pszTimestamp && !*pszFlags,
768 ("'%s' '%s' '%s'\n", pszValue, pszTimestamp, pszFlags),
769 VERR_PARSE_ERROR);
770 }
771
772 /*
773 * Everything is fine, set the return values.
774 */
775 if (ppszName)
776 *ppszName = *pszName != '\0' ? pszName : NULL;
777 if (ppszValue)
778 *ppszValue = *pszValue != '\0' ? pszValue : NULL;
779 if (pu64Timestamp)
780 *pu64Timestamp = u64Timestamp;
781 if (ppszFlags)
782 *ppszFlags = *pszFlags != '\0' ? pszFlags : NULL;
783 return VINF_SUCCESS;
784}
785
786
787/**
788 * Free an enumeration handle returned by @a VbglR3GuestPropEnum.
789 * @param pHandle the handle to free
790 */
791VBGLR3DECL(void) VbglR3GuestPropEnumFree(PVBGLR3GUESTPROPENUM pHandle)
792{
793 if (!pHandle)
794 return;
795 RTMemFree(pHandle->pchBuf);
796 RTMemFree(pHandle);
797}
798
799
800/**
801 * Deletes a guest property.
802 *
803 * @returns VBox status code.
804 * @param u32ClientId The client id returned by VbglR3InvsSvcConnect().
805 * @param pszName The property to delete. Utf8
806 */
807VBGLR3DECL(int) VbglR3GuestPropDelete(uint32_t u32ClientId, const char *pszName)
808{
809 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
810
811 DelProperty Msg;
812
813 Msg.hdr.result = VERR_WRONG_ORDER;
814 Msg.hdr.u32ClientID = u32ClientId;
815 Msg.hdr.u32Function = DEL_PROP;
816 Msg.hdr.cParms = 1;
817 VbglHGCMParmPtrSetString(&Msg.name, pszName);
818 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
819 if (RT_SUCCESS(rc))
820 rc = Msg.hdr.result;
821
822 return rc;
823}
824
825
826/**
827 * Deletes a set of keys.
828 *
829 * The set is specified in the same way as for VbglR3GuestPropEnum.
830 *
831 * @returns VBox status code. Stops on first failure.
832 * See also VbglR3GuestPropEnum.
833 *
834 * @param u32ClientId The client id returned by VbglR3InfoSvcConnect().
835 * @param papszPatterns The patterns against which the properties are
836 * matched. Pass NULL if everything should be matched.
837 * @param cPatterns The number of patterns in @a papszPatterns. 0 means
838 * match everything.
839 */
840VBGLR3DECL(int) VbglR3GuestPropDelSet(uint32_t u32ClientId,
841 const char * const *papszPatterns,
842 uint32_t cPatterns)
843{
844 PVBGLR3GUESTPROPENUM pHandle;
845 char const *pszName, *pszValue, *pszFlags;
846 uint64_t pu64Timestamp;
847 int rc = VbglR3GuestPropEnum(u32ClientId,
848 (char **)papszPatterns, /** @todo fix this cast. */
849 cPatterns,
850 &pHandle,
851 &pszName,
852 &pszValue,
853 &pu64Timestamp,
854 &pszFlags);
855
856 while (RT_SUCCESS(rc) && pszName)
857 {
858 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, NULL);
859 if (RT_FAILURE(rc))
860 break;
861
862 rc = VbglR3GuestPropEnumNext(pHandle,
863 &pszName,
864 &pszValue,
865 &pu64Timestamp,
866 &pszFlags);
867 }
868
869 VbglR3GuestPropEnumFree(pHandle);
870 return rc;
871}
872
873
874/**
875 * Wait for notification of changes to a guest property. If this is called in
876 * a loop, the timestamp of the last notification seen can be passed as a
877 * parameter to be sure that no notifications are missed.
878 *
879 * @returns VBox status code.
880 * @retval VINF_SUCCESS on success, @a ppszName, @a ppszValue,
881 * @a pu64Timestamp and @a ppszFlags containing valid data.
882 * @retval VINF_NOT_FOUND if no previous notification could be found with the
883 * timestamp supplied. This will normally mean that a large number
884 * of notifications occurred in between.
885 * @retval VERR_BUFFER_OVERFLOW if the scratch buffer @a pvBuf is not large
886 * enough. In this case the size needed will be placed in
887 * @a pcbBufActual if it is not NULL.
888 * @retval VERR_TIMEOUT if a timeout occurred before a notification was seen.
889 *
890 * @param u32ClientId The client id returned by VbglR3GuestPropConnect().
891 * @param pszPatterns The patterns that the property names must matchfor
892 * the change to be reported.
893 * @param pvBuf A scratch buffer to store the data retrieved into.
894 * The returned data is only valid for it's lifetime.
895 * @a ppszValue will point to the start of this buffer.
896 * @param cbBuf The size of @a pvBuf
897 * @param u64Timestamp The timestamp of the last event seen. Pass zero
898 * to wait for the next event.
899 * @param cMillies Timeout in milliseconds. Use RT_INDEFINITE_WAIT
900 * to wait indefinitely.
901 * @param ppszName Where to store the pointer to the name retrieved.
902 * Optional.
903 * @param ppszValue Where to store the pointer to the value retrieved.
904 * Optional.
905 * @param pu64Timestamp Where to store the timestamp. Optional.
906 * @param ppszFlags Where to store the pointer to the flags. Optional.
907 * @param pcbBufActual If @a pcBuf is not large enough, the size needed.
908 * Optional.
909 */
910VBGLR3DECL(int) VbglR3GuestPropWait(uint32_t u32ClientId,
911 const char *pszPatterns,
912 void *pvBuf, uint32_t cbBuf,
913 uint64_t u64Timestamp, uint32_t cMillies,
914 char ** ppszName, char **ppszValue,
915 uint64_t *pu64Timestamp, char **ppszFlags,
916 uint32_t *pcbBufActual)
917{
918 /*
919 * Create the GET_NOTIFICATION message and call the host.
920 */
921 GetNotification Msg;
922
923 Msg.hdr.u32Timeout = cMillies;
924 Msg.hdr.fInterruptible = true;
925 Msg.hdr.info.result = VERR_WRONG_ORDER;
926 Msg.hdr.info.u32ClientID = u32ClientId;
927 Msg.hdr.info.u32Function = GET_NOTIFICATION;
928 Msg.hdr.info.cParms = 4;
929 VbglHGCMParmPtrSetString(&Msg.patterns, pszPatterns);
930 Msg.buffer.SetPtr(pvBuf, cbBuf);
931 Msg.timestamp.SetUInt64(u64Timestamp);
932 Msg.size.SetUInt32(0);
933
934 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(sizeof(Msg)), &Msg, sizeof(Msg));
935 if (RT_SUCCESS(rc))
936 rc = Msg.hdr.info.result;
937
938 /*
939 * The cbBufActual parameter is also returned on overflow so the caller can
940 * adjust their buffer.
941 */
942 if ( rc == VERR_BUFFER_OVERFLOW
943 || pcbBufActual != NULL)
944 {
945 int rc2 = Msg.size.GetUInt32(pcbBufActual);
946 AssertRCReturn(rc2, RT_FAILURE(rc) ? rc : rc2);
947 }
948 if (RT_FAILURE(rc))
949 return rc;
950
951 /*
952 * Buffer layout: Name\0Value\0Flags\0.
953 *
954 * If the caller cares about any of these strings, make sure things are
955 * properly terminated (paranoia).
956 */
957 if ( RT_SUCCESS(rc)
958 && (ppszName != NULL || ppszValue != NULL || ppszFlags != NULL))
959 {
960 /* Validate / skip 'Name'. */
961 char *pszValue = RTStrEnd((char *)pvBuf, cbBuf) + 1;
962 AssertPtrReturn(pszValue, VERR_TOO_MUCH_DATA);
963 if (ppszName)
964 *ppszName = (char *)pvBuf;
965
966 /* Validate / skip 'Value'. */
967 char *pszFlags = RTStrEnd(pszValue, cbBuf - (pszValue - (char *)pvBuf)) + 1;
968 AssertPtrReturn(pszFlags, VERR_TOO_MUCH_DATA);
969 if (ppszValue)
970 *ppszValue = pszValue;
971
972 if (ppszFlags)
973 {
974 /* Validate 'Flags'. */
975 char *pszEos = RTStrEnd(pszFlags, cbBuf - (pszFlags - (char *)pvBuf));
976 AssertPtrReturn(pszEos, VERR_TOO_MUCH_DATA);
977 *ppszFlags = pszFlags;
978 }
979 }
980
981 /* And the timestamp, if requested. */
982 if (pu64Timestamp != NULL)
983 {
984 rc = Msg.timestamp.GetUInt64(pu64Timestamp);
985 AssertRCReturn(rc, rc);
986 }
987
988 return VINF_SUCCESS;
989}
990#endif /* VBOX_VBGLR3_XSERVER */
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