VirtualBox

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

Last change on this file since 58029 was 57407, checked in by vboxsync, 10 years ago

VBoxGuestR3LibGuestProp.cpp: Elimiate RTCMemAutoPtr.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette