VirtualBox

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

Last change on this file since 31384 was 31384, checked in by vboxsync, 14 years ago

X11 additions: fixed unresolved symbols for Xorg < 7.0

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