Index: trunk/include/VBox/HostServices/GuestPropertySvc.h
===================================================================
--- trunk/include/VBox/HostServices/GuestPropertySvc.h	(revision 13558)
+++ trunk/include/VBox/HostServices/GuestPropertySvc.h	(revision 13574)
@@ -65,40 +65,56 @@
 enum ePropFlags
 {
-    NILFLAG    = 0,
-    TRANSIENT  = RT_BIT(1),
-    HOSTWRITE  = RT_BIT(2),
-    GUESTWRITE = RT_BIT(3),
-    READONLY   = RT_BIT(4)
+    NILFLAG     = 0,
+    TRANSIENT   = RT_BIT(1),
+    RDONLYGUEST = RT_BIT(2),
+    RDONLYHOST  = RT_BIT(3),
+    READONLY    = RDONLYGUEST | RDONLYHOST,
+    ALLFLAGS    = TRANSIENT | READONLY
 };
 
 /**
- * A structure to map the guest property flag values to names. I know it is
- * ugly to have constants inline, but it has to be accessible in different
- * modules and it does not seem reasonable to put it into its own library.
- */
-const struct
-{
-    /** The flag value */
-    uint32_t fFlag;
-    /** And the name of the flag */
-    const char *pcszName;
-} flagNames[] =
-{
-    { TRANSIENT,  "TRANSIENT" },
-    { HOSTWRITE,  "HOSTWRITE" },
-    { GUESTWRITE, "GUESTWRITE" },
-    { READONLY,   "READONLY" },
-    { NILFLAG,    NULL }
-};
-
-/** Maximum length for the property flags field */
-enum { MAX_FLAGS_LEN =   sizeof(flagNames[0]) + 2  /* + 2 for ", " */
-                       + sizeof(flagNames[1]) + 2
-                       + sizeof(flagNames[2]) + 2
-                       + sizeof(flagNames[3]) + 1  /* + 1 for '\0' */
-     };
-
-/**
- * Parse a guest properties flags string for the flags in flagNames.
+ * Get the name of a flag as a string.
+ * @returns the name, or NULL if fFlag is invalid.
+ * @param   fFlag  the flag.  Must be a value from the ePropFlags enumeration
+ *                 list.
+ */
+DECLINLINE(const char *) flagName(uint32_t fFlag)
+{
+    switch(fFlag)
+    {
+        case TRANSIENT:
+            return "TRANSIENT";
+        case RDONLYGUEST:
+            return "RDONLYGUEST";
+        case RDONLYHOST:
+            return "RDONLYHOST";
+        case READONLY:
+            return "READONLY";
+        default:
+            return NULL;
+    }
+}
+
+/**
+ * Get the length of a flag name as returned by flagName.
+ * @returns the length, or 0 if fFlag is invalid.
+ * @param   fFlag  the flag.  Must be a value from the ePropFlags enumeration
+ *                 list.
+ */
+DECLINLINE(size_t) flagNameLen(uint32_t fFlag)
+{
+    const char *pcszName = flagName(fFlag);
+    return RT_LIKELY(pcszName != NULL) ? strlen(pcszName) : 0;
+}
+
+/**
+ * Maximum length for the property flags field.  We only ever return one of
+ * RDONLYGUEST, RDONLYHOST and RDONLY
+ */
+enum { MAX_FLAGS_LEN =   sizeof("TRANSIENT, RDONLYGUEST") };
+
+/**
+ * Parse a guest properties flags string for flag names and make sure that
+ * there is no junk text in the string.
  * @returns  IPRT status code
  * @returns  VERR_INVALID_PARAM if the flag string is not valid
@@ -111,4 +127,8 @@
 DECLINLINE(int) validateFlags(const char *pcszFlags, uint32_t *pfFlags)
 {
+    static uint32_t flagList[] =
+    {
+        TRANSIENT, READONLY, RDONLYGUEST, RDONLYHOST
+    };
     const char *pcszNext = pcszFlags;
     int rc = VINF_SUCCESS;
@@ -120,22 +140,24 @@
     while ((*pcszNext != '\0') && RT_SUCCESS(rc))
     {
-        int i = 0;
-        for (; flagNames[i].fFlag != NILFLAG; ++i)
-            if (strncasecmp(pcszNext, flagNames[i].pcszName,
-                            strlen(flagNames[i].pcszName)) == 0)
+        unsigned i = 0;
+        for (; i < RT_ELEMENTS(flagList); ++i)
+            if (strncasecmp(pcszNext, flagName(flagList[i]),
+                            flagNameLen(flagList[i])
+                           ) == 0
+               )
                 break;
-        if (NILFLAG == flagNames[i].fFlag)
-            rc = VERR_INVALID_PARAMETER;
+        if (RT_ELEMENTS(flagList) == i)
+             rc = VERR_INVALID_PARAMETER;
         else
         {
-            fFlags |= flagNames[i].fFlag;
-            pcszNext += strlen(flagNames[i].pcszName);
+            fFlags |= flagList[i];
+            pcszNext += flagNameLen(flagList[i]);
+            while (' ' == *pcszNext)
+                ++pcszNext;
+            if (',' == *pcszNext)
+                ++pcszNext;
+            while (' ' == *pcszNext)
+                ++pcszNext;
         }
-        while (' ' == *pcszNext)
-            ++pcszNext;
-        if (',' == *pcszNext)
-            ++pcszNext;
-        while (' ' == *pcszNext)
-            ++pcszNext;
     }
     if (RT_SUCCESS(rc))
@@ -149,29 +171,38 @@
  * @param    fFlags    the flags to write out
  * @param    pszFlags  where to write the flags string.  This must point to
- *                     a buffer of size (at least) MAX_FLAGS_LEN + 1.
+ *                     a buffer of size (at least) MAX_FLAGS_LEN.
  */
 DECLINLINE(int) writeFlags(uint32_t fFlags, char *pszFlags)
 {
+    static uint32_t flagList[] =
+    {
+        TRANSIENT, READONLY, RDONLYGUEST, RDONLYHOST
+    };
     char *pszNext = pszFlags;
     int rc = VINF_SUCCESS;
     AssertLogRelReturn(VALID_PTR(pszFlags), VERR_INVALID_POINTER);
-    int i = 0;
-    for (; flagNames[i].fFlag != NILFLAG; ++i)
+    if ((fFlags & ~ALLFLAGS) != NILFLAG)
+        rc = VERR_INVALID_PARAMETER;
+    if (RT_SUCCESS(rc))
     {
-        if (fFlags & flagNames[i].fFlag)
+        unsigned i = 0;
+        for (; i < RT_ELEMENTS(flagList); ++i)
         {
-            strcpy(pszNext, flagNames[i].pcszName);
-            pszNext += strlen(flagNames[i].pcszName);
-            fFlags &= ~flagNames[i].fFlag;
-            if ((flagNames[i + 1].fFlag != NILFLAG) && (fFlags != NILFLAG))
+            if (fFlags & flagList[i])
             {
-                strcpy(pszNext, ", ");
-                pszNext += 2;
+                strcpy(pszNext, flagName(flagList[i]));
+                pszNext += flagNameLen(flagList[i]);
+                fFlags &= ~flagList[i];
+                if (fFlags != NILFLAG)
+                {
+                    strcpy(pszNext, ", ");
+                    pszNext += 2;
+                }
             }
         }
+        *pszNext = '\0';
+        if (fFlags != NILFLAG)
+            rc = VERR_INVALID_PARAMETER;  /* But pszFlags will still be set right. */
     }
-    *pszNext = '\0';
-    if (fFlags != NILFLAG)
-        rc = VERR_INVALID_PARAMETER;  /* But pszFlags will still be set right. */
     return rc;
 }
