VirtualBox

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

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

*: spelling fixes, thanks Timeless!

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