VirtualBox

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

Last change on this file since 19420 was 18451, checked in by vboxsync, 16 years ago

VBoxGuestR3LibGuestProp.cpp: load of size_t warnings. Simplified the parameter setting by adding VbglHGCMParmPtrSetString.

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