VirtualBox

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

Last change on this file since 27119 was 26425, checked in by vboxsync, 15 years ago

alternative license for VBoxGuestLib is CDDL

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

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