VirtualBox

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

Last change on this file since 21845 was 21211, checked in by vboxsync, 16 years ago

VBoxGuest.h,VBoxGuestLib: Moved the VbglR3 API out of VBoxGuest.h and did some cleanup.

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