VirtualBox

Changeset 13763

Show
Ignore:
Timestamp:
11/03/08 17:39:22 (2 months ago)
Author:
vboxsync
Message:

Backed out 38734

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/VBox/HostServices/GuestPropertySvc.h

    r13759 r13763  
    148148                break; 
    149149        if (RT_ELEMENTS(flagList) == i) 
    150              rc = VERR_PARSE_ERROR; 
     150             rc = VERR_INVALID_PARAMETER; 
    151151        else 
    152152        { 
     
    157157            if (',' == *pcszNext) 
    158158                ++pcszNext; 
    159             else if (*pcszNext != '\0') 
    160                 rc = VERR_PARSE_ERROR; 
    161159            while (' ' == *pcszNext) 
    162160                ++pcszNext; 
     
    191189        for (; i < RT_ELEMENTS(flagList); ++i) 
    192190        { 
    193             if (flagList[i] == (fFlags & flagList[i])
     191            if (fFlags & flagList[i]
    194192            { 
    195193                strcpy(pszNext, flagName(flagList[i])); 
     
    215213enum eHostFn 
    216214{ 
    217     /** 
    218      * Set properties in a block.  The parameters are pointers to 
    219      * NULL-terminated arrays containing the paramters.  These are, in order, 
    220      * name, value, timestamp, flags.  Strings are stored as pointers to 
    221      * mutable utf8 data.  All parameters must be supplied. 
    222      */ 
    223     SET_PROPS_HOST = 1, 
     215    /** Pass the address of the cfgm node used by the service as a database. */ 
     216    SET_CFGM_NODE = 1, 
    224217    /** 
    225218     * Get the value attached to a guest property 
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r13759 r13763  
    4747 
    4848#include <memory>  /* for auto_ptr */ 
    49 #include <string> 
    50 #include <list> 
    5149 
    5250#include <iprt/err.h> 
     
    6159#include <VBox/log.h> 
    6260 
     61#include <VBox/cfgm.h> 
     62 
    6363/******************************************************************************* 
    6464*   Internal functions                                                         * 
     
    7777} 
    7878 
    79 /** Extract a constant pointer value from an HGCM parameter structure */ 
    80 static int VBoxHGCMParmPtrConstGet (VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) 
    81 { 
    82     if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) 
    83     { 
    84         *ppv = pParm->u.pointer.addr; 
    85         *pcb = pParm->u.pointer.size; 
    86         return VINF_SUCCESS; 
    87     } 
    88  
    89     return VERR_INVALID_PARAMETER; 
    90 } 
    91  
    9279/** Set a uint32_t value to an HGCM parameter structure */ 
    9380static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32) 
     
    9784} 
    9885 
     86 
    9987/** Set a uint64_t value to an HGCM parameter structure */ 
    10088static void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64) 
     
    10290    pParm->type = VBOX_HGCM_SVC_PARM_64BIT; 
    10391    pParm->u.uint64 = u64; 
    104 } 
    105  
    106 /** Set a pointer value to an HGCM parameter structure */ 
    107 static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) 
    108 { 
    109     pParm->type = VBOX_HGCM_SVC_PARM_PTR; 
    110     pParm->u.pointer.addr = pv; 
    111     pParm->u.pointer.size = cb; 
    11292} 
    11393 
     
    124104    /** HGCM helper functions. */ 
    125105    PVBOXHGCMSVCHELPERS mpHelpers; 
    126     /** Structure for holding a property */ 
    127     struct Property 
    128     { 
    129         /** The name of the property */ 
    130         std::string mName; 
    131         /** The property value */ 
    132         std::string mValue; 
    133         /** The timestamp of the property */ 
    134         uint64_t mTimestamp; 
    135         /** The property flags */ 
    136         uint32_t mFlags; 
    137         /** Constructor with const char * */ 
    138         Property(const char *pcszName, const char *pcszValue, 
    139                  uint64_t u64Timestamp, uint32_t u32Flags) 
    140             : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp), 
    141               mFlags(u32Flags) {} 
    142         /** Constructor with std::string */ 
    143         Property(std::string name, std::string value, uint64_t u64Timestamp, 
    144                  uint32_t u32Flags) 
    145             : mName(name), mValue(value), mTimestamp(u64Timestamp), 
    146               mFlags(u32Flags) {} 
    147     }; 
    148     /** The properties list type */ 
    149     typedef std::list <Property> PropertyList; 
    150     /** The property list */ 
    151     PropertyList mProperties; 
     106    /** Pointer to our configuration values node. */ 
     107    PCFGMNODE mpValueNode; 
     108    /** Pointer to our configuration timestamps node. */ 
     109    PCFGMNODE mpTimestampNode; 
     110    /** Pointer to our configuration flags node. */ 
     111    PCFGMNODE mpFlagsNode; 
    152112    /** @todo we should have classes for thread and request handler thread */ 
    153113    /** Queue of outstanding property change notifications */ 
     
    165125public: 
    166126    explicit Service(PVBOXHGCMSVCHELPERS pHelpers) 
    167         : mpHelpers(pHelpers), mfExitThread(false), mpfnHostCallback(NULL), 
     127        : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL), 
     128          mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL), 
    168129          mpvHostData(NULL) 
    169130    { 
    170131        int rc = RTReqCreateQueue(&mReqQueue); 
    171 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
    172         if (RT_SUCCESS(rc)) 
    173             rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, 
    174                                 RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE, 
    175                                 "GuestPropReq"); 
    176 #endif 
     132        rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP, 
     133                                RTTHREADFLAGS_WAITABLE, "GuestPropReq"); 
    177134        if (RT_FAILURE(rc)) 
    178135            throw rc; 
     
    253210    static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser); 
    254211    int validateName(const char *pszName, uint32_t cbName); 
    255     int validateValue(const char *pszValue, uint32_t cbValue); 
    256     int setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
     212    int validateValue(char *pszValue, uint32_t cbValue); 
     213    int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
    257214    int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 
    258215    int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest); 
     
    329286 * @thread  HGCM 
    330287 */ 
    331 int Service::validateValue(const char *pszValue, uint32_t cbValue) 
     288int Service::validateValue(char *pszValue, uint32_t cbValue) 
    332289{ 
    333290    LogFlowFunc(("cbValue=%d\n", cbValue)); 
     
    348305} 
    349306 
    350 /** 
    351  * Set a block of properties in the property registry, checking the validity 
    352  * of the arguments passed. 
    353  * 
    354  * @returns iprt status value 
    355  * @param   cParms  the number of HGCM parameters supplied 
    356  * @param   paParms the array of HGCM parameters 
    357  * @thread  HGCM 
    358  */ 
    359 int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
    360 { 
    361     char **ppNames, **ppValues, **ppFlags; 
    362     uint64_t *pTimestamps; 
    363     uint32_t cbDummy; 
    364     int rc = VINF_SUCCESS; 
    365  
    366     /* 
    367      * Get and validate the parameters 
    368      */ 
    369     if (   (cParms != 4) 
    370         || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[0], (void **) &ppNames, &cbDummy)) 
    371         || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[1], (void **) &ppValues, &cbDummy)) 
    372         || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[2], (void **) &pTimestamps, &cbDummy)) 
    373         || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[3], (void **) &ppFlags, &cbDummy)) 
    374         ) 
    375         rc = VERR_INVALID_PARAMETER; 
    376  
    377     /* 
    378      * Add the properties to the end of the list.  If we succeed then we 
    379      * will remove duplicates afterwards. 
    380      */ 
    381     /* Remember the last property before we started adding, for rollback or 
    382      * cleanup. */ 
    383     PropertyList::iterator itEnd = mProperties.end(); 
    384     if (!mProperties.empty()) 
    385         --itEnd; 
    386     try 
    387     { 
    388         for (unsigned i = 0; RT_SUCCESS(rc) && ppNames[i] != NULL; ++i) 
    389         { 
    390             uint32_t fFlags; 
    391             if (   !VALID_PTR(ppNames[i]) 
    392                 || !VALID_PTR(ppValues[i]) 
    393                 || !VALID_PTR(ppFlags[i]) 
    394               ) 
    395                 rc = VERR_INVALID_POINTER; 
    396             if (RT_SUCCESS(rc)) 
    397                 rc = validateFlags(ppFlags[i], &fFlags); 
    398             if (RT_SUCCESS(rc)) 
    399                 mProperties.push_back(Property(ppNames[i], ppValues[i], 
    400                                                pTimestamps[i], fFlags)); 
    401         } 
    402     } 
    403     catch (std::bad_alloc) 
    404     { 
    405         rc = VERR_NO_MEMORY; 
    406     } 
    407  
    408     /* 
    409      * If all went well then remove the duplicate elements. 
    410      */ 
    411     if (RT_SUCCESS(rc) && itEnd != mProperties.end()) 
    412     { 
    413         ++itEnd; 
    414         for (unsigned i = 0; ppNames[i] != NULL; ++i) 
    415         { 
    416             bool found = false; 
    417             for (PropertyList::iterator it = mProperties.begin(); 
    418                 !found && it != itEnd; ++it) 
    419                 if (it->mName.compare(ppNames[i]) == 0) 
    420                 { 
    421                     found = true; 
    422                     mProperties.erase(it); 
    423                 } 
    424         } 
    425     } 
    426  
    427     /* 
    428      * If something went wrong then rollback.  This is possible because we 
    429      * haven't deleted anything yet. 
    430      */ 
    431     if (RT_FAILURE(rc)) 
    432     { 
    433         if (itEnd != mProperties.end()) 
    434             ++itEnd; 
    435         mProperties.erase(itEnd, mProperties.end()); 
    436     } 
    437     return rc; 
    438 } 
    439307 
    440308/** 
     
    450318 * @thread  HGCM 
    451319 */ 
     320int Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
     321{ 
     322    int rc = VINF_SUCCESS; 
     323    char *pszName, *pszValue; 
     324    uint32_t cbName, cbValue; 
     325    size_t cbValueActual; 
     326 
     327    LogFlowThisFunc(("\n")); 
     328    AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
     329    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */ 
     330        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */ 
     331        || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */ 
     332       ) 
     333        rc = VERR_INVALID_PARAMETER; 
     334    if (RT_SUCCESS(rc)) 
     335        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); 
     336    if (RT_SUCCESS(rc)) 
     337        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue); 
     338    if (RT_SUCCESS(rc)) 
     339        rc = validateName(pszName, cbName); 
     340    if (RT_SUCCESS(rc)) 
     341        rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual); 
     342    if (RT_SUCCESS(rc)) 
     343        VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual); 
     344    if (RT_SUCCESS(rc) && (cbValueActual > cbValue)) 
     345        rc = VERR_BUFFER_OVERFLOW; 
     346    if (RT_SUCCESS(rc)) 
     347        rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue); 
     348    if (RT_SUCCESS(rc)) 
     349        Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue)); 
     350    else if (VERR_CFGM_VALUE_NOT_FOUND == rc) 
     351        rc = VERR_NOT_FOUND; 
     352    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
     353    return rc; 
     354} 
     355 
     356 
     357/** 
     358 * Retrieve a value from the property registry by name, checking the validity 
     359 * of the arguments passed.  If the guest has not allocated enough buffer 
     360 * space for the value then we return VERR_OVERFLOW and set the size of the 
     361 * buffer needed in the "size" HGCM parameter.  If the name was not found at 
     362 * all, we return VERR_NOT_FOUND. 
     363 * 
     364 * @returns iprt status value 
     365 * @param   cParms  the number of HGCM parameters supplied 
     366 * @param   paParms the array of HGCM parameters 
     367 * @thread  HGCM 
     368 */ 
    452369int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
    453370{ 
    454371    int rc = VINF_SUCCESS; 
    455     const char *pcszName; 
    456     char *pchBuf; 
     372    char *pszName, *pchBuf; 
    457373    uint32_t cchName, cchBuf; 
    458     size_t cchFlags, cchBufActual; 
     374    size_t cchValue, cchFlags, cchBufActual; 
    459375    char szFlags[MAX_FLAGS_LEN]; 
    460376    uint32_t fFlags; 
     
    464380     */ 
    465381    LogFlowThisFunc(("\n")); 
     382    AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
    466383    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */ 
    467384        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)    /* name */ 
     
    470387        rc = VERR_INVALID_PARAMETER; 
    471388    if (RT_SUCCESS(rc)) 
    472         rc = VBoxHGCMParmPtrConstGet(&paParms[0], (const void **) &pcszName, &cchName); 
     389        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName); 
    473390    if (RT_SUCCESS(rc)) 
    474391        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 
    475392    if (RT_SUCCESS(rc)) 
    476         rc = validateName(pcszName, cchName); 
     393        rc = validateName(pszName, cchName); 
    477394 
    478395    /* 
     
    481398 
    482399    /* Get the value size */ 
    483     PropertyList::const_iterator it; 
    484     bool found = false; 
    485     if (RT_SUCCESS(rc)) 
    486         for (it = mProperties.begin(); it != mProperties.end(); ++it) 
    487             if (it->mName.compare(pcszName) == 0) 
    488             { 
    489                 found = true; 
    490                 break; 
    491             } 
    492     if (RT_SUCCESS(rc) && !found) 
    493         rc = VERR_NOT_FOUND; 
    494     if (RT_SUCCESS(rc)) 
    495         rc = writeFlags(it->mFlags, szFlags); 
     400    if (RT_SUCCESS(rc)) 
     401        rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue); 
     402    /* Get the flags and their size */ 
     403    if (RT_SUCCESS(rc)) 
     404        CFGMR3QueryU32(mpFlagsNode, pszName, (uint32_t *)&fFlags); 
     405    if (RT_SUCCESS(rc)) 
     406        rc = writeFlags(fFlags, szFlags); 
    496407    if (RT_SUCCESS(rc)) 
    497408        cchFlags = strlen(szFlags); 
     
    499410    if (RT_SUCCESS(rc)) 
    500411    { 
    501         cchBufActual = it->mValue.size() + 1 + cchFlags; 
     412        cchBufActual = cchValue + cchFlags; 
    502413        VBoxHGCMParmUInt32Set(&paParms[3], cchBufActual); 
    503414    } 
    504415    if (RT_SUCCESS(rc) && (cchBufActual > cchBuf)) 
    505416        rc = VERR_BUFFER_OVERFLOW; 
    506     /* Write the value, flags and timestamp */ 
    507     if (RT_SUCCESS(rc)) 
    508     { 
    509         it->mValue.copy(pchBuf, cchBuf, 0); 
    510         pchBuf[it->mValue.size()] = '\0'; /* Terminate the value */ 
    511         strcpy(pchBuf + it->mValue.size() + 1, szFlags); 
    512         VBoxHGCMParmUInt64Set(&paParms[2], it->mTimestamp); 
    513     } 
     417    /* Write the value */ 
     418    if (RT_SUCCESS(rc)) 
     419        rc = CFGMR3QueryString(mpValueNode, pszName, pchBuf, cchBuf); 
     420    /* Write the flags */ 
     421    if (RT_SUCCESS(rc)) 
     422        strcpy(pchBuf + cchValue, szFlags); 
     423    /* Timestamp */ 
     424    uint64_t u64Timestamp = 0; 
     425    if (RT_SUCCESS(rc)) 
     426        CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp); 
     427    VBoxHGCMParmUInt64Set(&paParms[2], u64Timestamp); 
    514428 
    515429    /* 
     
    517431     */ 
    518432    if (RT_SUCCESS(rc)) 
    519         Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n", 
    520               pcszName, it->mValue.c_str(), it->mTimestamp, szFlags)); 
     433        Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n", 
     434              pszName, cchValue, pchBuf, u64Timestamp, cchFlags, 
     435              pchBuf + cchValue)); 
     436    else if (VERR_CFGM_VALUE_NOT_FOUND == rc) 
     437        rc = VERR_NOT_FOUND; 
    521438    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
    522439    return rc; 
    523440} 
    524441 
     442 
    525443/** 
    526444 * Set a value in the property registry by name, checking the validity 
    527  * of the arguments passed. 
    528  * 
    529  * @returns iprt status value 
    530  * @param   cParms  the number of HGCM parameters supplied 
    531  * @param   paParms the array of HGCM parameters 
    532  * @param   isGuest is this call coming from the guest (or the host)? 
    533  * @throws  std::bad_alloc  if an out of memory condition occurs 
    534  * @thread  HGCM 
    535  */ 
    536 int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 
    537 { 
    538     int rc = VINF_SUCCESS; 
    539     const char *pcszName, *pcszValue, *pcszFlags = NULL; 
    540     uint32_t cchName, cchValue, cchFlags = 0; 
    541     uint32_t fFlags = NILFLAG; 
    542  
    543     LogFlowThisFunc(("\n")); 
    544     /* 
    545      * First of all, make sure that we won't exceed the maximum number of properties. 
    546      */ 
    547     if (mProperties.size() >= MAX_PROPS) 
    548         rc = VERR_TOO_MUCH_DATA; 
    549  
    550     /* 
    551      * General parameter correctness checking. 
    552      */ 
    553     if (   RT_SUCCESS(rc) 
    554         && (   (cParms < 2) || (cParms > 3)  /* Hardcoded value as the next lines depend on it. */ 
    555             || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 
    556                    (const void **) &pcszName, &cchName)) /* name */ 
    557             || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[1], 
    558                    (const void **) &pcszValue, &cchValue)) /* value */ 
    559             || (   (3 == cParms) 
    560                 && RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[2], 
    561                        (const void **) &pcszFlags, &cchFlags)) /* flags */ 
    562                ) 
    563            ) 
    564        ) 
    565         rc = VERR_INVALID_PARAMETER; 
    566  
    567     /* 
    568      * Check the values passed in the parameters for correctness. 
    569      */ 
    570     if (RT_SUCCESS(rc)) 
    571         rc = validateName(pcszName, cchName); 
    572     if (RT_SUCCESS(rc)) 
    573         rc = validateValue(pcszValue, cchValue); 
    574     if ((3 == cParms) && RT_SUCCESS(rc)) 
    575         rc = RTStrValidateEncodingEx(pcszFlags, cchFlags, 
    576                                      RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); 
    577     if ((3 == cParms) && RT_SUCCESS(rc)) 
    578         rc = validateFlags(pcszFlags, &fFlags); 
    579  
    580     /* 
    581      * If the property already exists, check its flags to see if we are allowed 
    582      * to change it. 
    583      */ 
    584     PropertyList::iterator it; 
    585     bool found = false; 
    586     if (RT_SUCCESS(rc)) 
    587         for (it = mProperties.begin(); it != mProperties.end(); ++it) 
    588             if (it->mName.compare(pcszName) == 0) 
    589             { 
    590                 found = true; 
    591                 break; 
    592             } 
    593     if (RT_SUCCESS(rc) && found) 
    594         if (   (isGuest && (it->mFlags & RDONLYGUEST)) 
    595             || (!isGuest && (it->mFlags & RDONLYHOST)) 
    596            ) 
    597             rc = VERR_PERMISSION_DENIED; 
    598  
    599     /* 
    600      * Set the actual value 
    601      */ 
    602     if (RT_SUCCESS(rc)) 
    603     { 
    604         RTTIMESPEC time; 
    605         uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); 
    606         if (found) 
    607         { 
    608             it->mValue = pcszValue; 
    609             it->mTimestamp = u64TimeNano; 
    610             it->mFlags = fFlags; 
    611         } 
    612         else  /* This can throw.  No problem as we have nothing to roll back. */ 
    613             mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags)); 
    614     } 
    615  
    616     /* 
    617      * Send a notification to the host and return. 
    618      */ 
    619     if (RT_SUCCESS(rc)) 
    620     { 
    621         // if (isGuest)  /* Notify the host even for properties that the host 
    622         //                * changed.  Less efficient, but ensures consistency. */ 
    623             notifyHost(pcszName); 
    624         Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue)); 
    625     } 
    626     LogFlowThisFunc(("rc = %Rrc\n", rc)); 
    627     return rc; 
    628 } 
    629  
    630  
    631 /** 
    632  * Remove a value in the property registry by name, checking the validity 
    633  * of the arguments passed. 
    634  * 
    635  * @returns iprt status value 
    636  * @param   cParms  the number of HGCM parameters supplied 
    637  * @param   paParms the array of HGCM parameters 
    638  * @param   isGuest is this call coming from the guest (or the host)? 
    639  * @thread  HGCM 
    640  */ 
    641 int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 
    642 { 
    643     int rc = VINF_SUCCESS; 
    644     const char *pcszName; 
    645     uint32_t cbName; 
    646  
    647     LogFlowThisFunc(("\n")); 
    648  
    649     /* 
    650      * Check the user-supplied parameters. 
    651      */ 
    652     if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */ 
    653         || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 
    654                (const void **) &pcszName, &cbName))  /* name */ 
    655        ) 
    656         rc = VERR_INVALID_PARAMETER; 
    657     if (RT_SUCCESS(rc)) 
    658         rc = validateName(pcszName, cbName); 
    659  
    660     /* 
    661      * If the property exists, check its flags to see if we are allowed 
    662      * to change it. 
    663      */ 
    664     PropertyList::iterator it; 
    665     bool found = false; 
    666     if (RT_SUCCESS(rc)) 
    667         for (it = mProperties.begin(); it != mProperties.end(); ++it) 
    668             if (it->mName.compare(pcszName) == 0) 
    669             { 
    670                 found = true; 
    671                 break; 
    672             } 
    673     if (RT_SUCCESS(rc) && found) 
    674         if (   (isGuest && (it->mFlags & RDONLYGUEST)) 
    675             || (!isGuest && (it->mFlags & RDONLYHOST)) 
    676            ) 
    677             rc = VERR_PERMISSION_DENIED; 
    678  
    679     /* 
    680      * And delete the property if all is well. 
    681      */ 
    682     if (RT_SUCCESS(rc) && found) 
    683     { 
    684         mProperties.erase(it); 
    685         // if (isGuest)  /* Notify the host even for properties that the host 
    686         //                * changed.  Less efficient, but ensures consistency. */ 
    687             notifyHost(pcszName); 
    688     } 
    689     LogFlowThisFunc(("rc = %Rrc\n", rc)); 
    690     return rc; 
    691 } 
    692  
    693 /** 
    694  * Enumerate guest properties by mask, checking the validity 
    695445 * of the arguments passed. 
    696446 * 
     
    700450 * @thread  HGCM 
    701451 */ 
     452int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 
     453{ 
     454    int rc = VINF_SUCCESS; 
     455    char *pszName, *pszValue; 
     456    uint32_t cchName, cchValue; 
     457    uint32_t fFlags = NILFLAG; 
     458 
     459    LogFlowThisFunc(("\n")); 
     460    AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
     461    /* 
     462     * First of all, make sure that we won't exceed the maximum number of properties. 
     463     */ 
     464    { 
     465        unsigned cChildren = 0; 
     466        for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild)) 
     467            ++cChildren; 
     468        if (cChildren >= MAX_PROPS) 
     469            rc = VERR_TOO_MUCH_DATA; 
     470    } 
     471    /* 
     472     * General parameter correctness checking. 
     473     */ 
     474    if (   RT_SUCCESS(rc) 
     475        && (   (cParms < 2) || (cParms > 4)  /* Hardcoded value as the next lines depend on it. */ 
     476            || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */ 
     477            || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */ 
     478            || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR))  /* flags */ 
     479           ) 
     480       ) 
     481        rc = VERR_INVALID_PARAMETER; 
     482    /* 
     483     * Check the values passed in the parameters for correctness. 
     484     */ 
     485    if (RT_SUCCESS(rc)) 
     486        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName); 
     487    if (RT_SUCCESS(rc)) 
     488        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue); 
     489    if (RT_SUCCESS(rc)) 
     490        rc = validateName(pszName, cchName); 
     491    if (RT_SUCCESS(rc)) 
     492        rc = validateValue(pszValue, cchValue); 
     493 
     494    /* 
     495     * If the property already exists, check its flags to see if we are allowed 
     496     * to change it. 
     497     */ 
     498    if (RT_SUCCESS(rc)) 
     499    { 
     500        CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags);  /* Failure is no problem here. */ 
     501        if (   (isGuest && (fFlags & RDONLYGUEST)) 
     502            || (!isGuest && (fFlags & RDONLYHOST)) 
     503           ) 
     504            rc = VERR_PERMISSION_DENIED; 
     505    } 
     506 
     507    /* 
     508     * Check whether the user supplied flags (if any) are valid. 
     509     */ 
     510    if (RT_SUCCESS(rc) && (3 == cParms)) 
     511    { 
     512        char *pszFlags; 
     513        uint32_t cchFlags; 
     514        rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags); 
     515        if (RT_SUCCESS(rc)) 
     516            rc = validateFlags(pszFlags, &fFlags); 
     517    } 
     518    /* 
     519     * Set the actual value 
     520     */ 
     521    if (RT_SUCCESS(rc)) 
     522    { 
     523        RTTIMESPEC time; 
     524        CFGMR3RemoveValue(mpValueNode, pszName); 
     525        CFGMR3RemoveValue(mpTimestampNode, pszName); 
     526        CFGMR3RemoveValue(mpFlagsNode, pszName); 
     527        rc = CFGMR3InsertString(mpValueNode, pszName, pszValue); 
     528        if (RT_SUCCESS(rc)) 
     529            rc = CFGMR3InsertInteger(mpTimestampNode, pszName, 
     530                                     RTTimeSpecGetNano(RTTimeNow(&time))); 
     531        if (RT_SUCCESS(rc)) 
     532            rc = CFGMR3InsertInteger(mpFlagsNode, pszName, fFlags); 
     533        /* If anything goes wrong, make sure that we leave a clean state 
     534         * behind. */ 
     535        if (RT_FAILURE(rc)) 
     536        { 
     537            CFGMR3RemoveValue(mpValueNode, pszName); 
     538            CFGMR3RemoveValue(mpTimestampNode, pszName); 
     539            CFGMR3RemoveValue(mpFlagsNode, pszName); 
     540        } 
     541    } 
     542    /* 
     543     * Send a notification to the host and return. 
     544     */ 
     545    if (RT_SUCCESS(rc)) 
     546    { 
     547        if (isGuest) 
     548            notifyHost(pszName); 
     549        Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue)); 
     550    } 
     551    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
     552    return rc; 
     553} 
     554 
     555 
     556/** 
     557 * Remove a value in the property registry by name, checking the validity 
     558 * of the arguments passed. 
     559 * 
     560 * @returns iprt status value 
     561 * @param   cParms  the number of HGCM parameters supplied 
     562 * @param   paParms the array of HGCM parameters 
     563 * @thread  HGCM 
     564 */ 
     565int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) 
     566{ 
     567    int rc = VINF_SUCCESS; 
     568    char *pszName; 
     569    uint32_t cbName; 
     570 
     571    LogFlowThisFunc(("\n")); 
     572    AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
     573 
     574    /* 
     575     * Check the user-supplied parameters. 
     576     */ 
     577    if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */ 
     578        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */ 
     579       ) 
     580        rc = VERR_INVALID_PARAMETER; 
     581    if (RT_SUCCESS(rc)) 
     582        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); 
     583    if (RT_SUCCESS(rc)) 
     584        rc = validateName(pszName, cbName); 
     585 
     586    /* 
     587     * If the property already exists, check its flags to see if we are allowed 
     588     * to change it. 
     589     */ 
     590    if (RT_SUCCESS(rc)) 
     591    { 
     592        uint32_t fFlags = NILFLAG; 
     593        CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags);  /* Failure is no problem here. */ 
     594        if (   (isGuest && (fFlags & RDONLYGUEST)) 
     595            || (!isGuest && (fFlags & RDONLYHOST)) 
     596           ) 
     597            rc = VERR_PERMISSION_DENIED; 
     598    } 
     599 
     600    /* 
     601     * And delete the property if all is well. 
     602     */ 
     603    if (RT_SUCCESS(rc)) 
     604    { 
     605        CFGMR3RemoveValue(mpValueNode, pszName); 
     606        if (isGuest) 
     607            notifyHost(pszName); 
     608    } 
     609    LogFlowThisFunc(("rc = %Rrc\n", rc)); 
     610    return rc; 
     611} 
     612 
     613/** 
     614 * Enumerate guest properties by mask, checking the validity 
     615 * of the arguments passed. 
     616 * 
     617 * @returns iprt status value 
     618 * @param   cParms  the number of HGCM parameters supplied 
     619 * @param   paParms the array of HGCM parameters 
     620 * @thread  HGCM 
     621 */ 
    702622int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 
    703623{ 
     624    /* We reallocate the temporary buffer in which we build up our array in 
     625     * increments of size BLOCK: */ 
     626    enum 
     627    { 
     628        /* Calculate the increment, not yet rounded down */ 
     629        BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048), 
     630        /* And this is the increment after rounding */ 
     631        BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024 
     632    }; 
    704633    int rc = VINF_SUCCESS; 
    705634 
    706     /* 
    707      * Get the HGCM function arguments. 
    708      */ 
    709     char *pcchPatterns = NULL, *pchBuf = NULL; 
     635/* 
     636 * Get the HGCM function arguments. 
     637 */ 
     638    char *paszPatterns = NULL, *pchBuf = NULL; 
    710639    uint32_t cchPatterns = 0, cchBuf = 0; 
    711640    LogFlowThisFunc(("\n")); 
     641    AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */ 
    712642    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */ 
    713         || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], 
    714                (const void **) &pcchPatterns, &cchPatterns))  /* patterns */ 
    715         || RT_FAILURE(VBoxHGCMParmPtrGet(&paParms[1],  
    716                (void **) &pchBuf, &cchBuf))  /* return buffer */ 
     643        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* patterns */ 
     644        || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* return buffer */ 
    717645       ) 
    718646        rc = VERR_INVALID_PARAMETER; 
     647    if (RT_SUCCESS(rc)) 
     648        rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &paszPatterns, &cchPatterns); 
    719649    if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN) 
    720650        rc = VERR_TOO_MUCH_DATA; 
    721  
    722     /* 
    723      * First repack the patterns into the format expected by RTStrSimplePatternMatch() 
    724      */ 
     651    if (RT_SUCCESS(rc)) 
     652        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf); 
     653 
     654/* 
     655 * First repack the patterns into the format expected by RTStrSimplePatternMatch() 
     656 */ 
    725657    bool matchAll = false; 
    726658    char pszPatterns[MAX_PATTERN_LEN]; 
    727     if (   (NULL == pcchPatterns) 
     659    if (   (NULL == paszPatterns) 
    728660        || (cchPatterns < 2)  /* An empty pattern string means match all */ 
    729661       ) 
     
    732664    { 
    733665        for (unsigned i = 0; i < cchPatterns - 1; ++i) 
    734             if (pcchPatterns[i] != '\0') 
    735                 pszPatterns[i] = pcchPatterns[i]; 
     666            if (paszPatterns[i] != '\0') 
     667                pszPatterns[i] = paszPatterns[i]; 
    736668            else 
    737669                pszPatterns[i] = '|'; 
     
    739671    } 
    740672 
    741     /* 
    742      * Next enumerate into a temporary buffer.  This can throw, but this is 
    743      * not a problem as we have nothing to roll back. 
    744      */ 
    745     std::string buffer; 
    746     for (PropertyList::const_iterator it = mProperties.begin(); 
    747          RT_SUCCESS(rc) && (it != mProperties.end()); ++it) 
    748     { 
    749         if (   matchAll 
    750             || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 
    751                                             it->mName.c_str(), RTSTR_MAX, NULL) 
     673/* 
     674 * Next enumerate all values in the current node into a temporary buffer. 
     675 */ 
     676    RTMemAutoPtr<char> TmpBuf; 
     677    uint32_t cchTmpBuf = 0, iTmpBuf = 0; 
     678    PCFGMLEAF pLeaf = CFGMR3GetFirstValue(mpValueNode); 
     679    while ((pLeaf != NULL) && RT_SUCCESS(rc)) 
     680    { 
     681        /* Reallocate the buffer if it has got too tight */ 
     682        if (iTmpBuf + BLOCKINCR > cchTmpBuf) 
     683        { 
     684            cchTmpBuf += BLOCKINCR * 2; 
     685            if (!TmpBuf.realloc(cchTmpBuf)) 
     686                rc = VERR_NO_MEMORY; 
     687        } 
     688        /* Fetch the name into the buffer and if it matches one of the 
     689         * patterns, add its value and an empty timestamp and flags.  If it 
     690         * doesn't match, we simply overwrite it in the buffer. */ 
     691        if (RT_SUCCESS(rc)) 
     692            rc = CFGMR3GetValueName(pLeaf, &TmpBuf[iTmpBuf], cchTmpBuf - iTmpBuf); 
     693        /* Only increment the buffer offest if the name matches, otherwise we 
     694         * overwrite it next iteration. */ 
     695        if (   RT_SUCCESS(rc) 
     696            && (   matchAll 
     697                || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, 
     698                                                &TmpBuf[iTmpBuf], RTSTR_MAX, 
     699                                                NULL) 
     700               ) 
    752701           ) 
    753702        { 
    754             char szFlags[MAX_FLAGS_LEN]; 
    755             char szTimestamp[256]; 
    756             size_t cchTimestamp; 
    757             buffer += it->mName; 
    758             buffer += '\0'; 
    759             buffer += it->mValue; 
    760             buffer += '\0'; 
    761             cchTimestamp = RTStrFormatNumber(szTimestamp, it->mTimestamp, 
    762                                              10, 0, 0, 0); 
    763             buffer.append(szTimestamp, cchTimestamp); 
    764             buffer += '\0'; 
    765             rc = writeFlags(it->mFlags, szFlags); 
     703            const char *pszName = &TmpBuf[iTmpBuf]; 
     704            /* Get value */ 
     705            iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 
     706            rc = CFGMR3QueryString(mpValueNode, pszName, &TmpBuf[iTmpBuf], 
     707                                   cchTmpBuf - iTmpBuf); 
    766708            if (RT_SUCCESS(rc)) 
    767                 buffer += szFlags; 
    768             buffer += '\0'; 
     709            { 
     710                /* Get timestamp */ 
     711                iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 
     712                uint64_t u64Timestamp = 0; 
     713                CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp); 
     714                iTmpBuf += RTStrFormatNumber(&TmpBuf[iTmpBuf], u64Timestamp, 
     715                                             10, 0, 0, 0) + 1; 
     716                /* Get flags */ 
     717                uint32_t fFlags = NILFLAG; 
     718                CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); 
     719                TmpBuf[iTmpBuf] = '\0';  /* Bad (== in)sanity, will be fixed. */ 
     720                writeFlags(fFlags, &TmpBuf[iTmpBuf]); 
     721                iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1; 
     722            } 
    769723        } 
    770     } 
    771     buffer.append(4, '\0');  /* The final terminators */ 
    772  
    773     /* 
    774      * Finally write out the temporary buffer to the real one if it is not too 
    775      * small. 
    776      */ 
    777     if (RT_SUCCESS(rc)) 
    778     { 
    779         VBoxHGCMParmUInt32Set(&paParms[2], buffer.size()); 
     724        if (RT_SUCCESS(rc)) 
     725            pLeaf = CFGMR3GetNextValue(pLeaf); 
     726    } 
     727    if (RT_SUCCESS(rc)) 
     728    { 
     729        /* The terminator.  We *do* have space left for this. */ 
     730        TmpBuf[iTmpBuf] = '\0'; 
     731        TmpBuf[iTmpBuf + 1] = '\0'; 
     732        TmpBuf[iTmpBuf + 2] = '\0'; 
     733        TmpBuf[iTmpBuf + 3] = '\0'; 
     734        iTmpBuf += 4; 
     735        VBoxHGCMParmUInt32Set(&paParms[2], iTmpBuf); 
    780736        /* Copy the memory if it fits into the guest buffer */ 
    781         if (buffer.size() <= cchBuf) 
    782             buffer.copy(pchBuf, cchBuf); 
     737        if (iTmpBuf <= cchBuf) 
     738            memcpy(pchBuf, TmpBuf.get(), iTmpBuf); 
    783739        else 
    784740            rc = VERR_BUFFER_OVERFLOW; 
     
    797753void Service::notifyHost(const char *pszProperty) 
    798754{ 
    799 #ifndef VBOX_GUEST_PROP_TEST_NOTHREAD 
     755    char szValue[MAX_VALUE_LEN]; 
     756    uint64_t u64Timestamp = 0; 
     757    uint32_t fFlags = NILFLAG; 
    800758    char szFlags[MAX_FLAGS_LEN]; 
    801759    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL; 
    802     int rc = VINF_SUCCESS; 
    803  
     760 
     761    AssertPtr(mpValueNode); 
    804762    if (NULL == mpfnHostCallback) 
    805763        return;  /* Nothing to do. */ 
    806     PropertyList::const_iterator it; 
    807     bool found = false; 
    808     if (RT_SUCCESS(rc)) 
    809         for (it = mProperties.begin(); it != mProperties.end(); ++it) 
    810             if (it->mName.compare(pszProperty) == 0) 
    811             { 
    812                 found = true; 
    813                 break; 
    814             } 
     764    int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue, 
     765                               sizeof(szValue)); 
    815766    /* 
    816767     * First case: if the property exists then send the host its current value 
    817768     */ 
    818     if (found) 
    819     { 
    820         rc = writeFlags(it->mFlags, szFlags); 
     769    if (rc != VERR_CFGM_VALUE_NOT_FOUND) 
     770    { 
     771        if (RT_SUCCESS(rc)) 
     772            rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp); 
     773        if (RT_SUCCESS(rc)) 
     774            rc = CFGMR3QueryU32(mpFlagsNode, pszProperty, &fFlags); 
     775        if (RT_SUCCESS(rc)) 
     776            rc = writeFlags(fFlags, szFlags); 
    821777        if (RT_SUCCESS(rc)) 
    822778            rc = RTStrDupEx(&pszName, pszProperty); 
    823779        if (RT_SUCCESS(rc)) 
    824             rc = RTStrDupEx(&pszValue, it->mValue.c_str()); 
     780            rc = RTStrDupEx(&pszValue, szValue); 
    825781        if (RT_SUCCESS(rc)) 
    826782            rc = RTStrDupEx(&pszFlags, szFlags); 
     
    829785                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback, 
    830786                             mpvHostData, pszName, pszValue, 
    831                              (uint32_t) RT_HIDWORD(it->mTimestamp), 
    832                              (uint32_t) RT_LODWORD(it->mTimestamp), pszFlags); 
     787                             (uint32_t) RT_HIDWORD(u64Timestamp), 
     788                             (uint32_t) RT_LODWORD(u64Timestamp), pszFlags); 
    &n