VirtualBox

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

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

Additions/common/VBoxGuestLib: change VbglR3GuestPropEnum() to return success if no properties are found.

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