VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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