VirtualBox

Changeset 10930 in vbox for trunk/src/VBox/Additions/common


Ignore:
Timestamp:
Jul 29, 2008 1:25:47 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33778
Message:

Additions/common: added guest property enumeration functions to the guest library

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp

    r10865 r10930  
    2828#include <iprt/mem.h>
    2929#include <iprt/assert.h>
     30#include <iprt/autores>
    3031#include <iprt/stdarg.h>
    3132#include <VBox/log.h>
     
    3334
    3435#include "VBGLR3Internal.h"
     36
     37/*******************************************************************************
     38*   Structures and Typedefs                                                    *
     39*******************************************************************************/
     40/**
     41 * Structure containing information needed to enumerate through guest
     42 * properties.
     43 */
     44struct VBGLR3GUESTPROPENUM
     45{
     46    /** The buffer containing the raw enumeration data */
     47    char *pchBuf;
     48    /** The size of the buffer */
     49    uint32_t cchBuf;
     50    /** Index into the buffer pointing to the next entry to enumerate */
     51    uint32_t iBuf;
     52};
    3553
    3654using namespace guestProp;
     
    235253 * @param   u32ClientId     The client id returned by VbglR3ClipboardConnect().
    236254 * @param   pszName         The value to read.  Utf8
    237  * @param   pcBuf           A scratch buffer to store the data retrieved into.
     255 * @param   pvBuf           A scratch buffer to store the data retrieved into.
    238256 *                          The returned data is only valid for it's lifetime.
     257 *                          @a ppszValue will point to the start of this buffer.
    239258 * @param   cbBuf           The size of @a pcBuf
    240259 * @param   pszValue        Where to store the pointer to the value retrieved.
     260 *                          Optional.
    241261 * @param   pu64Timestamp   Where to store the timestamp.  Optional.
    242262 * @param   pszFlags        Where to store the pointer to the flags.  Optional.
     
    273293    if (RT_SUCCESS(rc) && (pu64Timestamp != NULL))
    274294        rc = VbglHGCMParmUInt64Get(&Msg.timestamp, pu64Timestamp);
    275     if (RT_SUCCESS(rc))
     295    if (RT_SUCCESS(rc) && (ppszValue != NULL))
    276296        *ppszValue = reinterpret_cast<char *>(pvBuf);
    277297    if (RT_SUCCESS(rc) && (ppszFlags != NULL))
     
    320340     * report the problem if that fails.
    321341     */
    322     char       *pszValue = NULL;
    323     void       *pvBuf    = NULL;
    324     uint32_t    cchBuf   = MAX_VALUE_LEN;
    325     int         rc       = VERR_BUFFER_OVERFLOW;
     342    uint32_t cchBuf = MAX_VALUE_LEN;
     343    RTMemAutoPtr<char> pcBuf;
     344    int rc = VERR_BUFFER_OVERFLOW;
    326345    for (unsigned i = 0; i < 10 && rc == VERR_BUFFER_OVERFLOW; ++i)
    327346    {
    328347        /* We leave a bit of space here in case the maximum value is raised. */
    329348        cchBuf += 1024;
    330         void *pvTmpBuf = RTMemRealloc(pvBuf, cchBuf);
    331         if (pvTmpBuf)
    332         {
    333             pvBuf = pvTmpBuf;
    334             rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cchBuf,
    335                                      &pszValue, NULL, NULL, &cchBuf);
    336         }
     349        if (!pcBuf.realloc<RTMemRealloc>(cchBuf))
     350            rc = VERR_NO_MEMORY;
     351        if (RT_SUCCESS(rc))
     352            rc = VbglR3GuestPropRead(u32ClientId, pszName, pcBuf.get(), cchBuf,
     353                                     NULL, NULL, NULL, &cchBuf);
    337354        else
    338355            rc = VERR_NO_MEMORY;
    339356    }
    340357    if (RT_SUCCESS(rc))
    341     {
    342         Assert(pszValue == (char *)pvBuf);
    343         *ppszValue = pszValue;
    344     }
    345     else
    346     {
    347         RTMemFree(pvBuf);
    348         if (rc == VERR_BUFFER_OVERFLOW)
    349             /* VERR_BUFFER_OVERFLOW has a different meaning here as a
    350              * return code, but we need to report the race. */
    351             rc = VERR_TOO_MUCH_DATA;
    352     }
     358        *ppszValue = pcBuf.release();
     359    else if (rc == VERR_BUFFER_OVERFLOW)
     360        /* VERR_BUFFER_OVERFLOW has a different meaning here as a
     361         * return code, but we need to report the race. */
     362        rc = VERR_TOO_MUCH_DATA;
    353363
    354364    return rc;
     
    407417    return rc;
    408418}
     419
     420
     421/**
     422 * Raw API for enumerating guest properties which match a given pattern.
     423 *
     424 * @returns VINF_SUCCESS on success and pcBuf points to a packed array
     425 *          of the form <name>, <value>, <timestamp string>, <flags>,
     426 *          terminated by four empty strings.  pcbBufActual will contain the
     427 *          total size of the array.
     428 * @returns VERR_BUFFER_OVERFLOW if the buffer provided was too small.  In
     429 *          this case pcbBufActual will contain the size of the buffer needed.
     430 * @returns IPRT error code in other cases, and pchBufActual is undefined.
     431 * @param   u32ClientId   The client ID returned by VbglR3GuestPropConnect
     432 * @param   paszPatterns  A packed array of zero terminated strings, terminated
     433 *                        by an empty string.
     434 * @param   pcBuf         The buffer to store the results to.
     435 * @param   cbBuf         The size of the buffer
     436 * @param   pcbBufActual  Where to store the size of the returned data on
     437 *                        success or the buffer size needed if @a pcBuf is too
     438 *                        small.
     439 */
     440VBGLR3DECL(int) VbglR3GuestPropEnumRaw(uint32_t u32ClientId,
     441                                       const char *paszPatterns,
     442                                       char *pcBuf,
     443                                       uint32_t cbBuf,
     444                                       uint32_t *pcbBufActual)
     445{
     446    EnumProperties Msg;
     447
     448    Msg.hdr.result = (uint32_t)VERR_WRONG_ORDER;  /** @todo drop the cast when the result type has been fixed! */
     449    Msg.hdr.u32ClientID = u32ClientId;
     450    Msg.hdr.u32Function = ENUM_PROPS;
     451    Msg.hdr.cParms = 3;
     452    /* Get the length of the patterns array... */
     453    uint32_t cchPatterns = 0;
     454    for (uint32_t cchCurrent = strlen(paszPatterns); cchCurrent != 0;
     455         cchCurrent = strlen(paszPatterns + cchPatterns))
     456        cchPatterns += cchCurrent + 1;
     457    /* ...including the terminator. */
     458    ++cchPatterns;
     459    VbglHGCMParmPtrSet(&Msg.patterns, const_cast<char *>(paszPatterns),
     460                       cchPatterns);
     461    VbglHGCMParmPtrSet(&Msg.strings, pcBuf, cbBuf);
     462    VbglHGCMParmUInt32Set(&Msg.size, 0);
     463
     464    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     465    if (RT_SUCCESS(rc))
     466        rc = Msg.hdr.result;
     467    if (   (RT_SUCCESS(rc) || (VERR_BUFFER_OVERFLOW == rc))
     468        && (pcbBufActual != NULL)
     469       )
     470    {
     471        int rc2 = VbglHGCMParmUInt32Get(&Msg.size, pcbBufActual);
     472        if (!RT_SUCCESS(rc2))
     473            rc = rc2;
     474    }
     475    return rc;
     476}
     477
     478
     479/**
     480 * Start enumerating guest properties which match a given pattern.
     481 * This function creates a handle which can be used to continue enumerating.
     482 * @returns VINF_SUCCESS on success, ppHandle points to a handle for continuing
     483 *          the enumeration and ppszName, ppszValue, pu64Timestamp and
     484 *          ppszFlags are set.
     485 * @returns VERR_NOT_FOUND if no matching properties were found.  In this case
     486 *          the return parameters are not initialised.
     487 * @returns VERR_TOO_MUCH_DATA if it was not possible to determine the amount
     488 *          of local space needed to store all the enumeration data.  This is
     489 *          due to a race between allocating space and the host adding new
     490 *          data, so retrying may help here.  Other parameters are left
     491 *          uninitialised
     492 * @returns IPRT status value otherwise.  Other parameters are left
     493 *          uninitialised.
     494 * @param   ppaszPatterns the patterns against which the properties are
     495 *                        matched.  Pass NULL if everything should be matched.
     496 * @param   cPatterns     the number of patterns in @a ppaszPatterns.  0 means
     497 *                        match everything.
     498 * @param   ppHandle      where the handle for continued enumeration is stored
     499 *                        on success.  This must be freed with
     500 *                        VbglR3GuestPropEnumFree when it is no longer needed.
     501 * @param   ppszName      Where to store the first property name on success.
     502 *                        Should not be freed.
     503 * @param   ppszValue     Where to store the first property value on success.
     504 *                        Should not be freed.
     505 * @param   ppszValue     Where to store the first timestamp value on success.
     506 * @param   ppszFlags     Where to store the first flags value on success.
     507 *                        Should not be freed.
     508 */
     509VBGLR3DECL(int) VbglR3GuestPropEnum(uint32_t u32ClientId,
     510                                    char **ppaszPatterns,
     511                                    int cPatterns,
     512                                    PVBGLR3GUESTPROPENUM *ppHandle,
     513                                    char **ppszName,
     514                                    char **ppszValue,
     515                                    uint64_t *pu64Timestamp,
     516                                    char **ppszFlags)
     517{
     518    int rc = VINF_SUCCESS;
     519    RTMemAutoPtr<VBGLR3GUESTPROPENUM, VbglR3GuestPropEnumFree> pHandle;
     520    pHandle = reinterpret_cast<PVBGLR3GUESTPROPENUM>(
     521                                      RTMemAllocZ(sizeof(VBGLR3GUESTPROPENUM))
     522                                                    );
     523    if (NULL == pHandle.get())
     524        rc = VERR_NO_MEMORY;
     525
     526    /* Get the length of the pattern string, including the final terminator. */
     527    uint32_t cchPatterns = 1;
     528    for (int i = 0; i < cPatterns; ++i)
     529        cchPatterns += strlen(ppaszPatterns[i]) + 1;
     530    /* Pack the pattern array */
     531    RTMemAutoPtr<char> pPatterns;
     532    pPatterns = reinterpret_cast<char *>(RTMemAlloc(cchPatterns));
     533    char *pPatternsRaw = pPatterns.get();
     534    for (int i = 0; i < cPatterns; ++i)
     535        pPatternsRaw = strcpy(pPatternsRaw, ppaszPatterns[i]) + strlen(ppaszPatterns[i]) + 1;
     536    *pPatternsRaw = 0;
     537
     538    /* Randomly chosen initial size for the buffer to hold the enumeration
     539     * information. */
     540    uint32_t cchBuf = 4096;
     541    RTMemAutoPtr<char> pchBuf;
     542    /* In reading the guest property data we are racing against the host
     543     * adding more of it, so loop a few times and retry on overflow. */
     544    bool finish = false;
     545    if (RT_SUCCESS(rc))
     546        for (int i = 0; (i < 10) && !finish; ++i)
     547        {
     548            if (!pchBuf.realloc<RTMemRealloc>(cchBuf))
     549                rc = VERR_NO_MEMORY;
     550            if (RT_SUCCESS(rc) || (VERR_BUFFER_OVERFLOW == rc))
     551                rc = VbglR3GuestPropEnumRaw(u32ClientId, pPatterns.get(),
     552                                            pchBuf.get(), cchBuf, &cchBuf);
     553            if (rc != VERR_BUFFER_OVERFLOW)
     554                finish = true;
     555            else
     556                cchBuf += 4096;  /* Just to increase our chances */
     557        }
     558    if (VERR_BUFFER_OVERFLOW == rc)
     559        rc = VERR_TOO_MUCH_DATA;
     560    if (RT_SUCCESS(rc))
     561    {
     562        /* Transfer ownership of the buffer to the handle structure. */
     563        pHandle->pchBuf = pchBuf.release();
     564        pHandle->cchBuf = cchBuf;
     565    }
     566    if (RT_SUCCESS(rc))
     567        rc = VbglR3GuestPropEnumNext(pHandle.get(), ppszName, ppszValue,
     568                                     pu64Timestamp, ppszFlags);
     569    if (RT_SUCCESS(rc) && (NULL == ppszName))
     570        /* No matching properties found */
     571        rc = VERR_NOT_FOUND;
     572    /* And transfer ownership of the handle to the caller. */
     573    if (RT_SUCCESS(rc))
     574        *ppHandle = pHandle.release();
     575    return rc;
     576}
     577
     578
     579/**
     580 * Get the next guest property.  See @a VbglR3GuestPropEnum.
     581 * @param  pHandle       handle obtained from @a VbglR3GuestPropEnum.
     582 * @param  ppszName      where to store the next property name.  This will be
     583 *                       set to NULL if there are no more properties to
     584 *                       enumerate.  This pointer should not be freed.
     585 * @param  ppszValue     where to store the next property value.  This will be
     586 *                       set to NULL if there are no more properties to
     587 *                       enumerate.  This pointer should not be freed.
     588 * @param  pu64Timestamp where to store the next property timestamp.  This
     589 *                       will be set to zero if there are no more properties
     590 *                       to enumerate.
     591 * @param  ppszFlags     where to store the next property flags.  This will be
     592 *                       set to NULL if there are no more properties to
     593 *                       enumerate.  This pointer should not be freed.
     594 */
     595VBGLR3DECL(int) VbglR3GuestPropEnumNext(PVBGLR3GUESTPROPENUM pHandle,
     596                                        char **ppszName,
     597                                        char **ppszValue,
     598                                        uint64_t *pu64Timestamp,
     599                                        char **ppszFlags)
     600{
     601    uint32_t iBuf = pHandle->iBuf;
     602    char *pszName = pHandle->pchBuf + iBuf;
     603    /** @todo replace these with safe strlen's and return an error if needed. */
     604    iBuf += strlen(pszName) + 1;
     605    char *pszValue = pHandle->pchBuf + iBuf;
     606    iBuf += strlen(pszValue) + 1;
     607    char *pszTimestamp = pHandle->pchBuf + iBuf;
     608    iBuf += strlen(pszTimestamp) + 1;
     609    uint64_t u64Timestamp = RTStrToUInt64(pszTimestamp);
     610    char *pszFlags = pHandle->pchBuf + iBuf;
     611    iBuf += strlen(pszFlags) + 1;
     612    /* Otherwise we just stay at the end of the list. */
     613    if ((iBuf != pHandle->iBuf + 4) && (iBuf < pHandle->cchBuf) /* sanity */)
     614        pHandle->iBuf = iBuf;
     615    *ppszName = *pszName != 0 ? pszName : NULL;
     616    *ppszValue = pszValue != 0 ? pszValue : NULL;
     617    *pu64Timestamp = u64Timestamp;
     618    *ppszFlags = pszFlags != 0 ? pszFlags : NULL;
     619    return VINF_SUCCESS;
     620}
     621
     622
     623/**
     624 * Free an enumeration handle returned by @a VbglR3GuestPropEnum.
     625 * @param pHandle the handle to free
     626 */
     627VBGLR3DECL(void) VbglR3GuestPropEnumFree(PVBGLR3GUESTPROPENUM pHandle)
     628{
     629    RTMemFree(pHandle->pchBuf);
     630    RTMemFree(pHandle);
     631}
Note: See TracChangeset for help on using the changeset viewer.

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