VirtualBox

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

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

addendum to r71078: there is another limit of 15 bytes required

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