Index: /trunk/include/VBox/VBoxGuestLib.h
===================================================================
--- /trunk/include/VBox/VBoxGuestLib.h	(revision 75406)
+++ /trunk/include/VBox/VBoxGuestLib.h	(revision 75407)
@@ -682,7 +682,13 @@
                                                   PVBGLR3SHAREDFOLDERMAPPING *ppaMappings, uint32_t *pcMappings);
 VBGLR3DECL(void)    VbglR3SharedFolderFreeMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings);
-VBGLR3DECL(int)     VbglR3SharedFolderGetName(HGCMCLIENTID  idClient,uint32_t u32Root, char **ppszName);
-VBGLR3DECL(int)     VbglR3SharedFolderGetMountPrefix(char **ppszPrefix);
-VBGLR3DECL(int)     VbglR3SharedFolderGetMountDir(char **ppszDir);
+VBGLR3DECL(int)     VbglR3SharedFolderGetName(HGCMCLIENTID  idClient,uint32_t u32Root, char **ppszName); /**< @todo r=bird: GET functions return the value, not a status code!*/
+VBGLR3DECL(int)     VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags,
+                                                      char **ppszName, char **ppszMountPoint,
+                                                      uint64_t *pfFlags, uint32_t *puRootIdVersion);
+VBGLR3DECL(int)     VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion);
+VBGLR3DECL(int)     VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient);
+
+VBGLR3DECL(int)     VbglR3SharedFolderGetMountPrefix(char **ppszPrefix); /**< @todo r=bird: GET functions return the value, not a status code! */
+VBGLR3DECL(int)     VbglR3SharedFolderGetMountDir(char **ppszDir);       /**< @todo r=bird: GET functions return the value, not a status code! */
 /** @}  */
 # endif /* VBOX_WITH_SHARED_FOLDERS defined */
Index: /trunk/include/VBox/shflsvc.h
===================================================================
--- /trunk/include/VBox/shflsvc.h	(revision 75406)
+++ /trunk/include/VBox/shflsvc.h	(revision 75407)
@@ -77,7 +77,10 @@
  * @{
  */
-/** Query mappings changes. */
+/** Query mappings changes.
+ * @note Description is currently misleading, it will always return all
+ *       current mappings with SHFL_MS_NEW status.  Only modification is the
+ *       SHFL_MF_AUTOMOUNT flag that causes filtering out non-auto mounts. */
 #define SHFL_FN_QUERY_MAPPINGS      (1)
-/** Query mappings changes. */
+/** Query the name of a map. */
 #define SHFL_FN_QUERY_MAP_NAME      (2)
 /** Open/create object. */
@@ -118,4 +121,14 @@
  * @since VBox 4.0  */
 #define SHFL_FN_SET_SYMLINKS        (20)
+/** Query information about a map.
+ * @since VBox 6.0  */
+#define SHFL_FN_QUERY_MAP_INFO      (21)
+/** Wait for changes to the mappings.
+ * @since VBox 6.0  */
+#define SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES       (22)
+/** Cancel all waits for changes to the mappings for the calling client.
+ * The wait calls will return VERR_CANCELLED.
+ * @since VBox 6.0  */
+#define SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS   (23)
 /** @} */
 
@@ -240,15 +253,28 @@
  * Helper for copying one string into another.
  *
- * @returns pDst
- * @param   pDst        The destination string. Assumed to be the same size as
- *                      the source.
+ * @returns IPRT status code.
+ * @retval  VERR_BUFFER_OVERFLOW and pDst->u16Length set to source length.
+ * @param   pDst        The destination string.
  * @param   pSrc        The source string.
- */
-DECLINLINE(PSHFLSTRING) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
-{
+ * @param   cbTerm      The size of the string terminator.
+ */
+DECLINLINE(int) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc, size_t cbTerm)
+{
+    int rc = VINF_SUCCESS;
+    if (pDst->u16Size >= pSrc->u16Length + cbTerm)
+    {
+        memcpy(&pDst->String, &pSrc->String, pSrc->u16Length);
+        switch (cbTerm)
+        {
+            default:
+            case 2: pDst->String.ach[pSrc->u16Length + 1] = '\0'; RT_FALL_THROUGH();
+            case 1: pDst->String.ach[pSrc->u16Length + 0] = '\0'; break;
+            case 0: break;
+        }
+    }
+    else
+        rc = VERR_BUFFER_OVERFLOW;
     pDst->u16Length = pSrc->u16Length;
-    pDst->u16Size   = pSrc->u16Size;
-    memcpy(&pDst->String, &pSrc->String, pSrc->u16Size);
-    return pDst;
+    return rc;
 }
 
@@ -265,5 +291,9 @@
     PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Size);
     if (pDst)
-        return ShflStringCopy(pDst, pSrc);
+    {
+        pDst->u16Length = pSrc->u16Length;
+        pDst->u16Size   = pSrc->u16Size;
+        memcpy(&pDst->String, &pSrc->String, pSrc->u16Size);
+    }
     return pDst;
 }
@@ -355,4 +385,80 @@
     AssertMsgFailed(("rc=%Rrc cwcConversion=%#x\n", rc, cwcConversion));
     return NULL;
+}
+
+/**
+ * Copies a UTF-8 string to a buffer as UTF-16.
+ *
+ * @returns IPRT status code.
+ * @param   pDst        The destination buffer.
+ * @param   pszSrc      The source string.
+ * @param   cchSrc      The source string length, or RTSTR_MAX.
+ */
+DECLINLINE(int) ShflStringCopyUtf8AsUtf16(PSHFLSTRING pDst, const char *pszSrc, size_t cchSrc)
+{
+    int rc;
+    size_t cwcDst = 0;
+    if (pDst->u16Size >= sizeof(RTUTF16))
+    {
+        PRTUTF16 pwszDst = pDst->String.utf16;
+        rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, pDst->u16Size / sizeof(RTUTF16), &cwcDst);
+    }
+    else
+    {
+        RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcDst);
+        rc = VERR_BUFFER_OVERFLOW;
+    }
+    pDst->u16Length = (uint16_t)(cwcDst * sizeof(RTUTF16));
+    return rc != VERR_BUFFER_OVERFLOW || cwcDst < UINT16_MAX / sizeof(RTUTF16) ? rc : VERR_TOO_MUCH_DATA;
+}
+
+/**
+ * Copies a UTF-8 string buffer to another buffer as UTF-16
+ *
+ * @returns IPRT status code.
+ * @param   pDst        The destination buffer (UTF-16).
+ * @param   pSrc        The source buffer (UTF-8).
+ */
+DECLINLINE(int) ShflStringCopyUtf8BufAsUtf16(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
+{
+    return ShflStringCopyUtf8AsUtf16(pDst, pSrc->String.ach, pSrc->u16Length);
+}
+
+/**
+ * Copies a UTF-16 string to a buffer as UTF-8
+ *
+ * @returns IPRT status code.
+ * @param   pDst        The destination buffer.
+ * @param   pwszSrc     The source string.
+ * @param   cwcSrc      The source string length, or RTSTR_MAX.
+ */
+DECLINLINE(int) ShflStringCopyUtf16AsUtf8(PSHFLSTRING pDst, PCRTUTF16 pwszSrc, size_t cwcSrc)
+{
+    int rc;
+    size_t cchDst = 0;
+    if (pDst->u16Size > 0)
+    {
+        char *pszDst = pDst->String.ach;
+        rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, pDst->u16Size, &cchDst);
+    }
+    else
+    {
+        RTUtf16CalcUtf8LenEx(pwszSrc, cwcSrc, &cchDst);
+        rc = VERR_BUFFER_OVERFLOW;
+    }
+    pDst->u16Length = (uint16_t)cchDst;
+    return rc != VERR_BUFFER_OVERFLOW || cchDst < UINT16_MAX ? rc : VERR_TOO_MUCH_DATA;
+}
+
+/**
+ * Copies a UTF-16 string buffer to another buffer as UTF-8
+ *
+ * @returns IPRT status code.
+ * @param   pDst        The destination buffer (UTF-8).
+ * @param   pSrc        The source buffer (UTF-16).
+ */
+DECLINLINE(int) ShflStringCopyUtf16BufAsUtf8(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
+{
+    return ShflStringCopyUtf16AsUtf8(pDst, pSrc->String.utf16, pSrc->u16Length / sizeof(RTUTF16));
 }
 
@@ -802,5 +908,6 @@
 typedef struct _SHFLMAPPING
 {
-    /** Mapping status. */
+    /** Mapping status.
+     * @note Currently always set to SHFL_MS_NEW.  */
     uint32_t u32Status;
     /** Root handle. */
@@ -1558,4 +1665,74 @@
 
 
+/** @name SHFL_FN_QUERY_MAP_INFO
+ * @{
+ */
+/** Query flag: Guest prefers drive letters as mount points. */
+#define SHFL_MIQF_DRIVE_LETTER      RT_BIT_64(0)
+/** Query flag: Guest prefers paths as mount points. */
+#define SHFL_MIQF_PATH              RT_BIT_64(1)
+
+/** Set if writable. */
+#define SHFL_MIF_WRITABLE           RT_BIT_64(0)
+/** Indicates that the mapping should be auto-mounted. */
+#define SHFL_MIF_AUTO_MOUNT         RT_BIT_64(1)
+/** Set if host is case insensitive. */
+#define SHFL_MIF_HOST_ICASE         RT_BIT_64(2)
+/** Set if guest is case insensitive. */
+#define SHFL_MIF_GUEST_ICASE        RT_BIT_64(3)
+/** Symbolic link creation is allowed. */
+#define SHFL_MIF_SYMLINK_CREATION   RT_BIT_64(4)
+
+/** Parameters structure. */
+typedef struct VBoxSFQueryMapInfo
+{
+    /** Common header. */
+    VBGLIOCHGCMCALL callInfo;
+    /** 32-bit, in: SHFLROOT - root handle of the mapping to query. */
+    HGCMFunctionParameter root;
+    /** pointer, in/out: SHFLSTRING buffer for the name. */
+    HGCMFunctionParameter name;
+    /** pointer, in/out: SHFLSTRING buffer for the auto mount point. */
+    HGCMFunctionParameter mountPoint;
+    /** 64-bit, in: SHFL_MIQF_XXX; out: SHFL_MIF_XXX. */
+    HGCMFunctionParameter flags;
+    /** 32-bit, out: Root ID version number - root handle reuse guard. */
+    HGCMFunctionParameter rootIdVersion;
+} VBoxSFQueryMapInfo;
+/** Number of parameters */
+#define SHFL_CPARMS_QUERY_MAP_INFO (5)
+/** @} */
+
+
+/** @name SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES
+ *
+ * Returns VINF_SUCCESS on change and VINF_TRY_AGAIN when restored from saved
+ * state.  If the guest makes too many calls (max 64) VERR_OUT_OF_RESOURCES will
+ * be returned.
+ *
+ * @{
+ */
+/** Parameters structure. */
+typedef struct VBoxSFWaitForMappingsChanges
+{
+    /** Common header. */
+    VBGLIOCHGCMCALL callInfo;
+    /** 32-bit, in/out: The mappings configuration version.
+     * On input the client sets it to the last config it knows about, on return
+     * it holds the current version.  */
+    HGCMFunctionParameter version;
+} VBoxSFWaitForMappingsChanges;
+/** Number of parameters */
+#define SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES       (1)
+/** @} */
+
+
+/** @name SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS
+ * @{
+ */
+/** Number of parameters */
+#define SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS   (0)
+/** @} */
+
 
 /** @name SHFL_FN_ADD_MAPPING
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 75406)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 75407)
@@ -65,11 +65,12 @@
 	VBoxLA.cpp
 endif
-ifdef VBOX_WITH_SHARED_FOLDERS
- VBoxTray_DEFS     += VBOX_WITH_SHARED_FOLDERS
- VBoxTray_SOURCES  += \
-	VBoxSharedFolders.cpp
- VBoxTray_LIBS.win += \
-	mpr.lib
-endif
+## Now handled by VBoxService.
+#ifdef VBOX_WITH_SHARED_FOLDERS
+# VBoxTray_DEFS     += VBOX_WITH_SHARED_FOLDERS
+# VBoxTray_SOURCES  += \
+#	VBoxSharedFolders.cpp
+# VBoxTray_LIBS.win += \
+#	mpr.lib
+#endif
 ifdef VBOX_WITH_WDDM
  VBoxTray_DEFS   += VBOX_WITH_WDDM
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp	(revision 75406)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp	(revision 75407)
@@ -31,5 +31,7 @@
 #include "VBoxVRDP.h"
 #include "VBoxHostVersion.h"
-#include "VBoxSharedFolders.h"
+#ifdef VBOX_WITH_SHARED_FOLDERS
+# include "VBoxSharedFolders.h"
+#endif
 #ifdef VBOX_WITH_DRAG_AND_DROP
 # include "VBoxDnD.h"
@@ -825,6 +827,8 @@
             if (RT_SUCCESS(rc))
             {
+#ifdef VBOX_WITH_SHARED_FOLDERS
                 /* Do the Shared Folders auto-mounting stuff. */
                 rc = VBoxSharedFoldersAutoMount();
+#endif
                 if (RT_SUCCESS(rc))
                 {
Index: /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibSharedFolders.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibSharedFolders.cpp	(revision 75406)
+++ /trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibSharedFolders.cpp	(revision 75407)
@@ -161,5 +161,5 @@
             }
         }
-    } while (rc == VINF_BUFFER_OVERFLOW);
+    } while (rc == VINF_BUFFER_OVERFLOW); /** @todo r=bird: This won't happen because the weird host code never returns it. */
 
     if (   RT_FAILURE(rc)
@@ -211,5 +211,5 @@
 
     int         rc;
-    uint32_t    cbString = SHFLSTRING_HEADER_SIZE + SHFL_MAX_LEN;
+    uint32_t    cbString = SHFLSTRING_HEADER_SIZE + SHFL_MAX_LEN * sizeof(RTUTF16);
     PSHFLSTRING pString = (PSHFLSTRING)RTMemAlloc(cbString);
     if (pString)
@@ -233,7 +233,133 @@
     }
     else
-        rc = VERR_INVALID_PARAMETER;
-    return rc;
-}
+        rc = VERR_NO_MEMORY;
+    return rc;
+}
+
+
+/**
+ * Queries information about a shared folder.
+ *
+ * @returns VBox status code.
+ *
+ * @param   idClient        The client ID.
+ * @param   idRoot          The root ID of the folder to query information for.
+ * @param   fQueryFlags     SHFL_MIQF_XXX.
+ * @param   ppszName        Where to return the pointer to the name.
+ *                          Free using RTStrFree.  Optional.
+ * @param   ppszMountPoint  Where to return the pointer to the auto mount point.
+ *                          Free using RTStrFree.  Optional.
+ * @param   pfFlags         Where to return the flags (SHFL_MIF_XXX).  Optional.
+ * @param   puRootIdVersion where to return the root ID version.  Optional.
+ *                          This helps detecting root-id reuse.
+ *
+ * @remarks ASSUMES UTF-16 connection to host.
+ */
+VBGLR3DECL(int) VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags,
+                                                  char **ppszName, char **ppszMountPoint,
+                                                  uint64_t *pfFlags, uint32_t *puRootIdVersion)
+{
+    AssertReturn(!(fQueryFlags & ~(SHFL_MIQF_DRIVE_LETTER | SHFL_MIQF_PATH), VERR_INVALID_FLAGS);
+
+    /*
+     * Allocate string buffers first.
+     */
+    int rc;
+    PSHFLSTRING pNameBuf    = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (SHFL_MAX_LEN + 1) * sizeof(RTUTF16));
+    PSHFLSTRING pMountPoint = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (260          + 1) * sizeof(RTUTF16));
+    if (pNameBuf && pMountPoint)
+    {
+        ShflStringInitBuffer(pNameBuf,    SHFLSTRING_HEADER_SIZE + (SHFL_MAX_LEN + 1) * sizeof(RTUTF16));
+        ShflStringInitBuffer(pMountPoint, SHFLSTRING_HEADER_SIZE + (260          + 1) * sizeof(RTUTF16));
+
+        /*
+         * Make the call.
+         */
+        VBoxSFQueryMapInfo Msg;
+        VBGL_HGCM_HDR_INIT(&Msg.callInfo, idClient, SHFL_FN_QUERY_MAP_INFO, 5);
+        VbglHGCMParmUInt32Set(&Msg.root, idRoot);
+        VbglHGCMParmPtrSet(&Msg.name, pNameBuf, SHFLSTRING_HEADER_SIZE + pNameBuf->u16Size);
+        VbglHGCMParmPtrSet(&Msg.mountPoint, pMountPoint, SHFLSTRING_HEADER_SIZE + pMountPoint->u16Size);
+        VbglHGCMParmUInt64Set(&Msg.flags, fQueryFlags);
+        VbglHGCMParmUInt32Set(&Msg.rootIdVersion, 0);
+
+        rc = VbglR3HGCMCall(&Msg.callInfo, sizeof(Msg));
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Copy out the results.
+             */
+            if (puRootIdVersion)
+                *puRootIdVersion = Msg.rootIdVersion.u.value64;
+
+            if (pfFlags)
+                *pfFlags = Msg.flags.u.value64;
+
+            if (ppszName)
+            {
+                *ppszName = NULL;
+                rc = RTUtf16ToUtf8Ex(pNameBuf->String.utf16, pNameBuf->u16Length / sizeof(RTUTF16), ppszName, 0, NULL);
+            }
+
+            if (ppszMountPoint && RT_SUCCESS(rc))
+            {
+                *ppszMountPoint = NULL;
+                rc = RTUtf16ToUtf8Ex(pMountPoint->String.utf16, pMountPoint->u16Length / sizeof(RTUTF16), ppszMountPoint, 0, NULL);
+                if (RT_FAILURE(rc) && ppszName)
+                {
+                    RTStrFree(*ppszName);
+                    *ppszName = NULL;
+                }
+            }
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+    RTMemFree(pMountPoint);
+    RTMemFree(pNameBuf);
+    return rc;
+}
+
+
+/**
+ * Waits for changes to the mappings (add, remove, restore).
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on change
+ * @retval  VINF_TRY_AGAIN on restore.
+ * @retval  VERR_OUT_OF_RESOURCES if there are too many guys waiting.
+ *
+ * @param   idClient        The client ID.
+ * @param   uPrevVersion    The mappings config version number returned the last
+ *                          time around.  Use UINT32_MAX for the first call.
+ * @param   puCurVersion    Where to return the current mappings config version.
+ */
+VBGLR3DECL(int) VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion)
+{
+    VBoxSFWaitForMappingsChanges Msg;
+    VBGL_HGCM_HDR_INIT(&Msg.callInfo, idClient, SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES, 1);
+    VbglHGCMParmUInt32Set(&Msg.version, uPrevVersion);
+
+    int rc = VbglR3HGCMCall(&Msg.callInfo, sizeof(Msg));
+
+    *puCurVersion = Msg.version.u.value32;
+    return rc;
+}
+
+
+/**
+ * Cancels all threads currently waiting for changes for this client.
+ *
+ * @returns VBox status code.
+ * @param   idClient        The client ID.
+ */
+VBGLR3DECL(int) VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient)
+{
+    VBGLIOCHGCMCALL CallInfo;
+    VBGL_HGCM_HDR_INIT(&CallInfo, idClient, SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS, 0);
+
+    return VbglR3HGCMCall(&CallInfo, sizeof(CallInfo));
+}
+
 
 /**
@@ -258,4 +384,5 @@
         {
 #endif
+/** @todo r=bird: Inconsistent! VbglR3SharedFolderGetMountDir does not return a default. */
             rc = RTStrDupEx(ppszPrefix, "sf_");
 #ifdef VBOX_WITH_GUEST_PROPS
@@ -266,4 +393,5 @@
     return rc;
 }
+
 
 /**
Index: /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk	(revision 75406)
+++ /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk	(revision 75407)
@@ -40,19 +40,19 @@
 if1of ($(KBUILD_TARGET), linux)
  # CPU hotplugging.
- VBOX_WITH_VBOXSERVICE_CPUHOTPLUG   := 1
-endif
-
+VBOX_WITH_VBOXSERVICE_CPUHOTPLUG    := 1
+endif
+
+# Page Sharing (Page Fusion).
 if1of ($(KBUILD_TARGET), win)
- # Page Sharing (Page Fusion).
- VBOX_WITH_VBOXSERVICE_PAGE_SHARING := 1
+VBOX_WITH_VBOXSERVICE_PAGE_SHARING  := 1
 endif
 
 ifdef VBOX_WITH_GUEST_PROPS
- VBOX_WITH_VBOXSERVICE_VMINFO       := 1
-endif
-
+VBOX_WITH_VBOXSERVICE_VMINFO        := 1
+endif
+
+# Guest Control.
 ifdef VBOX_WITH_GUEST_CONTROL
- # Guest Control.
- VBOX_WITH_VBOXSERVICE_CONTROL      := 1
+VBOX_WITH_VBOXSERVICE_CONTROL       := 1
 endif
 
@@ -68,17 +68,17 @@
 # Define features to be activate.
 VBoxService_DEFS         += \
-	$(if $(VBOX_WITH_VBOXSERVICE_CONTROL),VBOX_WITH_VBOXSERVICE_CONTROL,)           \
-	$(if $(VBOX_WITH_VBOXSERVICE_CPUHOTPLUG),VBOX_WITH_VBOXSERVICE_CPUHOTPLUG,)     \
-	$(if $(VBOX_WITH_VBOXSERVICE_MANAGEMENT),VBOX_WITH_VBOXSERVICE_MANAGEMENT,)     \
+	$(if $(VBOX_WITH_VBOXSERVICE_CONTROL),VBOX_WITH_VBOXSERVICE_CONTROL,) \
+	$(if $(VBOX_WITH_VBOXSERVICE_CPUHOTPLUG),VBOX_WITH_VBOXSERVICE_CPUHOTPLUG,) \
+	$(if $(VBOX_WITH_VBOXSERVICE_MANAGEMENT),VBOX_WITH_VBOXSERVICE_MANAGEMENT,) \
 	$(if $(VBOX_WITH_VBOXSERVICE_PAGE_SHARING),VBOX_WITH_VBOXSERVICE_PAGE_SHARING,) \
-	$(if $(VBOX_WITH_VBOXSERVICE_TIMESYNC),VBOX_WITH_VBOXSERVICE_TIMESYNC,)         \
-	$(if $(VBOX_WITH_VBOXSERVICE_TOOLBOX),VBOX_WITH_VBOXSERVICE_TOOLBOX,)           \
+	$(if $(VBOX_WITH_VBOXSERVICE_TIMESYNC),VBOX_WITH_VBOXSERVICE_TIMESYNC,) \
+	$(if $(VBOX_WITH_VBOXSERVICE_TOOLBOX),VBOX_WITH_VBOXSERVICE_TOOLBOX,) \
 	$(if $(VBOX_WITH_VBOXSERVICE_VMINFO),VBOX_WITH_VBOXSERVICE_VMINFO,)
 
 # Import global defines.
-VBoxService_DEFS         +=                                       \
-	$(if $(VBOX_WITH_DBUS),VBOX_WITH_DBUS,)                   \
+VBoxService_DEFS         += \
+	$(if $(VBOX_WITH_DBUS),VBOX_WITH_DBUS,) \
 	$(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,) \
-	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,)     \
+	$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
 	$(if $(VBOX_WITH_HGCM),VBOX_WITH_HGCM,)
 
@@ -88,29 +88,22 @@
 VBoxService_DEFS.os2      = VBOX_WITH_HGCM VBOX_WITH_VBOXSERVICE_CLIPBOARD
 
-ifdef VBOX_WITH_SHARED_FOLDERS
- # darwin freebsd
- if1of ($(KBUILD_TARGET), linux solaris)
-  VBoxService_DEFS       += VBOX_WITH_SHARED_FOLDERS
- endif
-endif
-
-VBoxService_SOURCES       =  \
-	VBoxService.cpp      \
+VBoxService_SOURCES       = \
+	VBoxService.cpp \
 	VBoxServiceUtils.cpp \
 	VBoxServiceStats.cpp
 
 ifdef VBOX_WITH_VBOXSERVICE_TIMESYNC
- VBoxService_SOURCES     += \
+VBoxService_SOURCES      += \
 	VBoxServiceTimeSync.cpp
 endif
 
 ifdef VBOX_WITH_VBOXSERVICE_TOOLBOX
- VBoxService_SOURCES     += \
+VBoxService_SOURCES      += \
 	VBoxServiceToolBox.cpp
 endif
 
 ifdef VBOX_WITH_VBOXSERVICE_CONTROL
- VBoxService_SOURCES     +=       \
- 	VBoxServiceControl.cpp        \
+VBoxService_SOURCES      += \
+	VBoxServiceControl.cpp  \
 	VBoxServiceControlProcess.cpp \
 	VBoxServiceControlSession.cpp
@@ -118,33 +111,38 @@
 
 ifdef VBOX_WITH_VBOXSERVICE_MANAGEMENT
- VBoxService_SOURCES     += \
- 	VBoxServiceBalloon.cpp
- VBoxService_DEFS        += $(if $(VBOX_WITH_MEMBALLOON),VBOX_WITH_MEMBALLOON,)
+VBoxService_SOURCES      += \
+	VBoxServiceBalloon.cpp
+ ifdef VBOX_WITH_MEMBALLOON
+VBoxService_DEFS         += VBOX_WITH_MEMBALLOON
+ endif
 endif
 
 if1of ($(KBUILD_TARGET), win)
- VBoxService_SOURCES    += \
+VBoxService_SOURCES      += \
  	VBoxServicePageSharing.cpp
 endif
 
 ifdef VBOX_WITH_VBOXSERVICE_VMINFO
- VBoxService_SOURCES.win += \
+VBoxService_SOURCES.win  += \
  	VBoxServiceVMInfo-win.cpp
- VBoxService_SOURCES     +=  \
- 	VBoxServiceVMInfo.cpp    \
- 	VBoxServicePropCache.cpp
+VBoxService_SOURCES      += \
+	VBoxServiceVMInfo.cpp \
+	VBoxServicePropCache.cpp
 endif
 
 ifdef VBOX_WITH_VBOXSERVICE_CPUHOTPLUG
- VBoxService_SOURCES     += \
+VBoxService_SOURCES      += \
 	VBoxServiceCpuHotPlug.cpp
 endif
 
 ifdef VBOX_WITH_SHARED_FOLDERS
- if1of ($(KBUILD_TARGET), linux solaris)
-  VBoxService_SOURCES          += \
+ if1of ($(KBUILD_TARGET), win linux solaris)
+VBoxService_DEFS         += VBOX_WITH_SHARED_FOLDERS
+VBoxService_SOURCES      += \
 	VBoxServiceAutoMount.cpp
-  VBoxService_SOURCES.linux    += \
+VBoxService_SOURCES.linux += \
 	../../linux/sharedfolders/vbsfmount.c
+VBoxService_LIBS.win     += \
+	Mpr.Lib
  endif
 endif
@@ -160,5 +158,5 @@
 VBoxService_LDFLAGS.darwin = -framework IOKit
 
-VBoxService_LIBS        += \
+VBoxService_LIBS         += \
 	$(VBOX_LIB_IPRT_GUEST_R3) \
 	$(VBOX_LIB_VBGL_R3) \
@@ -170,15 +168,15 @@
 ifdef VBOX_WITH_DBUS
  if1of ($(KBUILD_TARGET), linux solaris) # FreeBSD?
-  VBoxService_LIBS       += \
+VBoxService_LIBS         += \
 	dl
  endif
 endif
 ifdef VBOX_WITH_GUEST_PROPS
- VBoxService_LIBS.win    += \
- 	Secur32.lib \
- 	WtsApi32.lib \
- 	Psapi.lib
- VBoxService_LIBS.solaris += \
- 	nsl \
+VBoxService_LIBS.win     += \
+	Secur32.lib \
+	WtsApi32.lib \
+	Psapi.lib
+VBoxService_LIBS.solaris += \
+	nsl \
 	kstat \
 	contract
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp	(revision 75406)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp	(revision 75407)
@@ -38,34 +38,59 @@
 *********************************************************************************************************************************/
 #include <iprt/assert.h>
+#include <iprt/ctype.h>
 #include <iprt/dir.h>
 #include <iprt/mem.h>
 #include <iprt/path.h>
+#include <iprt/semaphore.h>
+#include <iprt/sort.h>
 #include <iprt/string.h>
-#include <iprt/semaphore.h>
 #include <VBox/VBoxGuestLib.h>
+#include <VBox/shflsvc.h>
 #include "VBoxServiceInternal.h"
 #include "VBoxServiceUtils.h"
 
-#include <errno.h>
-#include <grp.h>
-#include <sys/mount.h>
-#ifdef RT_OS_SOLARIS
-# include <sys/mntent.h>
-# include <sys/mnttab.h>
-# include <sys/vfs.h>
+#ifdef RT_OS_WINDOWS
+#elif defined(RT_OS_OS2)
 #else
-# include <mntent.h>
-# include <paths.h>
+# include <errno.h>
+# include <grp.h>
+# include <sys/mount.h>
+# ifdef RT_OS_SOLARIS
+#  include <sys/mntent.h>
+#  include <sys/mnttab.h>
+#  include <sys/vfs.h>
+# elif defined(RT_OS_LINUX)
+#  include <mntent.h>
+#  include <paths.h>
+RT_C_DECLS_BEGIN
+#  include "../../linux/sharedfolders/vbsfmount.h"
+RT_C_DECLS_END
+# else
+#  error "Port me!"
+# endif
+# include <unistd.h>
 #endif
-#include <unistd.h>
-
-RT_C_DECLS_BEGIN
-#include "../../linux/sharedfolders/vbsfmount.h"
-RT_C_DECLS_END
-
-#ifdef RT_OS_SOLARIS
-# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR       "/mnt"
-#else
-# define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR       "/media"
+
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
+ * Default mount directory (unix only).
+ */
+#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
+# ifdef RT_OS_SOLARIS
+#  define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR      "/mnt"
+# else
+#  define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR      "/media"
+# endif
+#endif
+
+/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
+ * Default mount prefix (unix only).
+ */
+#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
+# define VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX   "sf_"
 #endif
 
@@ -78,4 +103,53 @@
 #endif
 
+/** @def VBOXSERVICE_AUTOMOUNT_MIQF
+ * The drive letter / path mount point flag.  */
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+# define VBOXSERVICE_AUTOMOUNT_MIQF             SHFL_MIQF_DRIVE_LETTER
+#else
+# define VBOXSERVICE_AUTOMOUNT_MIQF             SHFL_MIQF_PATH
+#endif
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * Automounter mount table entry.
+ *
+ * This holds the information returned by SHFL_FN_QUERY_MAP_INFO and
+ * additional mount state info.  We only keep entries for mounted mappings.
+ */
+typedef struct VBSVCAUTOMOUNTERENTRY
+{
+    /** The root ID. */
+    uint32_t     idRoot;
+    /** The root ID version. */
+    uint32_t     uRootIdVersion;
+    /** Map info flags, SHFL_MIF_XXX. */
+    uint64_t     fFlags;
+    /** The shared folder (mapping) name. */
+    char        *pszName;
+    /** The configured mount point, NULL if none. */
+    char        *pszMountPoint;
+    /** The actual mount point, NULL if not mount.  */
+    char        *pszActualMountPoint;
+} VBSVCAUTOMOUNTERENTRY;
+/** Pointer to an automounter entry.   */
+typedef VBSVCAUTOMOUNTERENTRY *PVBSVCAUTOMOUNTERENTRY;
+
+/** Automounter mount table. */
+typedef struct VBSVCAUTOMOUNTERTABLE
+{
+    /** Current number of entries in the array. */
+    uint32_t                cEntries;
+    /** Max number of entries the array can hold w/o growing it. */
+    uint32_t                cAllocated;
+    /** Pointer to an array of entry pointers. */
+    PVBSVCAUTOMOUNTERENTRY   *papEntries;
+} VBSVCAUTOMOUNTERTABLE;
+/** Pointer to an automounter mount table.   */
+typedef  VBSVCAUTOMOUNTERTABLE *PVBSVCAUTOMOUNTERTABLE;
+
 
 /*********************************************************************************************************************************
@@ -83,7 +157,18 @@
 *********************************************************************************************************************************/
 /** The semaphore we're blocking on. */
-static RTSEMEVENTMULTI  g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
+static RTSEMEVENTMULTI  g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
 /** The Shared Folders service client ID. */
-static uint32_t         g_SharedFoldersSvcClientID = 0;
+static uint32_t         g_idClientSharedFolders = 0;
+/** Set if we can wait on changes to the mappings. */
+static bool             g_fHostSupportsWaitAndInfoQuery = false;
+
+#ifdef RT_OS_OS2
+/** The attachment tag we use to identify attchments that belongs to us. */
+static char const       g_szTag[] = "VBoxAutomounter";
+#elif defined(RT_OS_SOLARIS)
+/** Dummy mount option that lets us identify mounts that belongs to us. */
+static char const       g_szTag[] = ",VBoxService=auto";
+#endif
+
 
 
@@ -91,15 +176,16 @@
  * @interface_method_impl{VBOXSERVICE,pfnInit}
  */
-static DECLCALLBACK(int) vbsvcAutoMountInit(void)
-{
-    VGSvcVerbose(3, "vbsvcAutoMountInit\n");
-
-    int rc = RTSemEventMultiCreate(&g_AutoMountEvent);
+static DECLCALLBACK(int) vbsvcAutomounterInit(void)
+{
+    VGSvcVerbose(3, "vbsvcAutomounterInit\n");
+
+    int rc = RTSemEventMultiCreate(&g_hAutoMountEvent);
     AssertRCReturn(rc, rc);
 
-    rc = VbglR3SharedFolderConnect(&g_SharedFoldersSvcClientID);
+    rc = VbglR3SharedFolderConnect(&g_idClientSharedFolders);
     if (RT_SUCCESS(rc))
     {
-        VGSvcVerbose(3, "vbsvcAutoMountInit: Service Client ID: %#x\n", g_SharedFoldersSvcClientID);
+        VGSvcVerbose(3, "vbsvcAutomounterInit: Service Client ID: %#x\n", g_idClientSharedFolders);
+        g_fHostSupportsWaitAndInfoQuery = RT_SUCCESS(VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders));
     }
     else
@@ -109,11 +195,11 @@
         if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
         {
-            VGSvcVerbose(0, "vbsvcAutoMountInit: Shared Folders service is not available\n");
+            VGSvcVerbose(0, "vbsvcAutomounterInit: Shared Folders service is not available\n");
             rc = VERR_SERVICE_DISABLED;
         }
         else
             VGSvcError("Control: Failed to connect to the Shared Folders service! Error: %Rrc\n", rc);
-        RTSemEventMultiDestroy(g_AutoMountEvent);
-        g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
+        RTSemEventMultiDestroy(g_hAutoMountEvent);
+        g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
     }
 
@@ -122,22 +208,25 @@
 
 
+#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) /* The old code: */
+
 /**
  * @todo Integrate into RTFsQueryMountpoint()?
  */
-static bool vbsvcAutoMountShareIsMounted(const char *pszShare, char *pszMountPoint, size_t cbMountPoint)
-{
-    AssertPtrReturn(pszShare, VERR_INVALID_PARAMETER);
-    AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
-    AssertReturn(cbMountPoint, VERR_INVALID_PARAMETER);
+static bool vbsvcAutoMountShareIsMountedOld(const char *pszShare, char *pszMountPoint, size_t cbMountPoint)
+{
+    AssertPtrReturn(pszShare, false);
+    AssertPtrReturn(pszMountPoint, false);
+    AssertReturn(cbMountPoint, false);
 
     bool fMounted = false;
+
+# if defined(RT_OS_SOLARIS)
     /** @todo What to do if we have a relative path in mtab instead
      *       of an absolute one ("temp" vs. "/media/temp")?
      * procfs contains the full path but not the actual share name ...
      * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
-#ifdef RT_OS_SOLARIS
     FILE *pFh = fopen(_PATH_MOUNTED, "r");
     if (!pFh)
-        VGSvcError("vbsvcAutoMountShareIsMounted: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
+        VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
     else
     {
@@ -154,8 +243,8 @@
         fclose(pFh);
     }
-#else
+# elif defined(RT_OS_LINUX)
     FILE *pFh = setmntent(_PATH_MOUNTED, "r+t"); /** @todo r=bird: why open it for writing? (the '+') */
     if (pFh == NULL)
-        VGSvcError("vbsvcAutoMountShareIsMounted: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
+        VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
     else
     {
@@ -172,7 +261,9 @@
         endmntent(pFh);
     }
-#endif
-
-    VGSvcVerbose(4, "vbsvcAutoMountShareIsMounted: Share '%s' at mount point '%s' = %s\n",
+# else
+#  error "PORTME!"
+# endif
+
+    VGSvcVerbose(4, "vbsvcAutoMountShareIsMountedOld: Share '%s' at mount point '%s' = %s\n",
                        pszShare, fMounted ? pszMountPoint : "<None>", fMounted ? "Yes" : "No");
     return fMounted;
@@ -186,5 +277,5 @@
  * @param   pszMountPoint   The shared folder mount point.
  */
-static int vbsvcAutoMountUnmount(const char *pszMountPoint)
+static int vbsvcAutoMountUnmountOld(const char *pszMountPoint)
 {
     AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
@@ -217,5 +308,5 @@
  * @param   pOpts           For getting the group ID.
  */
-static int vbsvcAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName, vbsf_mount_opts *pOpts)
+static int vbsvcAutoMountPrepareMountPointOld(const char *pszMountPoint, const char *pszShareName, vbsf_mount_opts *pOpts)
 {
     AssertPtrReturn(pOpts, VERR_INVALID_PARAMETER);
@@ -235,20 +326,20 @@
                 if (rc == VERR_WRITE_PROTECT)
                 {
-                    VGSvcVerbose(3, "vbsvcAutoMountPrepareMountPoint: Mount directory '%s' already is used/mounted\n",
-                                       pszMountPoint);
+                    VGSvcVerbose(3, "vbsvcAutoMountPrepareMountPointOld: Mount directory '%s' already is used/mounted\n",
+                                 pszMountPoint);
                     rc = VINF_SUCCESS;
                 }
                 else
-                    VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not set mode %RTfmode for mount directory '%s', rc = %Rrc\n",
-                                     fMode, pszMountPoint, rc);
+                    VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set mode %RTfmode for mount directory '%s', rc = %Rrc\n",
+                               fMode, pszMountPoint, rc);
             }
         }
         else
-            VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not set permissions for mount directory '%s', rc = %Rrc\n",
-                             pszMountPoint, rc);
+            VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set permissions for mount directory '%s', rc = %Rrc\n",
+                       pszMountPoint, rc);
     }
     else
-        VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not create mount directory '%s' with mode %RTfmode, rc = %Rrc\n",
-                         pszMountPoint, fMode, rc);
+        VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not create mount directory '%s' with mode %RTfmode, rc = %Rrc\n",
+                   pszMountPoint, fMode, rc);
     return rc;
 }
@@ -265,44 +356,45 @@
  * @param   pOpts           The mount options.
  */
-static int vbsvcAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint, struct vbsf_mount_opts *pOpts)
-{
-    AssertPtr(pOpts);
-
-    int rc = VINF_SUCCESS;
-    bool fSkip = false;
-
-    /* Already mounted? */
-    char szAlreadyMountedTo[RTPATH_MAX];
-    if (vbsvcAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo)))
-    {
-        fSkip = true;
-        /* Do if it not mounted to our desired mount point */
-        if (RTStrICmp(pszMountPoint, szAlreadyMountedTo))
-        {
-            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted to '%s', unmounting ...\n",
-                               pszShareName, szAlreadyMountedTo);
-            rc = vbsvcAutoMountUnmount(szAlreadyMountedTo);
-            if (RT_SUCCESS(rc))
-                fSkip = false;
-            else
-                VGSvcError("vbsvcAutoMountWorker: Failed to unmount '%s', %s (%d)! (rc=%Rrc)\n",
-                                 szAlreadyMountedTo, strerror(errno), errno, rc); /** @todo errno isn't reliable at this point */
-        }
-        if (fSkip)
-            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted to '%s', skipping\n",
-                               pszShareName, szAlreadyMountedTo);
-    }
-
-    if (!fSkip && RT_SUCCESS(rc))
-        rc = vbsvcAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
-    if (!fSkip && RT_SUCCESS(rc))
-    {
-#ifdef RT_OS_SOLARIS
+static int vbsvcAutoMountSharedFolderOld(const char *pszShareName, const char *pszMountPoint)
+{
+    /*
+     * Linux and solaris share the same mount structure.
+     */
+    struct group *grp_vboxsf = getgrnam("vboxsf");
+    if (!grp_vboxsf)
+    {
+        VGSvcError("vbsvcAutoMountWorker: Group 'vboxsf' does not exist\n");
+        return VINF_SUCCESS;
+    }
+
+    struct vbsf_mount_opts Opts =
+    {
+        0,                     /* uid */
+        (int)grp_vboxsf->gr_gid, /* gid */
+        0,                     /* ttl */
+        0770,                  /* dmode, owner and group "vboxsf" have full access */
+        0770,                  /* fmode, owner and group "vboxsf" have full access */
+        0,                     /* dmask */
+        0,                     /* fmask */
+        0,                     /* ronly */
+        0,                     /* sloppy */
+        0,                     /* noexec */
+        0,                     /* nodev */
+        0,                     /* nosuid */
+        0,                     /* remount */
+        "\0",                  /* nls_name */
+        NULL,                  /* convertcp */
+    };
+
+    int rc = vbsvcAutoMountPrepareMountPointOld(pszMountPoint, pszShareName, &Opts);
+    if (RT_SUCCESS(rc))
+    {
+# ifdef RT_OS_SOLARIS
+        int fFlags = 0;
+        if (Opts.ronly)
+            fFlags |= MS_RDONLY;
         char szOptBuf[MAX_MNTOPT_STR] = { '\0', };
-        int fFlags = 0;
-        if (pOpts->ronly)
-            fFlags |= MS_RDONLY;
         RTStrPrintf(szOptBuf, sizeof(szOptBuf), "uid=%d,gid=%d,dmode=%0o,fmode=%0o,dmask=%0o,fmask=%0o",
-                    pOpts->uid, pOpts->gid, pOpts->dmode, pOpts->fmode, pOpts->dmask, pOpts->fmask);
+                    Opts.uid, Opts.gid, Opts.dmode, Opts.fmode, Opts.dmask, Opts.fmask);
         int r = mount(pszShareName,
                       pszMountPoint,
@@ -317,7 +409,7 @@
         else if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
             VGSvcError("vbsvcAutoMountWorker: Could not mount shared folder '%s' to '%s', error = %s\n",
-                             pszShareName, pszMountPoint, strerror(errno));
-
-#elif defined(RT_OS_LINUX)
+                       pszShareName, pszMountPoint, strerror(errno));
+
+# else /* RT_OS_LINUX */
         unsigned long fFlags = MS_NODEV;
 
@@ -331,11 +423,11 @@
         mntinf.length       = sizeof(mntinf);
 
-        mntinf.uid   = pOpts->uid;
-        mntinf.gid   = pOpts->gid;
-        mntinf.ttl   = pOpts->ttl;
-        mntinf.dmode = pOpts->dmode;
-        mntinf.fmode = pOpts->fmode;
-        mntinf.dmask = pOpts->dmask;
-        mntinf.fmask = pOpts->fmask;
+        mntinf.uid   = Opts.uid;
+        mntinf.gid   = Opts.gid;
+        mntinf.ttl   = Opts.ttl;
+        mntinf.dmode = Opts.dmode;
+        mntinf.fmode = Opts.fmode;
+        mntinf.dmask = Opts.dmask;
+        mntinf.fmask = Opts.fmask;
 
         strcpy(mntinf.name, pszShareName);
@@ -351,5 +443,5 @@
             VGSvcVerbose(0, "vbsvcAutoMountWorker: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
 
-            r = vbsfmount_complete(pszShareName, pszMountPoint, fFlags, pOpts);
+            r = vbsfmount_complete(pszShareName, pszMountPoint, fFlags, &Opts);
             switch (r)
             {
@@ -360,5 +452,5 @@
                 case 1:
                     VGSvcError("vbsvcAutoMountWorker: Could not update mount table (failed to create memstream): %s\n",
-                                     strerror(errno));
+                               strerror(errno));
                     break;
 
@@ -427,7 +519,5 @@
             }
         }
-#else
-# error "PORTME"
-#endif
+# endif
     }
     VGSvcVerbose(3, "vbsvcAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
@@ -446,6 +536,6 @@
  * @param   uClientID       The shared folder service (HGCM) client ID.
  */
-static int vbsvcAutoMountProcessMappings(PCVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
-                                         const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
+static int vbsvcAutoMountProcessMappingsOld(PCVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
+                                            const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
 {
     if (cMappings == 0)
@@ -490,30 +580,37 @@
                     VGSvcVerbose(4, "vbsvcAutoMountWorker: Processing mount point '%s'\n", szMountPoint);
 
-                    struct group *grp_vboxsf = getgrnam("vboxsf");
-                    if (grp_vboxsf)
+                    /*
+                     * Already mounted?
+                     */
+                    /** @todo r-bird: this does not take into account that a shared folder could
+                     *        be mounted twice... We're really just interested in whether the
+                     *        folder is mounted on 'szMountPoint', no where else... */
+                    bool fSkip = false;
+                    char szAlreadyMountedOn[RTPATH_MAX];
+                    if (vbsvcAutoMountShareIsMountedOld(pszShareName, szAlreadyMountedOn, sizeof(szAlreadyMountedOn)))
                     {
-                        struct vbsf_mount_opts mount_opts =
+                        /* Do if it not mounted to our desired mount point */
+                        if (RTStrICmp(szMountPoint, szAlreadyMountedOn))
                         {
-                            0,                     /* uid */
-                            (int)grp_vboxsf->gr_gid, /* gid */
-                            0,                     /* ttl */
-                            0770,                  /* dmode, owner and group "vboxsf" have full access */
-                            0770,                  /* fmode, owner and group "vboxsf" have full access */
-                            0,                     /* dmask */
-                            0,                     /* fmask */
-                            0,                     /* ronly */
-                            0,                     /* sloppy */
-                            0,                     /* noexec */
-                            0,                     /* nodev */
-                            0,                     /* nosuid */
-                            0,                     /* remount */
-                            "\0",                  /* nls_name */
-                            NULL,                  /* convertcp */
-                        };
-
-                        rc = vbsvcAutoMountSharedFolder(pszShareName, szMountPoint, &mount_opts);
+                            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', unmounting ...\n",
+                                         pszShareName, szAlreadyMountedOn);
+                            rc = vbsvcAutoMountUnmountOld(szAlreadyMountedOn);
+                            if (RT_SUCCESS(rc))
+                                fSkip = false;
+                            else
+                                VGSvcError("vbsvcAutoMountWorker: Failed to unmount '%s', %s (%d)! (rc=%Rrc)\n",
+                                           szAlreadyMountedOn, strerror(errno), errno, rc); /** @todo errno isn't reliable at this point */
+                        }
+                        if (fSkip)
+                            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', skipping\n",
+                                         pszShareName, szAlreadyMountedOn);
                     }
-                    else
-                        VGSvcError("vbsvcAutoMountWorker: Group 'vboxsf' does not exist\n");
+                    if (!fSkip)
+                    {
+                        /*
+                         * Mount it.
+                         */
+                        rc = vbsvcAutoMountSharedFolderOld(pszShareName, szMountPoint);
+                    }
                 }
                 else
@@ -532,19 +629,24 @@
 }
 
-
-/**
- * @interface_method_impl{VBOXSERVICE,pfnWorker}
- */
-static DECLCALLBACK(int) vbsvcAutoMountWorker(bool volatile *pfShutdown)
-{
-    /*
-     * Tell the control thread that it can continue
-     * spawning services.
-     */
-    RTThreadUserSignal(RTThreadSelf());
-
+#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) - the old code*/
+
+
+/**
+ * Service worker function for old host.
+ *
+ * This only mount stuff on startup.
+ *
+ * @returns VBox status code.
+ * @param   pfShutdown          Shutdown indicator.
+ */
+static int vbsvcAutoMountWorkerOld(bool volatile *pfShutdown)
+{
+#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX)
+    /*
+     * We only do a single pass here.
+     */
     uint32_t cMappings;
     PVBGLR3SHAREDFOLDERMAPPING paMappings;
-    int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
+    int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /* Only process auto-mounted folders */,
                                            &paMappings, &cMappings);
     if (   RT_SUCCESS(rc)
@@ -564,18 +666,17 @@
             {
                 VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder mount prefix set to '%s'\n", pszSharePrefix);
-#ifdef USE_VIRTUAL_SHARES
+# ifdef USE_VIRTUAL_SHARES
                 /* Check for a fixed/virtual auto-mount share. */
-                if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount"))
-                {
+                if (VbglR3SharedFolderExists(g_idClientSharedFolders, "vbsfAutoMount"))
                     VGSvcVerbose(3, "vbsvcAutoMountWorker: Host supports auto-mount root\n");
-                }
                 else
                 {
-#endif
+# endif
                     VGSvcVerbose(3, "vbsvcAutoMountWorker: Got %u shared folder mappings\n", cMappings);
-                    rc = vbsvcAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
-#ifdef USE_VIRTUAL_SHARES
+                    rc = vbsvcAutoMountProcessMappingsOld(paMappings, cMappings, pszMountDir, pszSharePrefix,
+                                                          g_idClientSharedFolders);
+# ifdef USE_VIRTUAL_SHARES
                 }
-#endif
+# endif
                 RTStrFree(pszSharePrefix);
             } /* Mount share prefix. */
@@ -593,32 +694,1438 @@
         VGSvcVerbose(3, "vbsvcAutoMountWorker: No shared folder mappings found\n");
 
-    /*
-     * Because this thread is a one-timer at the moment we don't want to break/change
-     * the semantics of the main thread's start/stop sub-threads handling.
+#else
+    int rc = VINF_SUCCESS;
+#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) */
+
+
+    /*
+     * Wait on shutdown (this used to be a silly RTThreadSleep(500) loop).
+     */
+    while (!*pfShutdown)
+    {
+        rc = RTSemEventMultiWait(g_hAutoMountEvent, RT_MS_1MIN);
+        if (rc != VERR_TIMEOUT)
+            break;
+    }
+
+    VGSvcVerbose(3, "vbsvcAutoMountWorkerOld: Finished with rc=%Rrc\n", rc);
+    return rc;
+}
+
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+/**
+ * Assembles the mount directory and prefix into @a pszDst.
+ *
+ * Will fall back on defaults if we have trouble with the configuration from the
+ * host.  This ASSUMES that @a cbDst is rather large and won't cause trouble
+ * with the default.
+ *
+ * @returns IPRT status code.
+ * @param   pszDst          Where to return the prefix.
+ * @param   cbDst           The size of the prefix buffer.
+ */
+static int vbsvcAutomounterQueryMountDirAndPrefix(char *pszDst, size_t cbDst)
+{
+    /*
+     * Query the config first.
+     */
+    /* Mount directory: */
+    const char *pszDir = VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR;
+    char       *pszCfgDir;
+    int rc = VbglR3SharedFolderGetMountDir(&pszCfgDir);
+    if (RT_SUCCESS(rc))
+    {
+        if (*pszCfgDir == '/')
+            pszDir = pszCfgDir;
+    }
+    else
+        pszCfgDir = NULL;
+
+    /* Prefix: */
+    const char *pszPrefix = VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX;
+    char *pszCfgPrefix;
+    rc = VbglR3SharedFolderGetMountPrefix(&pszCfgPrefix);
+    if (RT_SUCCESS(rc))
+    {
+        if (   strchr(pszCfgPrefix, '/')  == NULL
+            && strchr(pszCfgPrefix, '\\') == NULL
+            && strcmp(pszCfgPrefix, "..") != 0)
+            pszPrefix = pszCfgPrefix;
+    }
+    else
+        pszCfgPrefix = NULL;
+
+    /*
+     * Try combine the two.
+     */
+    rc = RTPathAbs(pszDir, pszDst, cbDst);
+    if (RT_SUCCESS(rc))
+    {
+        if (*pszPrefix)
+        {
+            rc = RTPathAppend(pszDst, cbDst, pszPrefix);
+            if (RT_FAILURE(rc))
+                VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAppend(%s,,%s) -> %Rrc\n", pszDst, pszPrefix, rc);
+        }
+        else
+        {
+            rc = RTPathEnsureTrailingSeparator(pszDst, cbDst);
+            if (RT_FAILURE(rc))
+                VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathEnsureTrailingSeparator(%s) -> %Rrc\n", pszDst, rc);
+        }
+    }
+    else
+        VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAbs(%s) -> %Rrc\n", rc);
+
+
+    /*
+     * Return the default dir + prefix if the above failed.
+     */
+    if (RT_FAILURE(rc))
+    {
+        rc = RTStrCopy(pszDst, cbDst, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/" VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX);
+        AssertRC(rc);
+    }
+
+    RTStrFree(pszCfgDir);
+    RTStrFree(pszCfgPrefix);
+    return rc;
+}
+#endif /* !RT_OS_WINDOW && !RT_OS_OS2 */
+
+
+/**
+ * @callback_method_impl{FNRTSORTCMP, For sorting mount table by root ID. }
+ */
+static DECLCALLBACK(int) vbsvcAutomounterCompareEntry(void const *pvElement1, void const *pvElement2, void *pvUser)
+{
+    RT_NOREF_PV(pvUser);
+    PVBSVCAUTOMOUNTERENTRY pEntry1 = (PVBSVCAUTOMOUNTERENTRY)pvElement1;
+    PVBSVCAUTOMOUNTERENTRY pEntry2 = (PVBSVCAUTOMOUNTERENTRY)pvElement2;
+    return pEntry1->idRoot < pEntry2->idRoot ? -1
+         : pEntry1->idRoot > pEntry2->idRoot ? 1 : 0;
+}
+
+
+/**
+ * Worker for vbsvcAutomounterPopulateTable for adding discovered entries.
+ *
+ * This is puts dummies in for missing values, depending on
+ * vbsvcAutomounterPopulateTable to query them later.
+ *
+ * @returns VINF_SUCCESS or VERR_NO_MEMORY;
+ * @param   pMountTable     The mount table to add an entry to.
+ * @param   pszName         The shared folder name.
+ * @param   pszMountPoint   The mount point.
+ */
+static int vbsvcAutomounterAddEntry(PVBSVCAUTOMOUNTERTABLE pMountTable, const char *pszName, const char *pszMountPoint)
+{
+    VGSvcVerbose(2, "vbsvcAutomounterAddEntry: %s -> %s\n", pszMountPoint, pszName);
+    PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
+    pEntry->idRoot              = UINT32_MAX;
+    pEntry->uRootIdVersion      = UINT32_MAX;
+    pEntry->fFlags              = UINT64_MAX;
+    pEntry->pszName             = RTStrDup(pszName);
+    pEntry->pszMountPoint       = NULL;
+    pEntry->pszActualMountPoint = RTStrDup(pszMountPoint);
+    if (pEntry->pszName && pEntry->pszActualMountPoint)
+    {
+        if (pMountTable->cEntries + 1 <= pMountTable->cAllocated)
+        {
+            pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
+            return VINF_SUCCESS;
+        }
+
+        void *pvNew = RTMemRealloc(pMountTable->papEntries, (pMountTable->cAllocated + 8) * sizeof(pMountTable->papEntries[0]));
+        if (pvNew)
+        {
+            pMountTable->cAllocated += 8;
+            pMountTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvNew;
+
+            pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
+            return VINF_SUCCESS;
+        }
+    }
+    RTMemFree(pEntry->pszActualMountPoint);
+    RTMemFree(pEntry->pszName);
+    RTMemFree(pEntry);
+    return VERR_NO_MEMORY;
+}
+
+
+/**
+ * Populates the mount table as best we can with existing automount entries.
+ *
+ * @returns VINF_SUCCESS or VERR_NO_MEMORY;
+ * @param   pMountTable     The mount table (empty).
+ */
+static int vbsvcAutomounterPopulateTable(PVBSVCAUTOMOUNTERTABLE pMountTable)
+{
+    int rc;
+
+#ifdef RT_OS_WINDOWS
+    /*
+     * Loop thru the drive letters and check out each of them using QueryDosDeviceW.
+     */
+    static const char s_szDevicePath[] = "\\Device\\VBoxMiniRdr\\;";
+    for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
+    {
+        RTUTF16 const wszMountPoint[4] = { chDrive, ':', '\0', '\0' };
+        RTUTF16       wszTargetPath[RTPATH_MAX];
+        DWORD const   cwcResult = QueryDosDeviceW(wszMountPoint, wszTargetPath, RT_ELEMENTS(wszTargetPath));
+        if (   cwcResult > sizeof(s_szDevicePath)
+            && RTUtf16NICmpAscii(wszTargetPath, RT_STR_TUPLE(s_szDevicePath)) == 0)
+        {
+            PCRTUTF16 pwsz = &wszTargetPath[RT_ELEMENTS(s_szDevicePath) - 1];
+            Assert(pwsz[-1] == ';');
+            if (   (pwsz[0] & ~(RTUTF16)0x20) == chDrive
+                && pwsz[1] == ':'
+                && pwsz[2] == '\\')
+            {
+                /* For now we'll just use the special capitalization of the
+                   "server" name to identify it as our work.  We could check
+                   if the symlink is from \Global?? or \??, but that trick does
+                   work for older OS versions (<= XP) or when running the
+                   service manually for testing/wathever purposes. */
+                /** @todo Modify the windows shared folder driver to allow tagging drives.*/
+                if (RTUtf16NCmpAscii(&pwsz[3], RT_STR_TUPLE("VBoxSvr\\")) == 0)
+                {
+                    pwsz += 3 + 8;
+                    if (*pwsz != '\\' && *pwsz)
+                    {
+                        /* The shared folder name should follow immediately after the server prefix. */
+                        char *pszMountedName = NULL;
+                        rc = RTUtf16ToUtf8(pwsz, &pszMountedName);
+                        if (RT_SUCCESS(rc))
+                        {
+                            char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
+                            rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
+                            RTStrFree(pszMountedName);
+                        }
+                        if (RT_FAILURE(rc))
+                            return rc;
+                    }
+                    else
+                        VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Malformed, not ours: %ls -> %ls\n",
+                                     wszMountPoint, wszTargetPath);
+                }
+                else
+                    VGSvcVerbose(3, "vbsvcAutomounterPopulateTable: Not ours: %ls -> %ls\n", wszMountPoint, wszTargetPath);
+            }
+        }
+    }
+
+#elif defined(RT_OS_OS2)
+    /*
+     * Just loop thru the drive letters and check the attachment of each.
+     */
+    for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
+    {
+        char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
+        union
+        {
+            FSQBUFFER2  FsQueryBuf;
+            char        achPadding[1024];
+        } uBuf;
+        RT_ZERO(uBuf);
+        ULONG  cbBuf = sizeof(uBuf) - 2;
+        APIRET rcOs2 = DosQueryFSAttach(szMountPoint, 0, FSAIL_QUERYNAME, uBuf, &cbBuf);
+        if (rcOs2 == NO_ERROR)
+        {
+            const char *pszFsdName = &uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
+            if (   uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
+                && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
+            {
+                const char *pszMountedName = &pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
+                const char *pszTag         = strlen(pszMountedName) + 1; /* (Safe. Always two trailing zero bytes, see above.) */
+                if (strcmp(pszTag, g_szTag) == 0)
+                {
+                    rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
+                    if (RT_FAILURE(rc))
+                        return rc;
+                }
+            }
+        }
+    }
+
+#elif defined(RT_OS_LINUX)
+    /*
+     * Scan the mount table file for the mount point and then match file system
+     * and device/share.  We identify our mounts by mount path + prefix for now,
+     * but later we may use the same approach as on solaris.
+     */
+    char szMountPrefix[RTPATH_MAX];
+    rc = vbsvcAutomounterQueryMountDirAndPrefix(szMountPrefix, sizeof(szMountPrefix));
+    AssertRCReturn(rc, rc);
+    size_t const cchMountPrefix = strlen(szMountPrefix);
+
+    FILE *pFile = setmntent(_PATH_MOUNTED, "r");
+    if (pFile)
+    {
+        rc = VWRN_NOT_FOUND;
+        struct mntent *pEntry;
+        while ((pEntry = getmntent(pFile)) != NULL)
+            if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
+            {
+                /** @todo add mount option for tagging a mount, make kernel show it by
+                 *        implementing super_operations::show_options. */
+                if (strncmp(pEntry->mnt_dir, szMountPrefix, cchMountPrefix) == 0)
+                {
+                    rc = vbsvcAutomounterAddEntry(pMountTable, pEntry->mnt_fsname, pEntry->mnt_dir);
+                    if (RT_FAILURE(rc))
+                    {
+                        endmntent(pFile);
+                        return rc;
+                    }
+                }
+            }
+        endmntent(pFile);
+    }
+    else
+        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d) or '/proc/mounts' (errno=%d)\n",
+                   _PATH_MOUNTED, errno);
+    return rc;
+
+#elif defined(RT_OS_SOLARIS)
+    /*
+     * Look thru the system mount table and inspect the vboxsf mounts.
+     */
+    FILE *pFile = fopen(_PATH_MOUNTED, "r");
+    if (pFile)
+    {
+        rc = VINF_SUCCESS;
+        struct mnttab Entry;
+        while (getmntent(pFile, &Entry) == 0)
+            if (strcmp(Entry.mnt_fstype, "vboxsf") == 0)
+            {
+                /* Look for the dummy automounter option. */
+                if (   Entry.mnt_opts != NULL
+                    && strstr(Entry.mnt_opts, g_szTag) != NULL)
+                {
+                    rc = vbsvcAutomounterAddEntry(pMountTable, Entry.mnt_special, Entry.mnt_mountp);
+                    if (RT_FAILURE(rc))
+                    {
+                        fclose(pFile);
+                        return rc;
+                    }
+                }
+            }
+        fclose(pFile);
+    }
+    else
+        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
+
+#else
+# error "PORTME!"
+#endif
+
+    /*
+     * Try reconcile the detected folders with data from the host.
+     */
+    uint32_t                    cMappings = 0;
+    PVBGLR3SHAREDFOLDERMAPPING  paMappings = NULL;
+    rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
+    if (RT_SUCCESS(rc))
+    {
+        for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
+        {
+            uint32_t const idRootSrc = paMappings[i].u32Root;
+
+            uint32_t uRootIdVer = UINT32_MAX;
+            uint64_t fFlags     = 0;
+            char    *pszName    = NULL;
+            char    *pszMntPt   = NULL;
+            int rc2 = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc,  VBOXSERVICE_AUTOMOUNT_MIQF,
+                                                        &pszName, &pszMntPt, &fFlags, &uRootIdVer);
+            if (RT_SUCCESS(rc2))
+            {
+                uint32_t iPrevHit = UINT32_MAX;
+                for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
+                {
+                    PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
+                    if (RTStrICmp(pEntry->pszName, pszName) == 0)
+                    {
+                        VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Identified %s -> %s: idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
+                                     pEntry->pszActualMountPoint, pEntry->pszName, idRootSrc, uRootIdVer, fFlags, pszMntPt);
+                        pEntry->fFlags         = fFlags;
+                        pEntry->idRoot         = idRootSrc;
+                        pEntry->uRootIdVersion = uRootIdVer;
+                        RTStrFree(pEntry->pszMountPoint);
+                        pEntry->pszMountPoint = RTStrDup(pszMntPt);
+                        if (!pEntry->pszMountPoint)
+                        {
+                            rc = VERR_NO_MEMORY;
+                            break;
+                        }
+
+                        /* If multiple mappings of the same folder, pick the first or the one
+                           with matching mount point. */
+                        if (iPrevHit == UINT32_MAX)
+                            iPrevHit = iTable;
+                        else if (RTPathCompare(pszMntPt, pEntry->pszActualMountPoint) == 0)
+                        {
+                            if (iPrevHit != UINT32_MAX)
+                                pMountTable->papEntries[iPrevHit]->uRootIdVersion -= 1;
+                            iPrevHit = iTable;
+                        }
+                        else
+                            pEntry->uRootIdVersion -= 1;
+                    }
+                }
+
+                RTStrFree(pszName);
+                RTStrFree(pszMntPt);
+            }
+            else
+                VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderQueryFolderInfo(%u) failed: %Rrc\n", idRootSrc, rc2);
+        }
+
+        VbglR3SharedFolderFreeMappings(paMappings);
+
+        /*
+         * Sort the table by root ID.
+         */
+        if (pMountTable->cEntries > 1)
+            RTSortApvShell((void **)pMountTable->papEntries, pMountTable->cEntries, vbsvcAutomounterCompareEntry, NULL);
+
+        for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
+        {
+            PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
+            if (pMountTable->papEntries[iTable]->idRoot != UINT32_MAX)
+                VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
+                             iTable, pEntry->pszActualMountPoint, pEntry->pszName, pEntry->idRoot, pEntry->uRootIdVersion,
+                             pEntry->fFlags, pEntry->pszMountPoint);
+            else
+                VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s - not identified!\n",
+                             iTable, pEntry->pszActualMountPoint, pEntry->pszName);
+        }
+    }
+    else
+        VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
+    return rc;
+}
+
+
+/**
+ * Checks whether the shared folder @a pszName is mounted on @a pszMountPoint.
+ *
+ * @returns Exactly one of the following IPRT status codes;
+ * @retval  VINF_SUCCESS if mounted
+ * @retval  VWRN_NOT_FOUND if nothing is mounted at @a pszMountPoint.
+ * @retval  VERR_RESOURCE_BUSY if a different shared folder is mounted there.
+ * @retval  VERR_ACCESS_DENIED if a non-shared folder file system is mounted
+ *          there.
+ *
+ * @param   pszMountPoint   The mount point to check.
+ * @param   pszName         The name of the shared folder (mapping).
+ */
+static int vbsvcAutomounterQueryMountPoint(const char *pszMountPoint, const char *pszName)
+{
+    VGSvcVerbose(4, "vbsvcAutomounterQueryMountPoint: pszMountPoint=%s pszName=%s\n", pszMountPoint, pszName);
+
+#ifdef RT_OS_WINDOWS
+    /*
+     * We could've used RTFsQueryType here but would then have to
+     * calling RTFsQueryLabel for the share name hint, ending up
+     * doing the same work twice.  We could also use QueryDosDeviceW,
+     * but output is less clear...
+     */
+    PRTUTF16 pwszMountPoint = NULL;
+    int rc = RTStrToUtf16(pszMountPoint, &pwszMountPoint);
+    if (RT_SUCCESS(rc))
+    {
+        DWORD   uSerial = 0;
+        DWORD   cchCompMax = 0;
+        DWORD   fFlags = 0;
+        RTUTF16 wszLabel[512];
+        RTUTF16 wszFileSystem[256];
+        RT_ZERO(wszLabel);
+        RT_ZERO(wszFileSystem);
+        if (GetVolumeInformationW(pwszMountPoint, wszLabel, RT_ELEMENTS(wszLabel) - 1, &uSerial, &cchCompMax, &fFlags,
+                                  wszFileSystem, RT_ELEMENTS(wszFileSystem) - 1))
+        {
+            if (RTUtf16ICmpAscii(wszFileSystem, "VBoxSharedFolderFS") == 0)
+            {
+                char *pszLabel = NULL;
+                rc = RTUtf16ToUtf8(wszLabel, &pszLabel);
+                if (RT_SUCCESS(rc))
+                {
+                    const char *pszMountedName = pszLabel;
+                    if (RTStrStartsWith(pszMountedName, "VBOX_"))
+                        pszMountedName += sizeof("VBOX_") - 1;
+                    if (RTStrICmp(pszMountedName, pszName) == 0)
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
+                                     pszMountPoint, pszName);
+                        rc = VINF_SUCCESS;
+                    }
+                    else
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
+                                     pszMountedName, pszMountPoint, pszName);
+                        rc = VERR_RESOURCE_BUSY;
+                    }
+                    RTStrFree(pszLabel);
+                }
+                else
+                {
+                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: RTUtf16ToUtf8(%ls,) failed: %Rrc\n", wszLabel, rc);
+                    rc = VERR_RESOURCE_BUSY;
+                }
+            }
+            else
+            {
+                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%ls' with label '%ls' mount at '%s', not '%s'...\n",
+                             wszFileSystem, wszLabel, pszMountPoint, pszName);
+                rc = VERR_ACCESS_DENIED;
+            }
+        }
+        else
+        {
+            rc = GetLastError();
+            if (rc != ERROR_PATH_NOT_FOUND || g_cVerbosity >= 4)
+                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: GetVolumeInformationW('%ls',,,,) failed: %u\n", pwszMountPoint, rc);
+            rc = VWRN_NOT_FOUND;
+        }
+        RTUtf16Free(pwszMountPoint);
+    }
+    else
+    {
+        VGSvcError("vbsvcAutomounterQueryMountPoint: RTStrToUtf16(%s,) -> %Rrc\n", pszMountPoint, rc);
+        rc = VWRN_NOT_FOUND;
+    }
+    return rc;
+
+#elif defined(RT_OS_OS2)
+    /*
+     * Query file system attachment info for the given drive letter.
+     */
+    union
+    {
+        FSQBUFFER2  FsQueryBuf;
+        char        achPadding[512];
+    } uBuf;
+    RT_ZERO(uBuf);
+
+    ULONG cbBuf = sizeof(uBuf);
+    APIRET rcOs2 = DosQueryFSAttach((PCSZ)pFsInfo->szMountpoint, 0, FSAIL_QUERYNAME, uBuf, &cbBuf);
+    int rc;
+    if (rcOs2 == NO_ERROR)
+    {
+        const char *pszFsdName = &uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
+        if (   uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
+            && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
+        {
+            const char *pszMountedName = &pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
+            if (RTStrICmp(pszMountedName, pszName) == 0)
+            {
+                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
+                             pszMountPoint, pszName);
+                rc = VINF_SUCCESS;
+            }
+            else
+            {
+                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
+                             pszMountedName, pszMountPoint, pszName);
+                rc = VERR_RESOURCE_BUSY;
+            }
+        }
+        else
+        {
+            VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' type %u mount at '%s', not '%s'...\n",
+                         pszFsdName, uBuf.FsQueryBuf.iType, pszMountPoint, pszName);
+            rc = VERR_ACCESS_DENIED;
+        }
+    }
+    else
+    {
+        rc = VWRN_NOT_FOUND;
+        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: DosQueryFSAttach(%s) -> %u\n", pszMountPoint, rcOs2);
+        AssertMsgStmt(rcOs2 != ERROR_BUFFER_OVERFLOW && rcOs2 != ERROR_INVALID_PARAMETER,
+                      ("%s -> %u\n", pszMountPoint, rcOs2), rc = VERR_ACCESS_DENIED);
+    }
+    return rc;
+
+#elif defined(RT_OS_LINUX)
+    /*
+     * Scan one of the mount table file for the mount point and then
+     * match file system and device/share.
+     */
+    FILE *pFile = setmntent(_PATH_MOUNTED, "r");
+    int rc = errno;
+    if (!pFile)
+        pFile = setmntent("/proc/mounts", "r");
+    if (pFile)
+    {
+        rc = VWRN_NOT_FOUND;
+        struct mntent *pEntry;
+        while ((pEntry = getmntent(pFile)) != NULL)
+            if (RTPathCompare(pEntry->mnt_dir, pszMountPoint) == 0)
+            {
+                if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
+                {
+                    if (RTStrICmp(pEntry->mnt_fsname, pszName) == 0)
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
+                                     pszMountPoint, pszName);
+                        rc = VINF_SUCCESS;
+                    }
+                    else
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
+                                     pEntry->mnt_fsname, pszMountPoint, pszName);
+                        rc = VERR_RESOURCE_BUSY;
+                    }
+                }
+                else
+                {
+                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
+                                 pEntry->mnt_type, pEntry->mnt_fsname, pszMountPoint, pszName);
+                    rc = VERR_ACCESS_DENIED;
+                }
+                /* We continue searching in case of stacked mounts, we want the last one. */
+            }
+        endmntent(pFile);
+    }
+    else
+    {
+        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d) or '/proc/mounts' (errno=%d)\n",
+                   _PATH_MOUNTED, rc, errno);
+        rc = VERR_ACCESS_DENIED;
+    }
+    return rc;
+
+#elif defined(RT_OS_SOLARIS)
+    /*
+     * Similar to linux.
+     */
+    int rc;
+    FILE *pFile = fopen(_PATH_MOUNTED, "r");
+    if (pFile)
+    {
+        rc = VWRN_NOT_FOUND;
+        struct mnttab Entry;
+        while (getmntent(pFile, &Entry) == 0)
+            if (RTPathCompare(Entry.mnt_mountp, pszMountPoint) == 0)
+            {
+                if (strcmp(Entry.mnt_fstype, "vboxsf") == 0)
+                {
+                    if (RTStrICmp(Entry.mnt_special, pszName) == 0)
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
+                                     pszMountPoint, pszName);
+                        rc = VINF_SUCCESS;
+                    }
+                    else
+                    {
+                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
+                                     Entry.mnt_special, pszMountPoint, pszName);
+                        rc = VERR_RESOURCE_BUSY;
+                    }
+                }
+                else
+                {
+                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
+                                 Entry.mnt_fstype, Entry.mnt_special, pszMountPoint, pszName);
+                    rc = VERR_ACCESS_DENIED;
+                }
+                /* We continue searching in case of stacked mounts, we want the last one. */
+            }
+        fclose(pFile);
+    }
+    else
+    {
+        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
+        rc = VERR_ACCESS_DENIED;
+    }
+    return rc;
+#else
+# error "PORTME"
+#endif
+}
+
+
+/**
+ * Worker for vbsvcAutomounterMountNewEntry that does the OS mounting.
+ *
+ * @returns IPRT status code.
+ * @param   pEntry      The entry to try mount.
+ */
+static int vbsvcAutomounterMountIt(PVBSVCAUTOMOUNTERENTRY pEntry)
+{
+    VGSvcVerbose(3, "vbsvcAutomounterMountIt: Trying to mount '%s' (idRoot=%#x) on '%s'...\n",
+                 pEntry->pszName, pEntry->idRoot, pEntry->pszActualMountPoint);
+#ifdef RT_OS_WINDOWS
+    /*
+     * Attach the shared folder using WNetAddConnection2W.
      *
-     * This thread exits so fast while doing its own startup in VGSvcStartServices()
-     * that this->fShutdown flag is set to true in VGSvcThread() before we have the
-     * chance to check for a service failure in VGSvcStartServices() to indicate
-     * a VBoxService startup error.
+     * According to google we should get a drive symlink in \\GLOBAL?? when
+     * we are running under the system account.  Otherwise it will a session
+     * local link (\\??).
+     */
+    Assert(RT_C_IS_UPPER(pEntry->pszActualMountPoint[0]) && pEntry->pszActualMountPoint[1] == ':' && pEntry->pszActualMountPoint[2] == '\0');
+    RTUTF16 wszDrive[4] = { pEntry->pszActualMountPoint[0], ':', '\0', '\0' };
+
+    RTUTF16 wszPrefixedName[RTPATH_MAX];
+    int rc = RTUtf16CopyAscii(wszPrefixedName, RT_ELEMENTS(wszPrefixedName), "\\\\VBoxSvr\\");
+    AssertRC(rc);
+
+    PRTUTF16 pwszName = &wszPrefixedName[RTUtf16Len(wszPrefixedName)];
+    rc = RTStrToUtf16Ex(pEntry->pszName, RTSTR_MAX, &pwszName, pwszName - wszPrefixedName, NULL);
+    if (RT_FAILURE(rc))
+    {
+        VGSvcError("vbsvcAutomounterMountIt: RTStrToUtf16Ex failed on '%s': %Rrc\n", pEntry->pszName, rc);
+        return rc;
+    }
+
+    NETRESOURCEW NetRsrc;
+    RT_ZERO(NetRsrc);
+    NetRsrc.dwType          = RESOURCETYPE_DISK;
+    NetRsrc.lpLocalName     = wszDrive;
+    NetRsrc.lpRemoteName    = wszPrefixedName;
+    NetRsrc.lpProvider      = L"VirtualBox Shared Folders"; /* Only try our provider. */
+    NetRsrc.lpComment       = pwszName;
+
+    DWORD dwErr = WNetAddConnection2W(&NetRsrc, NULL /*pwszPassword*/, NULL /*pwszUserName*/, 0 /*dwFlags*/);
+    if (dwErr == NO_ERROR)
+    {
+        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
+                     pEntry->pszName, pEntry->pszActualMountPoint);
+        return VINF_SUCCESS;
+    }
+    VGSvcError("vbsvcAutomounterMountIt: Failed to attach '%s' to '%s': %u\n",
+               pEntry->pszName, pEntry->pszActualMountPoint, rc);
+    return VERR_OPEN_FAILED;
+
+#elif defined(RT_OS_OS2)
+    /*
+     * It's a rather simple affair on OS/2.
      *
-     * Therefore *no* service threads are allowed to quit themselves and need to wait
-     * for the pfShutdown flag to be set by the main thread.
-     */
-/** @todo r=bird: Shared folders have always been configurable at run time, so
- * this service must be changed to check for changes and execute those changes!
- *
- * The 0.5sec sleep here is just soo crude and must go!
- */
+     * In order to be able to detect our mounts we add a 2nd string after
+     * the folder name that tags the attachment.  The IFS will remember this
+     * and return it when DosQueryFSAttach is called.
+     *
+     * Note! Kernel currently accepts limited 7-bit ASCII names.  We could
+     *       change that to UTF-8 if we like as that means no extra string
+     *       encoding conversion fun here.
+     */
+    char    szzNameAndTag[256];
+    size_t  cchName = strlen(pEntry->pszName);
+    if (cchName + 1 + sizeof(g_szTag) <= sizeof(szzNameAndTag))
+    {
+        memcpy(szzNameAndTag, pEntry->pszName, cchName);
+        szzNameAndTag[cchName] = '\0';
+        memcpy(&szzNameAndTag[cchName + 1], g_szTag, sizeof(g_szTag));
+
+        APIRET rc = DosFSAttach(pEntry->pszActualMountPoint, "VBOXSF", szzNameAndTag, cchName + 1 + sizeof(g_szzTag), FS_ATTACH);
+        if (rc == NO_ERROR)
+        {
+            VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
+                         pEntry->pszName, pEntry->pszActualMountPoint);
+            return VINF_SUCCESS;
+        }
+        VGSvcError("vbsvcAutomounterMountIt: DosFSAttach failed to attach '%s' to '%s': %u\n",
+                   pEntry->pszName, pEntry->pszActualMountPoint, rc);
+    }
+    else
+        VGSvcError("vbsvcAutomounterMountIt: Share name for attach to '%s' is too long: %u chars - '%s'\n",
+                   pEntry->pszActualMountPoint, cchName, pEntry->pszName;
+    return VERR_OPEN_FAILED;
+
+#else
+    /*
+     * Common work for unix-like systems: Get group, make sure mount directory exist.
+     */
+    int rc = RTDirCreateFullPath(pEntry->pszActualMountPoint,
+                                 RTFS_UNIX_IRWXU | RTFS_UNIX_IXGRP | RTFS_UNIX_IRGRP | RTFS_UNIX_IXOTH | RTFS_UNIX_IROTH);
+    if (RT_FAILURE(rc))
+    {
+        VGSvcError("vbsvcAutomounterMountIt: Failed to create mount path '%s' for share '%s': %Rrc\n",
+                   pEntry->pszActualMountPoint, pEntry->pszName, rc);
+        return rc;
+    }
+
+    gid_t gidMount;
+    struct group *grp_vboxsf = getgrnam("vboxsf");
+    if (grp_vboxsf)
+        gidMount = grp_vboxsf->gr_gid;
+    else
+    {
+        VGSvcError("vbsvcAutomounterMountIt: Group 'vboxsf' does not exist\n");
+        gidMount = 0;
+    }
+
+#  if defined(RT_OS_LINUX)
+    /*
+     * Linux a bit more work...
+     */
+    struct vbsf_mount_info_new MntInfo;
+    RT_ZERO(MntInfo);
+    struct vbsf_mount_opts MntOpts;
+    RT_ZERO(MntOpts);
+    MntInfo.nullchar     = '\0';
+    MntInfo.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
+    MntInfo.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
+    MntInfo.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
+    MntInfo.length       = sizeof(MntInfo);
+    MntInfo.uid          = MntOpts.uid   = 0;
+    MntInfo.gid          = MntOpts.gid   = gidMount;
+    MntInfo.dmode        = MntOpts.dmode = 0770;
+    MntInfo.fmode        = MntOpts.fmode = 0770;
+    MntInfo.dmask        = MntOpts.dmask = 0000;
+    MntInfo.fmask        = MntOpts.fmask = 0000;
+    rc = RTStrCopy(MntInfo.name, sizeof(MntInfo.name), pEntry->pszName);
+    if (RT_FAILURE(rc))
+    {
+        VGSvcError("vbsvcAutomounterMountIt: Share name '%s' is too long for the MntInfo.name field!\n", pEntry->pszName);
+        return rc;
+    }
+
+    errno = 0;
+    unsigned long fFlags = MS_NODEV;
+    rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, "vboxsf", fFlags, &MntInfo);
+    if (rc == 0)
+    {
+        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
+                     pEntry->pszName, pEntry->pszActualMountPoint);
+
+        errno = 0;
+        rc = vbsfmount_complete(pEntry->pszName, pEntry->pszActualMountPoint, fFlags, &MntOpts);
+        if (rc == 0)
+            return VINF_SUCCESS;
+
+        VGSvcError("vbsvcAutomounterMountIt: vbsfmount_complete failed: %s (%d/%d)\n",
+                   rc == 1 ? "open_memstream" : rc == 2 ? "setmntent" : rc == 3 ? "addmntent" : "unknown", rc, errno);
+    }
+    else if (errno == EINVAL)
+        VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s' because it is probably mounted elsewhere arleady! (%d,%d)\n",
+                   pEntry->pszName, pEntry->pszActualMountPoint, rc, errno);
+    else
+        VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s': %s (%d,%d)\n",
+                   pEntry->pszName, pEntry->pszActualMountPoint, strerror(errno), rc, errno);
+    return VERR_WRITE_ERROR;
+
+#  elif defined(RT_OS_SOLARIS)
+    /*
+     * Solaris is rather simple compared to linux.
+     *
+     * The ',VBoxService=auto' option (g_szTag) is ignored by the kernel but helps
+     * us identify our own mounts on restart.  See vbsvcAutomounterPopulateTable().
+     */
+    char szOpts[MAX_MNTOPT_STR] = { '\0', };
+    ssize_t cchOpts = RTStrPrintf2(szOpts, sizeof(szOpts),
+                                   "uid=0,gid=%d,dmode=0770,fmode=0770,dmask=0000,fmask=0000%s", gidMount, g_szTag);
+    if (cchOpts <= 0)
+    {
+        VGSvcError("vbsvcAutomounterMountIt: szOpts overflow! %zd\n", cchOpts);
+        return VERR_BUFFER_OVERFLOW;
+    }
+
+    rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, MS_OPTIONSTR, "vboxfs",
+               NULL /*dataptr*/, 0 /* datalen */, szOptBuf, cchOpts + 1);
+    if (rc == 0)
+    {
+        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
+        return VINF_SUCCESS;
+    }
+
+    rc = errno;
+    VGSvcError("vbsvcAutomounterMountIt: mount failed for '%s' at '%s': %s (%d)\n",
+               pEntry->pszName, pEntry->pszActualMountPoint, strerror(rc), rc);
+    return VERR_OPEN_FAILED;
+
+# else
+#  error "PORTME!"
+# endif
+#endif
+}
+
+
+/**
+ * Attempts to mount the given shared folder, adding it to the mount table on
+ * success.
+ *
+ * @returns iTable + 1 on success, iTable on failure.
+ * @param   pTable          The mount table.
+ * @param   iTable          The mount table index at which to add the mount.
+ * @param   pszName         The name of the shared folder mapping.
+ * @param   pszMntPt        The mount point (hint) specified by the host.
+ * @param   fFlags          The shared folder flags, SHFL_MIF_XXX.
+ * @param   idRoot          The root ID.
+ * @param   uRootIdVersion  The root ID version.
+ * @param   fAutoMntPt      Whether to try automatically assign a mount point if
+ *                          pszMntPt doesn't work out.  This is set in pass \#3.
+ */
+static uint32_t vbsvcAutomounterMountNewEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable,
+                                              const char *pszName, const char *pszMntPt, uint64_t fFlags,
+                                              uint32_t idRoot, uint32_t uRootIdVersion, bool fAutoMntPt)
+{
+    VGSvcVerbose(3, "vbsvcAutomounterMountNewEntry: #%u: '%s' at '%s'%s\n",
+                 iTable, pszName, pszMntPt, fAutoMntPt ? " auto-assign" : "");
+
+    /*
+     * First we need to figure out the actual mount point.
+     */
+    char szActualMountPoint[RTPATH_MAX];
+
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+    /*
+     * Drive letter based:
+     */
+    char chNextLetter = 'Z';
+    if (RT_C_IS_UPPER(pszMntPt[0]) && pszMntPt[1] == ':')
+        szActualMountPoint[0] = RT_C_TO_UPPER(pszMntPt[0]);
+    else if (!fAutoMntPt)
+        return iTable;
+    else
+        szActualMountPoint[0] = chNextLetter--;
+    szActualMountPoint[1] = ':';
+    szActualMountPoint[2] = '\0';
+
+    int rc;
     for (;;)
     {
-        /* Do we need to shutdown? */
-        if (*pfShutdown)
+        rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
+        if (rc == VWRN_NOT_FOUND)
             break;
 
-        /* Let's sleep for a bit and let others run ... */
-        RTThreadSleep(500);
-    }
-
-    VGSvcVerbose(3, "vbsvcAutoMountWorker: Finished with rc=%Rrc\n", rc);
+        /* next */
+        if (chNextLetter == 'A' || !fAutoMntPt)
+            return iTable;
+        szActualMountPoint[0] = chNextLetter--;
+    }
+
+#else
+    /*
+     * Path based #1: Host specified mount point.
+     */
+    int rc = VERR_ACCESS_DENIED;
+    if (*pszMntPt == '/')
+    {
+        rc = RTPathAbs(pszMntPt, szActualMountPoint, sizeof(szActualMountPoint));
+        if (RT_SUCCESS(rc))
+        {
+            static const char * const s_apszBlacklist[] =
+            { "/", "/dev", "/bin", "/sbin", "/lib", "/etc", "/var", "/tmp", "/usr", "/usr/bin", "/usr/sbin", "/usr/lib" };
+            for (size_t i = 0; i < RT_ELEMENTS(s_apszBlacklist); i++)
+                if (strcmp(szActualMountPoint, s_apszBlacklist[i]) == 0)
+                {
+                    rc = VERR_ACCESS_DENIED;
+                    break;
+                }
+            if (RT_SUCCESS(rc))
+                rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
+        }
+    }
+    if (rc != VWRN_NOT_FOUND)
+    {
+        if (!fAutoMntPt)
+            return iTable;
+
+        /*
+         * Path based #2: Mount dir + prefix + share.
+         */
+        /* Mount base directory: */
+        szActualMountPoint[0] = '\0';
+        char *pszProp;
+        rc = VbglR3SharedFolderGetMountDir(&pszProp);
+        if (RT_SUCCESS(rc))
+        {
+            if (*pszProp == '/')
+                rc = RTPathAbs(pszProp, szActualMountPoint, sizeof(szActualMountPoint));
+            else
+                VGSvcError("vbsvcAutomounterMountNewEntry: Invalid mount directory: '%s'\n", pszProp);
+            RTStrFree(pszProp);
+        }
+        if (RT_FAILURE(rc) || szActualMountPoint[0] != '/')
+            memcpy(szActualMountPoint, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR, sizeof(VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR));
+
+        /* Add prefix: */
+        rc = VbglR3SharedFolderGetMountPrefix(&pszProp);
+        if (RT_SUCCESS(rc))
+        {
+            if (   strchr(pszProp, '/')  == NULL
+                && strchr(pszProp, '\\') == NULL
+                && strcmp(pszProp, "..") != 0)
+                rc = RTPathAppend(szActualMountPoint, sizeof(szActualMountPoint), pszProp);
+            else
+                VGSvcError("vbsvcAutomounterMountNewEntry: Invalid mount prefix: '%s'\n", pszProp);
+            RTStrFree(pszProp);
+        }
+        else
+            rc = RTPathEnsureTrailingSeparator(szActualMountPoint, sizeof(szActualMountPoint)) != 0
+               ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
+        if (RT_SUCCESS(rc))
+        {
+            /* Add sanitized share name: */
+            size_t const offShare = strlen(szActualMountPoint);
+            size_t offDst = offShare;
+            size_t offSrc = 0;
+            for (;;)
+            {
+                char ch = pszName[offSrc++];
+                if (ch == ' ' || ch == '/' || ch == '\\' || ch == ':' || ch == '$')
+                    ch = '_';
+                else if (!ch)
+                    break;
+                else if (ch < 0x20 || ch == 0x7f)
+                    continue;
+                if (offDst < sizeof(szActualMountPoint) - 1)
+                    szActualMountPoint[offDst++] = ch;
+            }
+            szActualMountPoint[offDst] = '\0';
+            if (offDst > offShare)
+            {
+                rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
+                if (rc != VWRN_NOT_FOUND)
+                {
+                    /*
+                     * Path based #3: Mount dir + prefix + share + _ + number.
+                     */
+                    if (offDst + 2 >= sizeof(szActualMountPoint))
+                        return iTable;
+
+                    szActualMountPoint[offDst++] = '_';
+                    for (uint32_t iTry = 1; iTry < 10 && rc != VWRN_NOT_FOUND; iTry++)
+                    {
+                        szActualMountPoint[offDst] = '0' + iTry;
+                        szActualMountPoint[offDst + 1] = '\0';
+                        rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
+                    }
+                    if (rc != VWRN_NOT_FOUND)
+                       return iTable;
+                }
+            }
+            else
+                VGSvcError("vbsvcAutomounterMountNewEntry: Bad share name: %.*Rhxs", strlen(pszName), pszName);
+        }
+        else
+            VGSvcError("vbsvcAutomounterMountNewEntry: Failed to construct basic auto mount point for '%s'", pszName);
+    }
+#endif
+
+    /*
+     * Prepare a table entry and ensure space in the table..
+     */
+    if (pTable->cEntries + 1 > pTable->cAllocated)
+    {
+        void *pvEntries = RTMemRealloc(pTable->papEntries, sizeof(pTable->papEntries[0]) * (pTable->cAllocated + 8));
+        if (!pvEntries)
+        {
+            VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for growing table (size %u)\n", pTable->cAllocated);
+            return iTable;
+        }
+        pTable->cAllocated += 8;
+        pTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvEntries;
+    }
+
+    PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
+    if (pEntry)
+    {
+        pEntry->idRoot              = idRoot;
+        pEntry->uRootIdVersion      = uRootIdVersion;
+        pEntry->fFlags              = fFlags;
+        pEntry->pszName             = RTStrDup(pszName);
+        pEntry->pszMountPoint       = RTStrDup(pszMntPt);
+        pEntry->pszActualMountPoint = RTStrDup(szActualMountPoint);
+        if (pEntry->pszName && pEntry->pszMountPoint && pEntry->pszActualMountPoint)
+        {
+            /*
+             * Now try mount it.
+             */
+            rc = vbsvcAutomounterMountIt(pEntry);
+            if (RT_SUCCESS(rc))
+            {
+                uint32_t cToMove = pTable->cEntries - iTable;
+                if (cToMove > 0)
+                    memmove(&pTable->papEntries[iTable + 1], &pTable->papEntries[iTable], cToMove * sizeof(pTable->papEntries[0]));
+                pTable->papEntries[iTable] = pEntry;
+                pTable->cEntries++;
+                return iTable + 1;
+            }
+        }
+        else
+            VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
+        RTMemFree(pEntry->pszActualMountPoint);
+        RTMemFree(pEntry->pszMountPoint);
+        RTMemFree(pEntry->pszName);
+        RTMemFree(pEntry);
+    }
+    else
+        VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
+    return iTable;
+}
+
+
+
+/**
+ * Does the actual unmounting.
+ *
+ * @returns Exactly one of the following IPRT status codes;
+ * @retval  VINF_SUCCESS if successfully umounted or nothing was mounted there.
+ * @retval  VERR_TRY_AGAIN if the shared folder is busy.
+ * @retval  VERR_RESOURCE_BUSY if a different shared folder is mounted there.
+ * @retval  VERR_ACCESS_DENIED if a non-shared folder file system is mounted
+ *          there.
+ *
+ * @param   pszMountPoint       The mount point.
+ * @param   pszName             The shared folder (mapping) name.
+ */
+static int vbsvcAutomounterUnmount(const char *pszMountPoint, const char *pszName)
+{
+    /*
+     * Retry for 5 seconds in a hope that busy mounts will quiet down.
+     */
+    for (unsigned iTry = 0; ; iTry++)
+    {
+        /*
+         * Check what's mounted there before we start umounting stuff.
+         */
+        int rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
+        if (rc == VINF_SUCCESS)
+        { /* pszName is mounted there */ }
+        else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
+            return VINF_SUCCESS;
+        else
+        {
+            Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
+            return VERR_RESOURCE_BUSY;
+        }
+
+        /*
+         * Do host specific unmounting.
+         */
+#ifdef RT_OS_WINDOWS
+        Assert(RT_C_IS_UPPER(pszMountPoint[0]) && pszMountPoint[1] == ':' && pszMountPoint[2] == '\0');
+        RTUTF16 const wszDrive[4] = { pszMountPoint[0], ':', '\0', '\0' };
+        DWORD dwErr = WNetCancelConnection2W(wszDrive, 0 /*dwFlags*/, FALSE /*fForce*/);
+        if (dwErr == NO_ERROR)
+            return VINF_SUCCESS;
+        VGSvcVerbose(2, "vbsvcAutomounterUnmount: WNetCancelConnection2W returns %u for '%s' ('%s')\n", dwErr, pszMountPoint, pszName);
+        if (dwErr == ERROR_NOT_CONNECTED)
+            return VINF_SUCCESS;
+
+#elif defined(RT_OS_OS2)
+        APIRET rcOs2 = DosFSAttach(pszMountPoint, "VBOXSF", NULL, 0, FS_DETACH);
+        if (rcOs2 == NO_ERROR)
+            return VINF_SUCCESS;
+        VGSvcVerbose(2, "vbsvcAutomounterUnmount: DosFSAttach failed on '%s' ('%s'): %u\n", pszMountPoint, pszName, rcOs2);
+        if (rcOs2 == ERROR_INVALID_FSD_NAME)
+            return VERR_ACCESS_DENIED;
+        if (   rcOs2 == ERROR_INVALID_DRIVE
+            || rcOs2 == ERROR_INVALID_PATH)
+            return VERR_TRY_AGAIN;
+
+#else
+        int rc2 = umount(pszMountPoint);
+        if (rc2 == 0)
+            return VINF_SUCCESS;
+        rc2 = errno;
+        VGSvcVerbose(2, "vbsvcAutomounterUnmount: umount failed on '%s' ('%s'): %d\n", pszMountPoint, pszName, rc2);
+        if (rc2 != EBUSY && rc2 != EAGAIN)
+            return VERR_ACCESS_DENIED;
+#endif
+
+        /*
+         * Check what's mounted there before we start delaying.
+         */
+        RTThreadSleep(8); /* fudge */
+        rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
+        if (rc == VINF_SUCCESS)
+        { /* pszName is mounted there */ }
+        else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
+            return VINF_SUCCESS;
+        else
+        {
+            Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
+            return VERR_RESOURCE_BUSY;
+        }
+
+        if (iTry >= 5)
+            return VERR_TRY_AGAIN;
+        RTThreadSleep(1000);
+    }
+}
+
+
+/**
+ * Unmounts a mount table entry and evicts it from the table if successful.
+ *
+ * @returns The next iTable (same value on success, +1 on failure).
+ * @param   pTable              The mount table.
+ * @param   iTable              The table entry.
+ * @param   pszReason           Why we're here.
+ */
+static uint32_t vbsvcAutomounterUnmountEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable, const char *pszReason)
+{
+    Assert(iTable < pTable->cEntries);
+    PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
+    VGSvcVerbose(3, "vbsvcAutomounterUnmountEntry: #%u: '%s' at '%s' (reason: %s)\n",
+                 iTable, pEntry->pszName, pEntry->pszMountPoint, pszReason);
+
+    /*
+     * Do we need to umount the entry?  Return if unmount fails and we .
+     */
+    if (pEntry->pszActualMountPoint)
+    {
+        int rc = vbsvcAutomounterUnmount(pEntry->pszActualMountPoint, pEntry->pszName);
+        if (rc == VERR_TRY_AGAIN)
+        {
+            VGSvcVerbose(2, "vbsvcAutomounterUnmountEntry: Keeping '%s' -> '%s' (VERR_TRY_AGAIN)\n",
+                         pEntry->pszActualMountPoint, pEntry->pszName);
+            return iTable + 1;
+        }
+    }
+
+    /*
+     * Remove the entry by shifting up the ones after it.
+     */
+    pTable->cEntries -= 1;
+    uint32_t cAfter = pTable->cEntries - iTable;
+    if (cAfter)
+        memmove(&pTable->papEntries[iTable], &pTable->papEntries[iTable + 1], cAfter * sizeof(pTable->papEntries[0]));
+    pTable->papEntries[pTable->cEntries] = NULL;
+
+    RTStrFree(pEntry->pszActualMountPoint);
+    pEntry->pszActualMountPoint = NULL;
+    RTStrFree(pEntry->pszMountPoint);
+    pEntry->pszMountPoint = NULL;
+    RTStrFree(pEntry->pszName);
+    pEntry->pszName = NULL;
+    RTMemFree(pEntry);
+
+    return iTable;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSORTCMP,  For sorting the mappings by ID,}
+ */
+static DECLCALLBACK(int) vbsvcSharedFolderMappingCompare(void const *pvElement1, void const *pvElement2, void *pvUser)
+{
+    RT_NOREF_PV(pvUser);
+    PVBGLR3SHAREDFOLDERMAPPING pMapping1 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement1;
+    PVBGLR3SHAREDFOLDERMAPPING pMapping2 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement2;
+    return pMapping1->u32Root < pMapping2->u32Root ? -1 : pMapping1->u32Root != pMapping2->u32Root ? 1 : 0;
+}
+
+
+/**
+ * Refreshes the mount table.
+ *
+ * @returns true if we've processed the current config, false if we failed to
+ *          query the mappings.
+ * @param   pTable          The mount table to refresh.
+ */
+static bool vbsvcAutomounterRefreshTable(PVBSVCAUTOMOUNTERTABLE pTable)
+{
+    /*
+     * Query the root IDs of all auto-mountable shared folder mappings.
+     */
+    uint32_t                    cMappings = 0;
+    PVBGLR3SHAREDFOLDERMAPPING  paMappings = NULL;
+    int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
+    if (RT_FAILURE(rc))
+    {
+        VGSvcError("vbsvcAutomounterRefreshTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
+        return false;
+    }
+
+    /*
+     * Walk the table and the mappings in parallel, so we have to make sure
+     * they are both sorted by root ID.
+     */
+    if (cMappings > 1)
+        RTSortShell(paMappings, cMappings, sizeof(paMappings[0]), vbsvcSharedFolderMappingCompare, NULL);
+
+    /*
+     * Pass #1: Do all the umounting.
+     *
+     * By doing the umount pass separately from the mount pass, we can
+     * better handle changing involving the same mount points (switching
+     * mount points between two shares, new share on same mount point but
+     * with lower root ID, ++).
+     */
+    uint32_t iTable = 0;
+    for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
+    {
+        /*
+         * Unmount table entries up to idRootSrc.
+         */
+        uint32_t const idRootSrc = paMappings[iSrc].u32Root;
+        while (   iTable < pTable->cEntries
+               && pTable->papEntries[iTable]->idRoot < idRootSrc)
+            iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped");
+
+        /*
+         * If the paMappings entry and the mount table entry has the same
+         * root ID, umount if anything has changed or if we cannot query
+         * the mapping data.
+         */
+        if (iTable < pTable->cEntries)
+        {
+            PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
+            if (pEntry->idRoot == idRootSrc)
+            {
+                uint32_t uRootIdVer = UINT32_MAX;
+                uint64_t fFlags     = 0;
+                char    *pszName    = NULL;
+                char    *pszMntPt   = NULL;
+                rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
+                                                       &pszName, &pszMntPt, &fFlags, &uRootIdVer);
+                if (RT_FAILURE(rc))
+                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "VbglR3SharedFolderQueryFolderInfo failed");
+                else if (pEntry->uRootIdVersion != uRootIdVer)
+                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "root ID version changed");
+                else if (RTPathCompare(pEntry->pszMountPoint, pszMntPt) != 0)
+                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "mount point changed");
+                else if (RTStrICmp(pEntry->pszName, pszName) != 0)
+                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "name changed");
+                else
+                {
+                    VGSvcVerbose(3, "vbsvcAutomounterRefreshTable: Unchanged: %s -> %s\n", pEntry->pszMountPoint, pEntry->pszName);
+                    iTable++;
+                }
+                if (RT_SUCCESS(rc))
+                {
+                    RTStrFree(pszName);
+                    RTStrFree(pszMntPt);
+                }
+            }
+        }
+    }
+
+    while (iTable < pTable->cEntries)
+        iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped (tail)");
+
+    VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u entries in mount table after pass #1.\n", pTable->cEntries);
+
+    /*
+     * Pass #2: Try mount new folders that has mount points assigned.
+     * Pass #3: Try mount new folders not mounted in pass #2.
+     */
+    for (uint32_t iPass = 2; iPass <= 3; iPass++)
+    {
+        iTable = 0;
+        for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
+        {
+            uint32_t const idRootSrc = paMappings[iSrc].u32Root;
+
+            /*
+             * Skip tabel entries we couldn't umount in pass #1.
+             */
+            while (   iTable < pTable->cEntries
+                   && pTable->papEntries[iTable]->idRoot < idRootSrc)
+            {
+                VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Skipping idRoot=%u %s\n",
+                             iPass, iSrc, iTable, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
+                iTable++;
+            }
+
+            /*
+             * New share?
+             */
+            if (   iTable >= pTable->cEntries
+                || pTable->papEntries[iTable]->idRoot != idRootSrc)
+            {
+                uint32_t uRootIdVer = UINT32_MAX;
+                uint64_t fFlags     = 0;
+                char    *pszName    = NULL;
+                char    *pszMntPt   = NULL;
+                rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
+                                                       &pszName, &pszMntPt, &fFlags, &uRootIdVer);
+                if (RT_SUCCESS(rc))
+                {
+                    VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Mounting idRoot=%u/%u %s\n", iPass, iSrc, iTable,
+                                 idRootSrc, iTable >= pTable->cEntries ? UINT32_MAX : pTable->papEntries[iTable]->idRoot, pszName);
+                    iTable = vbsvcAutomounterMountNewEntry(pTable, iTable, pszName, pszMntPt, fFlags,
+                                                           idRootSrc, uRootIdVer, iPass == 3);
+
+                    RTStrFree(pszName);
+                    RTStrFree(pszMntPt);
+                }
+                else
+                    VGSvcVerbose(1, "vbsvcAutomounterRefreshTable: VbglR3SharedFolderQueryFolderInfo failed: %Rrc\n", rc);
+            }
+            else
+                VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: idRootSrc=%u vs idRoot=%u %s\n", iPass, iSrc,
+                             iTable, idRootSrc, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
+        }
+    }
+
+    VbglR3SharedFolderFreeMappings(paMappings);
+    return true;
+}
+
+
+/**
+ * @interface_method_impl{VBOXSERVICE,pfnWorker}
+ */
+static DECLCALLBACK(int) vbsvcAutomounterWorker(bool volatile *pfShutdown)
+{
+    /*
+     * Tell the control thread that it can continue spawning services.
+     */
+    RTThreadUserSignal(RTThreadSelf());
+
+    /* Divert old hosts to original auto-mount code. */
+    if (!g_fHostSupportsWaitAndInfoQuery)
+        return vbsvcAutoMountWorkerOld(pfShutdown);
+
+    /*
+     * Initialize the state in case we're restarted...
+     */
+    VBSVCAUTOMOUNTERTABLE MountTable  = { 0, 0, NULL };
+    int rc = vbsvcAutomounterPopulateTable(&MountTable);
+    if (RT_FAILURE(rc))
+    {
+        VGSvcError("vbsvcAutomounterWorker: vbsvcAutomounterPopulateTable failed (%Rrc), quitting!\n", rc);
+        return rc;
+    }
+
+    /*
+     * Work loop.
+     */
+    uint32_t uConfigVer    = UINT32_MAX;
+    uint32_t uNewVersion   = 0;
+    bool     fForceRefresh = true;
+    while (!*pfShutdown)
+    {
+        /*
+         * Update the mounts.
+         */
+        if (   uConfigVer != uNewVersion
+            || fForceRefresh)
+        {
+            fForceRefresh = !vbsvcAutomounterRefreshTable(&MountTable);
+            uConfigVer    = uNewVersion;
+        }
+
+        /*
+         * Wait for more to do.
+         */
+        if (!*pfShutdown)
+        {
+            uNewVersion = uConfigVer - 1;
+            VGSvcVerbose(2, "vbsvcAutomounterWorker: Waiting with uConfigVer=%u\n", uConfigVer);
+            rc = VbglR3SharedFolderWaitForMappingsChanges(g_idClientSharedFolders, uConfigVer, &uNewVersion);
+            VGSvcVerbose(2, "vbsvcAutomounterWorker: Woke up with uNewVersion=%u and rc=%Rrc\n", uNewVersion, rc);
+
+            /* Delay a little before doing a table refresh so the GUI can finish
+               all its updates.  Delay a little longer on non-shutdown failure to
+               avoid eating too many CPU cycles if something goes wrong here... */
+            if (!*pfShutdown)
+                RTSemEventMultiWait(g_hAutoMountEvent, RT_SUCCESS(rc) ? 256 : 1000);
+        }
+    }
+
+    /*
+     * Destroy the mount table.
+     */
+    while (MountTable.cEntries-- > 0)
+        RTMemFree(MountTable.papEntries[MountTable.cEntries]);
+    MountTable.papEntries = NULL;
+
+    VGSvcVerbose(3, "vbsvcAutomounterWorker: Finished\n");
     return VINF_SUCCESS;
 }
@@ -626,28 +2133,32 @@
 
 /**
+ * @interface_method_impl{VBOXSERVICE,pfnStop}
+ */
+static DECLCALLBACK(void) vbsvcAutomounterStop(void)
+{
+    RTSemEventMultiSignal(g_hAutoMountEvent);
+    if (g_fHostSupportsWaitAndInfoQuery)
+        VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
+}
+
+
+/**
  * @interface_method_impl{VBOXSERVICE,pfnTerm}
  */
-static DECLCALLBACK(void) vbsvcAutoMountTerm(void)
+static DECLCALLBACK(void) vbsvcAutomounterTerm(void)
 {
     VGSvcVerbose(3, "vbsvcAutoMountTerm\n");
 
-    VbglR3SharedFolderDisconnect(g_SharedFoldersSvcClientID);
-    g_SharedFoldersSvcClientID = 0;
-
-    if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI)
-    {
-        RTSemEventMultiDestroy(g_AutoMountEvent);
-        g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
-    }
-    return;
-}
-
-
-/**
- * @interface_method_impl{VBOXSERVICE,pfnStop}
- */
-static DECLCALLBACK(void) vbsvcAutoMountStop(void)
-{
-    RTSemEventMultiSignal(g_AutoMountEvent);
+    if (g_fHostSupportsWaitAndInfoQuery)
+        VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
+
+    VbglR3SharedFolderDisconnect(g_idClientSharedFolders);
+    g_idClientSharedFolders = 0;
+
+    if (g_hAutoMountEvent != NIL_RTSEMEVENTMULTI)
+    {
+        RTSemEventMultiDestroy(g_hAutoMountEvent);
+        g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
+    }
 }
 
@@ -661,5 +2172,5 @@
     "automount",
     /* pszDescription. */
-    "Auto-mount for Shared Folders",
+    "Automounter for Shared Folders",
     /* pszUsage. */
     NULL,
@@ -669,7 +2180,8 @@
     VGSvcDefaultPreInit,
     VGSvcDefaultOption,
-    vbsvcAutoMountInit,
-    vbsvcAutoMountWorker,
-    vbsvcAutoMountStop,
-    vbsvcAutoMountTerm
+    vbsvcAutomounterInit,
+    vbsvcAutomounterWorker,
+    vbsvcAutomounterStop,
+    vbsvcAutomounterTerm
 };
+
Index: /trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c
===================================================================
--- /trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c	(revision 75406)
+++ /trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c	(revision 75407)
@@ -479,4 +479,6 @@
 }
 
+/** @todo Implement show_options (forever) or maybe set s_options (2.6.25+).
+ *        Necessary for the automounter tagging.  */
 static struct super_operations sf_super_ops = {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
Index: /trunk/src/VBox/HostServices/SharedFolders/mappings.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedFolders/mappings.cpp	(revision 75406)
+++ /trunk/src/VBox/HostServices/SharedFolders/mappings.cpp	(revision 75407)
@@ -23,4 +23,5 @@
 #include <iprt/alloc.h>
 #include <iprt/assert.h>
+#include <iprt/list.h>
 #include <iprt/path.h>
 #include <iprt/string.h>
@@ -30,10 +31,45 @@
 #endif
 
-/* Shared folders order in the saved state and in the FolderMapping can differ.
+extern PVBOXHGCMSVCHELPERS g_pHelpers; /* service.cpp */
+
+
+/* Shared folders order in the saved state and in the g_FolderMapping can differ.
  * So a translation array of root handle is needed.
  */
 
-static MAPPING FolderMapping[SHFL_MAX_MAPPINGS];
-static SHFLROOT aIndexFromRoot[SHFL_MAX_MAPPINGS];
+static MAPPING g_FolderMapping[SHFL_MAX_MAPPINGS];
+static SHFLROOT g_aIndexFromRoot[SHFL_MAX_MAPPINGS];
+/**< Array running parallel to g_aIndexFromRoot and which entries are increased
+ * as an root handle is added or removed.
+ *
+ * This helps the guest figuring out that a mapping may have been reconfigured
+ * or that saved state has been restored.  Entry reuse is very likely given that
+ * vbsfRootHandleAdd() always starts searching at the start for an unused entry.
+ */
+static uint32_t g_auRootHandleVersions[SHFL_MAX_MAPPINGS];
+/** Version number that is increased for every change made.
+ * This is used by the automount guest service to wait for changes.
+ * @note This does not need saving, the guest should be woken up and refresh
+ *       its sate when restored. */
+static uint32_t volatile g_uFolderMappingsVersion = 0;
+
+
+/** For recording async vbsfMappingsWaitForChanges calls. */
+typedef struct SHFLMAPPINGSWAIT
+{
+    RTLISTNODE          ListEntry;  /**< List entry. */
+    PSHFLCLIENTDATA     pClient;    /**< The client that's waiting. */
+    VBOXHGCMCALLHANDLE  hCall;      /**< The call handle to signal completion with. */
+    PVBOXHGCMSVCPARM    pParm;      /**< The 32-bit unsigned parameter to stuff g_uFolderMappingsVersion into. */
+} SHFLMAPPINGSWAIT;
+/** Pointer to async mappings change wait. */
+typedef SHFLMAPPINGSWAIT *PSHFLMAPPINGSWAIT;
+/** List head for clients waiting on mapping changes (SHFLMAPPINGSWAIT). */
+static RTLISTANCHOR g_MappingsChangeWaiters;
+/** Number of clients waiting on mapping changes.
+ * We use this to limit the number of waiting calls the clients can make.  */
+static uint32_t     g_cMappingChangeWaiters = 0;
+static void vbsfMappingsWakeupAllWaiters(void);
+
 
 void vbsfMappingInit(void)
@@ -41,16 +77,18 @@
     unsigned root;
 
-    for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
-    {
-        aIndexFromRoot[root] = SHFL_ROOT_NIL;
-    }
-}
-
-int vbsfMappingLoaded(const PMAPPING pLoadedMapping, SHFLROOT root)
+    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
+    {
+        g_aIndexFromRoot[root] = SHFL_ROOT_NIL;
+    }
+
+    RTListInit(&g_MappingsChangeWaiters);
+}
+
+int vbsfMappingLoaded(const MAPPING *pLoadedMapping, SHFLROOT root)
 {
     /* Mapping loaded from the saved state with the index. Which means
      * the guest uses the iMapping as root handle for this folder.
-     * Check whether there is the same mapping in FolderMapping and
-     * update the aIndexFromRoot.
+     * Check whether there is the same mapping in g_FolderMapping and
+     * update the g_aIndexFromRoot.
      *
      * Also update the mapping properties, which were lost: cMappings.
@@ -62,7 +100,7 @@
 
     SHFLROOT i;
-    for (i = 0; i < RT_ELEMENTS(FolderMapping); i++)
-    {
-        MAPPING *pMapping = &FolderMapping[i];
+    for (i = 0; i < RT_ELEMENTS(g_FolderMapping); i++)
+    {
+        MAPPING *pMapping = &g_FolderMapping[i];
 
         /* Equal? */
@@ -71,11 +109,20 @@
             && memcmp(pLoadedMapping->pMapName, pMapping->pMapName, ShflStringSizeOfBuffer(pMapping->pMapName)) == 0)
         {
-            /* Actual index is i. */
-            aIndexFromRoot[root] = i;
-
-            /* Update the mapping properties. */
-            pMapping->cMappings = pLoadedMapping->cMappings;
-
-            return VINF_SUCCESS;
+            if (!pMapping->fLoadedRootId)
+            {
+                pMapping->fLoadedRootId = true;
+                Log(("vbsfMappingLoaded: root=%u i=%u (was %u) (%ls)\n",
+                     root, i, g_aIndexFromRoot[root], pLoadedMapping->pMapName->String.utf16));
+
+                /* Actual index is i. */
+                /** @todo This will not work with global shared folders, as these can change
+                 *        while state is saved and these blind assignments may hid new ones.  */
+                g_aIndexFromRoot[root] = i;
+
+                /* Update the mapping properties. */
+                pMapping->cMappings = pLoadedMapping->cMappings;
+
+                return VINF_SUCCESS;
+            }
         }
     }
@@ -93,12 +140,12 @@
 MAPPING *vbsfMappingGetByRoot(SHFLROOT root)
 {
-    if (root < RT_ELEMENTS(aIndexFromRoot))
-    {
-        SHFLROOT iMapping = aIndexFromRoot[root];
+    if (root < RT_ELEMENTS(g_aIndexFromRoot))
+    {
+        SHFLROOT iMapping = g_aIndexFromRoot[root];
 
         if (   iMapping != SHFL_ROOT_NIL
-            && iMapping < RT_ELEMENTS(FolderMapping))
-        {
-            return &FolderMapping[iMapping];
+            && iMapping < RT_ELEMENTS(g_FolderMapping))
+        {
+            return &g_FolderMapping[iMapping];
         }
     }
@@ -111,7 +158,7 @@
     unsigned root;
 
-    for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
-    {
-        if (iMapping == aIndexFromRoot[root])
+    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
+    {
+        if (iMapping == g_aIndexFromRoot[root])
         {
             return root;
@@ -122,13 +169,12 @@
 }
 
-static MAPPING *vbsfMappingGetByName (PRTUTF16 pwszName, SHFLROOT *pRoot)
-{
-    unsigned i;
-
-    for (i=0; i<SHFL_MAX_MAPPINGS; i++)
-    {
-        if (FolderMapping[i].fValid == true)
-        {
-            if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pwszName))
+static MAPPING *vbsfMappingGetByName(PRTUTF16 pwszName, SHFLROOT *pRoot)
+{
+    for (unsigned i = 0; i < SHFL_MAX_MAPPINGS; i++)
+    {
+        if (   g_FolderMapping[i].fValid
+            && !g_FolderMapping[i].fPlaceholder) /* Don't allow mapping placeholders. */
+        {
+            if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pwszName))
             {
                 SHFLROOT root = vbsfMappingGetRootFromIndex(i);
@@ -140,14 +186,10 @@
                         *pRoot = root;
                     }
-                    return &FolderMapping[i];
+                    return &g_FolderMapping[i];
                 }
-                else
-                {
-                    AssertFailed();
-                }
+                AssertFailed();
             }
         }
     }
-
     return NULL;
 }
@@ -157,9 +199,10 @@
     unsigned root;
 
-    for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
-    {
-        if (aIndexFromRoot[root] == SHFL_ROOT_NIL)
-        {
-            aIndexFromRoot[root] = iMapping;
+    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
+    {
+        if (g_aIndexFromRoot[root] == SHFL_ROOT_NIL)
+        {
+            g_aIndexFromRoot[root] = iMapping;
+            g_auRootHandleVersions[root] += 1;
             return;
         }
@@ -173,10 +216,15 @@
     unsigned root;
 
-    for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
-    {
-        if (aIndexFromRoot[root] == iMapping)
-        {
-            aIndexFromRoot[root] = SHFL_ROOT_NIL;
-            return;
+    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
+    {
+        if (g_aIndexFromRoot[root] == iMapping)
+        {
+            g_aIndexFromRoot[root] = SHFL_ROOT_NIL;
+            g_auRootHandleVersions[root] += 1;
+            Log(("vbsfRootHandleRemove: Removed root=%u (iMapping=%u)\n", root, iMapping));
+
+            /* Note! Do not stop here as g_aIndexFromRoot may (at least it could
+                     prior to the introduction of fLoadedRootId) contain
+                     duplicates after restoring save state. */
         }
     }
@@ -209,20 +257,26 @@
     Log(("vbsfMappingsAdd %ls\n", pMapName->String.ucs2));
 
-    /* check for duplicates */
-    for (i=0; i<SHFL_MAX_MAPPINGS; i++)
-    {
-        if (FolderMapping[i].fValid == true)
-        {
-            if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
+    /* Check for duplicates, ignoring placeholders to give the GUI to change stuff at runtime. */
+    /** @todo bird: Not entirely sure about ignoring placeholders, but you cannot
+     *        trigger auto-umounting without ignoring them. */
+    if (!fPlaceholder)
+    {
+        for (i = 0; i < SHFL_MAX_MAPPINGS; i++)
+        {
+            if (   g_FolderMapping[i].fValid
+                && !g_FolderMapping[i].fPlaceholder)
             {
-                AssertMsgFailed(("vbsfMappingsAdd: %ls mapping already exists!!\n", pMapName->String.ucs2));
-                return VERR_ALREADY_EXISTS;
+                if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
+                {
+                    AssertMsgFailed(("vbsfMappingsAdd: %ls mapping already exists!!\n", pMapName->String.ucs2));
+                    return VERR_ALREADY_EXISTS;
+                }
             }
         }
     }
 
-    for (i=0; i<SHFL_MAX_MAPPINGS; i++)
-    {
-        if (FolderMapping[i].fValid == false)
+    for (i = 0; i < SHFL_MAX_MAPPINGS; i++)
+    {
+        if (g_FolderMapping[i].fValid == false)
         {
             /* Make sure the folder name is an absolute path, otherwise we're
@@ -232,32 +286,34 @@
             AssertRCReturn(rc, rc);
 
-            FolderMapping[i].pszFolderName   = RTStrDup(szAbsFolderName);
-            FolderMapping[i].pMapName        = ShflStringDup(pMapName);
-            FolderMapping[i].pAutoMountPoint = ShflStringDup(pAutoMountPoint);
-            if (   !FolderMapping[i].pszFolderName
-                || !FolderMapping[i].pMapName
-                || !FolderMapping[i].pAutoMountPoint)
+            g_FolderMapping[i].pszFolderName   = RTStrDup(szAbsFolderName);
+            g_FolderMapping[i].pMapName        = ShflStringDup(pMapName);
+            g_FolderMapping[i].pAutoMountPoint = ShflStringDup(pAutoMountPoint);
+            if (   !g_FolderMapping[i].pszFolderName
+                || !g_FolderMapping[i].pMapName
+                || !g_FolderMapping[i].pAutoMountPoint)
             {
-                RTStrFree(FolderMapping[i].pszFolderName);
-                RTMemFree(FolderMapping[i].pMapName);
-                RTMemFree(FolderMapping[i].pAutoMountPoint);
+                RTStrFree(g_FolderMapping[i].pszFolderName);
+                RTMemFree(g_FolderMapping[i].pMapName);
+                RTMemFree(g_FolderMapping[i].pAutoMountPoint);
                 return VERR_NO_MEMORY;
             }
 
-            FolderMapping[i].fValid          = true;
-            FolderMapping[i].cMappings       = 0;
-            FolderMapping[i].fWritable       = fWritable;
-            FolderMapping[i].fAutoMount      = fAutoMount;
-            FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
-            FolderMapping[i].fMissing        = fMissing;
-            FolderMapping[i].fPlaceholder    = fPlaceholder;
+            g_FolderMapping[i].fValid          = true;
+            g_FolderMapping[i].cMappings       = 0;
+            g_FolderMapping[i].fWritable       = fWritable;
+            g_FolderMapping[i].fAutoMount      = fAutoMount;
+            g_FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
+            g_FolderMapping[i].fMissing        = fMissing;
+            g_FolderMapping[i].fPlaceholder    = fPlaceholder;
+            g_FolderMapping[i].fLoadedRootId   = false;
 
             /* Check if the host file system is case sensitive */
             RTFSPROPERTIES prop;
             prop.fCaseSensitive = false; /* Shut up MSC. */
-            rc = RTFsQueryProperties(FolderMapping[i].pszFolderName, &prop);
+            rc = RTFsQueryProperties(g_FolderMapping[i].pszFolderName, &prop);
             AssertRC(rc);
-            FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
+            g_FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
             vbsfRootHandleAdd(i);
+            vbsfMappingsWakeupAllWaiters();
             break;
         }
@@ -269,5 +325,6 @@
     }
 
-    Log(("vbsfMappingsAdd: added mapping %s to %ls\n", pszFolderName, pMapName->String.ucs2));
+    Log(("vbsfMappingsAdd: added mapping %s to %ls (slot %u, root %u)\n",
+         pszFolderName, pMapName->String.ucs2, i, vbsfMappingGetRootFromIndex(i)));
     return VINF_SUCCESS;
 }
@@ -285,42 +342,52 @@
 int vbsfMappingsRemove(PSHFLSTRING pMapName)
 {
-    unsigned i;
-
     Assert(pMapName);
-
     Log(("vbsfMappingsRemove %ls\n", pMapName->String.ucs2));
-    for (i=0; i<SHFL_MAX_MAPPINGS; i++)
-    {
-        if (FolderMapping[i].fValid == true)
-        {
-            if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
+
+    /*
+     * We must iterate thru the whole table as may have 0+ placeholder entries
+     * and 0-1 regular entries with the same name.  Also, it is good to kick
+     * the guest automounter into action wrt to evicting placeholders.
+     */
+    int rc = VERR_FILE_NOT_FOUND;
+    for (unsigned i = 0; i < SHFL_MAX_MAPPINGS; i++)
+    {
+        if (g_FolderMapping[i].fValid == true)
+        {
+            if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
             {
-                if (FolderMapping[i].cMappings != 0)
+                if (g_FolderMapping[i].cMappings != 0)
                 {
-                    LogRel2(("SharedFolders: removing '%ls' -> '%s', which is still used by the guest\n",
-                             pMapName->String.ucs2, FolderMapping[i].pszFolderName));
-                    FolderMapping[i].fMissing = true;
-                    FolderMapping[i].fPlaceholder = true;
-                    return VINF_PERMISSION_DENIED;
+                    LogRel2(("SharedFolders: removing '%ls' -> '%s'%s, which is still used by the guest\n", pMapName->String.ucs2,
+                             g_FolderMapping[i].pszFolderName, g_FolderMapping[i].fPlaceholder ? " (again)" : ""));
+                    g_FolderMapping[i].fMissing = true;
+                    g_FolderMapping[i].fPlaceholder = true;
+                    vbsfMappingsWakeupAllWaiters();
+                    rc = VINF_PERMISSION_DENIED;
                 }
-
-                /* pMapName can be the same as FolderMapping[i].pMapName,
-                 * log it before deallocating the memory.
-                 */
-                Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
-
-                RTStrFree(FolderMapping[i].pszFolderName);
-                RTMemFree(FolderMapping[i].pMapName);
-                FolderMapping[i].pszFolderName = NULL;
-                FolderMapping[i].pMapName      = NULL;
-                FolderMapping[i].fValid        = false;
-                vbsfRootHandleRemove(i);
-                return VINF_SUCCESS;
+                else
+                {
+                    /* pMapName can be the same as g_FolderMapping[i].pMapName when
+                     * called from vbsfUnmapFolder, log it before deallocating the memory. */
+                    Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
+                    bool fSame = g_FolderMapping[i].pMapName == pMapName;
+
+                    RTStrFree(g_FolderMapping[i].pszFolderName);
+                    RTMemFree(g_FolderMapping[i].pMapName);
+                    g_FolderMapping[i].pszFolderName = NULL;
+                    g_FolderMapping[i].pMapName      = NULL;
+                    g_FolderMapping[i].fValid        = false;
+                    vbsfRootHandleRemove(i);
+                    vbsfMappingsWakeupAllWaiters();
+                    if (rc == VERR_FILE_NOT_FOUND)
+                        rc = VINF_SUCCESS;
+                    if (fSame)
+                        break;
+                }
             }
         }
     }
 
-    AssertMsgFailed(("vbsfMappingsRemove: mapping %ls not found!!!!\n", pMapName->String.ucs2));
-    return VERR_FILE_NOT_FOUND;
+    return rc;
 }
 
@@ -378,37 +445,30 @@
 #endif
 /**
- * Note: If pMappings / *pcMappings is smaller than the actual amount of mappings
- *       that *could* have been returned *pcMappings contains the required buffer size
- *       so that the caller can retry the operation if wanted.
- */
-int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings)
-{
-    int rc = VINF_SUCCESS;
-
-    uint32_t cMappings = 0; /* Will contain actual valid mappings. */
-    uint32_t idx = 0;       /* Current index in mappings buffer. */
-
+ * @note If pMappings / *pcMappings is smaller than the actual amount of
+ *       mappings that *could* have been returned *pcMappings contains the
+ *       required buffer size so that the caller can retry the operation if
+ *       wanted.
+ */
+int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, bool fOnlyAutoMounts, PSHFLMAPPING pMappings, uint32_t *pcMappings)
+{
     LogFlow(("vbsfMappingsQuery: pClient = %p, pMappings = %p, pcMappings = %p, *pcMappings = %d\n",
              pClient, pMappings, pcMappings, *pcMappings));
 
+    uint32_t const cMaxMappings = *pcMappings;
+    uint32_t       idx          = 0;
     for (uint32_t i = 0; i < SHFL_MAX_MAPPINGS; i++)
     {
         MAPPING *pFolderMapping = vbsfMappingGetByRoot(i);
         if (   pFolderMapping != NULL
-            && pFolderMapping->fValid == true)
-        {
-            if (idx < *pcMappings)
+            && pFolderMapping->fValid
+            && (   !fOnlyAutoMounts
+                || (pFolderMapping->fAutoMount && !pFolderMapping->fPlaceholder)) )
+        {
+            if (idx < cMaxMappings)
             {
-                /* Skip mappings which are not marked for auto-mounting if
-                 * the SHFL_MF_AUTOMOUNT flag ist set. */
-                if (   (pClient->fu32Flags & SHFL_MF_AUTOMOUNT)
-                    && !pFolderMapping->fAutoMount)
-                    continue;
-
                 pMappings[idx].u32Status = SHFL_MS_NEW;
-                pMappings[idx].root = i;
-                idx++;
+                pMappings[idx].root      = i;
             }
-            cMappings++;
+            idx++;
         }
     }
@@ -416,8 +476,14 @@
     /* Return actual number of mappings, regardless whether the handed in
      * mapping buffer was big enough. */
-    *pcMappings = cMappings;
-
-    LogFlow(("vbsfMappingsQuery: return rc = %Rrc\n", rc));
-    return rc;
+    /** @todo r=bird: This is non-standard interface behaviour.  We return
+     *        VERR_BUFFER_OVERFLOW or at least a VINF_BUFFER_OVERFLOW here.
+     *
+     *        Guess this goes well along with ORing SHFL_MF_AUTOMOUNT into
+     *        pClient->fu32Flags rather than passing it as fOnlyAutoMounts...
+     *        Not amused by this. */
+    *pcMappings = idx;
+
+    LogFlow(("vbsfMappingsQuery: returns VINF_SUCCESS (idx=%u, cMaxMappings=%u)\n", idx, cMaxMappings));
+    return VINF_SUCCESS;
 }
 
@@ -437,42 +503,39 @@
 int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString)
 {
-    int rc = VINF_SUCCESS;
-
-    LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n",
-             pClient, root, pString));
-
+    LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n", pClient, root, pString));
+
+    int rc;
     MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
-    if (pFolderMapping == NULL)
-    {
-        return VERR_INVALID_PARAMETER;
-    }
-
-    if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
-    {
-        /* Not implemented. */
-        AssertFailed();
-        return VERR_INVALID_PARAMETER;
-    }
-
-    if (pFolderMapping->fValid == true)
-    {
-        if (pString->u16Size < pFolderMapping->pMapName->u16Size)
-        {
-            Log(("vbsfMappingsQuery: passed string too short (%d < %d bytes)!\n",
-                pString->u16Size,  pFolderMapping->pMapName->u16Size));
-            rc = VERR_INVALID_PARAMETER;
+    if (pFolderMapping)
+    {
+        if (pFolderMapping->fValid)
+        {
+            if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
+                rc = ShflStringCopyUtf16BufAsUtf8(pString, pFolderMapping->pMapName);
+            else
+            {
+                /* Not using ShlfStringCopy here as behaviour shouldn't change... */
+                if (pString->u16Size < pFolderMapping->pMapName->u16Size)
+                {
+                    Log(("vbsfMappingsQuery: passed string too short (%d < %d bytes)!\n",
+                        pString->u16Size,  pFolderMapping->pMapName->u16Size));
+                    rc = VERR_INVALID_PARAMETER;
+                }
+                else
+                {
+                    pString->u16Length = pFolderMapping->pMapName->u16Length;
+                    memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2,
+                           pFolderMapping->pMapName->u16Size);
+                    rc = VINF_SUCCESS;
+                }
+            }
         }
         else
-        {
-            pString->u16Length = pFolderMapping->pMapName->u16Length;
-            memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2,
-                   pFolderMapping->pMapName->u16Size);
-        }
+            rc = VERR_FILE_NOT_FOUND;
     }
     else
-        rc = VERR_FILE_NOT_FOUND;
+        rc = VERR_INVALID_PARAMETER;
 
     LogFlow(("vbsfMappingsQuery:Name return rc = %Rrc\n", rc));
-
     return rc;
 }
@@ -540,4 +603,62 @@
     return rc;
 }
+
+/**
+ * Implements SHFL_FN_QUERY_MAP_INFO.
+ * @since VBox 6.0
+ */
+int vbsfMappingsQueryInfo(PSHFLCLIENTDATA pClient, SHFLROOT root, PSHFLSTRING pNameBuf, PSHFLSTRING pMntPtBuf,
+                          uint64_t *pfFlags, uint32_t *puVersion)
+{
+    LogFlow(("vbsfMappingsQueryInfo: pClient=%p root=%d\n", pClient, root));
+
+    /* Resolve the root handle. */
+    int rc;
+    PMAPPING pFolderMapping = vbsfMappingGetByRoot(root);
+    if (pFolderMapping)
+    {
+        if (pFolderMapping->fValid)
+        {
+            /*
+             * Produce the output.
+             */
+            *puVersion = g_auRootHandleVersions[root];
+
+            *pfFlags = 0;
+            if (pFolderMapping->fWritable)
+                *pfFlags |= SHFL_MIF_WRITABLE;
+            if (pFolderMapping->fAutoMount)
+                *pfFlags |= SHFL_MIF_AUTO_MOUNT;
+            if (pFolderMapping->fHostCaseSensitive)
+                *pfFlags |= SHFL_MIF_HOST_ICASE;
+            if (pFolderMapping->fGuestCaseSensitive)
+                *pfFlags |= SHFL_MIF_GUEST_ICASE;
+            if (pFolderMapping->fSymlinksCreate)
+                *pfFlags |= SHFL_MIF_SYMLINK_CREATION;
+
+            int rc2;
+            if (pClient->fu32Flags & SHFL_CF_UTF8)
+            {
+                rc = ShflStringCopyUtf16BufAsUtf8(pNameBuf, pFolderMapping->pMapName);
+                rc2 = ShflStringCopyUtf16BufAsUtf8(pMntPtBuf, pFolderMapping->pAutoMountPoint);
+            }
+            else
+            {
+                rc = ShflStringCopy(pNameBuf, pFolderMapping->pMapName, sizeof(RTUTF16));
+                rc2 = ShflStringCopy(pMntPtBuf, pFolderMapping->pAutoMountPoint, sizeof(RTUTF16));
+            }
+            if (RT_SUCCESS(rc))
+                rc = rc2;
+        }
+        else
+            rc = VERR_FILE_NOT_FOUND;
+    }
+    else
+        rc = VERR_INVALID_PARAMETER;
+    LogFlow(("vbsfMappingsQueryInfo: returns %Rrc\n", rc));
+    return rc;
+}
+
+
 
 #ifdef UNITTEST
@@ -662,2 +783,117 @@
     return rc;
 }
+
+/**
+ * SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES implementation.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS on change.
+ * @retval  VINF_TRY_AGAIN on resume.
+ * @retval  VINF_HGCM_ASYNC_EXECUTE if waiting.
+ * @retval  VERR_CANCELLED if cancelled.
+ * @retval  VERR_OUT_OF_RESOURCES if there are too many pending waits.
+ *
+ * @param   pClient     The calling client.
+ * @param   hCall       The call handle.
+ * @param   pParm       The parameter (32-bit).
+ * @param   fRestored   Set if this is a call restored & resubmitted from saved
+ *                      state.
+ * @since   VBox 6.0
+ */
+int vbsfMappingsWaitForChanges(PSHFLCLIENTDATA pClient, VBOXHGCMCALLHANDLE hCall, PVBOXHGCMSVCPARM pParm, bool fRestored)
+{
+    /*
+     * Return immediately if the fodler mappings have changed since last call
+     * or if we got restored from saved state (adding of global folders, etc).
+     */
+    uint32_t uCurVersion = g_uFolderMappingsVersion;
+    if (   pParm->u.uint32 != uCurVersion
+        || fRestored
+        || (pClient->fu32Flags & SHFL_CF_CANCEL_NEXT_WAIT) )
+    {
+        int rc = VINF_SUCCESS;
+        if (pClient->fu32Flags & SHFL_CF_CANCEL_NEXT_WAIT)
+        {
+            pClient->fu32Flags &= ~SHFL_CF_CANCEL_NEXT_WAIT;
+            rc = VERR_CANCELLED;
+        }
+        else if (fRestored)
+        {
+            rc = VINF_TRY_AGAIN;
+            if (pParm->u.uint32 == uCurVersion)
+                uCurVersion = uCurVersion != UINT32_C(0x55555555) ? UINT32_C(0x55555555) : UINT32_C(0x99999999);
+        }
+        Log(("vbsfMappingsWaitForChanges: Version %#x -> %#x, returning %Rrc immediately.\n", pParm->u.uint32, uCurVersion, rc));
+        pParm->u.uint32 = uCurVersion;
+        return rc;
+    }
+
+    /*
+     * Setup a wait if we can.
+     */
+    if (g_cMappingChangeWaiters < 64)
+    {
+        PSHFLMAPPINGSWAIT pWait = (PSHFLMAPPINGSWAIT)RTMemAlloc(sizeof(*pWait));
+        if (pWait)
+        {
+            pWait->pClient = pClient;
+            pWait->hCall   = hCall;
+            pWait->pParm   = pParm;
+
+            RTListAppend(&g_MappingsChangeWaiters, &pWait->ListEntry);
+            g_cMappingChangeWaiters += 1;
+            return VINF_HGCM_ASYNC_EXECUTE;
+        }
+        return VERR_NO_MEMORY;
+    }
+    LogRelMax(32, ("vbsfMappingsWaitForChanges: Too many threads waiting for changes!\n"));
+    return VERR_OUT_OF_RESOURCES;
+}
+
+/**
+ * SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS implementation.
+ *
+ * @returns VINF_SUCCESS
+ * @param   pClient     The calling client to cancel all waits for.
+ * @since   VBox 6.0
+ */
+int vbsfMappingsCancelChangesWaits(PSHFLCLIENTDATA pClient)
+{
+    uint32_t const uCurVersion = g_uFolderMappingsVersion;
+
+    PSHFLMAPPINGSWAIT pCur, pNext;
+    RTListForEachSafe(&g_MappingsChangeWaiters, pCur, pNext, SHFLMAPPINGSWAIT, ListEntry)
+    {
+        if (pCur->pClient == pClient)
+        {
+            RTListNodeRemove(&pCur->ListEntry);
+            pCur->pParm->u.uint32 = uCurVersion;
+            g_pHelpers->pfnCallComplete(pCur->hCall, VERR_CANCELLED);
+            RTMemFree(pCur);
+        }
+    }
+
+    /* Set a flag to make sure the next SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES doesn't block.
+       This should help deal with races between this call and a thread about to do a wait. */
+    pClient->fu32Flags |= SHFL_CF_CANCEL_NEXT_WAIT;
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Wakes up all clients waiting on
+ */
+static void vbsfMappingsWakeupAllWaiters(void)
+{
+    uint32_t const uCurVersion = ++g_uFolderMappingsVersion;
+
+    PSHFLMAPPINGSWAIT pCur, pNext;
+    RTListForEachSafe(&g_MappingsChangeWaiters, pCur, pNext, SHFLMAPPINGSWAIT, ListEntry)
+    {
+        RTListNodeRemove(&pCur->ListEntry);
+        pCur->pParm->u.uint32 = uCurVersion;
+        g_pHelpers->pfnCallComplete(pCur->hCall, VERR_CANCELLED);
+        RTMemFree(pCur);
+    }
+}
+
Index: /trunk/src/VBox/HostServices/SharedFolders/mappings.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedFolders/mappings.h	(revision 75406)
+++ /trunk/src/VBox/HostServices/SharedFolders/mappings.h	(revision 75407)
@@ -38,4 +38,5 @@
     bool        fPlaceholder;           /**< Mapping does not exist in the VM settings but the guest
                                              still has. fMissing is always true for this mapping. */
+    bool        fLoadedRootId;          /**< Set if vbsfMappingLoaded has found this mapping already. */
 } MAPPING;
 /** Pointer to a MAPPING structure. */
@@ -50,13 +51,18 @@
 int vbsfMappingsRemove(PSHFLSTRING pMapName);
 
-int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings);
+int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, bool fOnlyAutoMounts, PSHFLMAPPING pMappings, uint32_t *pcMappings);
 int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString);
 int vbsfMappingsQueryWritable(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fWritable);
 int vbsfMappingsQueryAutoMount(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fAutoMount);
 int vbsfMappingsQuerySymlinksCreate(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fSymlinksCreate);
+int vbsfMappingsQueryInfo(PSHFLCLIENTDATA pClient, SHFLROOT root, PSHFLSTRING pNameBuf, PSHFLSTRING pMntPtBuf,
+                          uint64_t *pfFlags, uint32_t *puVersion);
 
 int vbsfMapFolder(PSHFLCLIENTDATA pClient, PSHFLSTRING pszMapName, RTUTF16 delimiter,
                   bool fCaseSensitive, SHFLROOT *pRoot);
 int vbsfUnmapFolder(PSHFLCLIENTDATA pClient, SHFLROOT root);
+
+int vbsfMappingsWaitForChanges(PSHFLCLIENTDATA pClient, VBOXHGCMCALLHANDLE hCall, PVBOXHGCMSVCPARM pParm, bool fRestored);
+int vbsfMappingsCancelChangesWaits(PSHFLCLIENTDATA pClient);
 
 const char* vbsfMappingsQueryHostRoot(SHFLROOT root);
@@ -65,5 +71,5 @@
 bool vbsfIsHostMappingCaseSensitive(SHFLROOT root);
 
-int vbsfMappingLoaded(const PMAPPING pLoadedMapping, SHFLROOT root);
+int vbsfMappingLoaded(MAPPING const *pLoadedMapping, SHFLROOT root);
 PMAPPING vbsfMappingGetByRoot(SHFLROOT root);
 
Index: /trunk/src/VBox/HostServices/SharedFolders/service.cpp
===================================================================
--- /trunk/src/VBox/HostServices/SharedFolders/service.cpp	(revision 75406)
+++ /trunk/src/VBox/HostServices/SharedFolders/service.cpp	(revision 75407)
@@ -26,4 +26,5 @@
 #include <iprt/string.h>
 #include <iprt/assert.h>
+#include <VBox/AssertGuest.h>
 #include <VBox/vmm/ssm.h>
 #include <VBox/vmm/pdmifs.h>
@@ -237,5 +238,5 @@
                 rc = SSMR3GetMem(pSSM, pFolderName, cb);
                 AssertRCReturn(rc, rc);
-                AssertReturn(pFolderName->u16Length < cb && pFolderName->u16Size < pFolderName->u16Length,
+                AssertReturn(pFolderName->u16Size < cb && pFolderName->u16Length < pFolderName->u16Size,
                              SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
                                                "Bad folder name string: %#x/%#x cb=%#x\n",
@@ -267,5 +268,5 @@
             rc = SSMR3GetMem(pSSM, pMapName, cb);
             AssertRCReturn(rc, rc);
-            AssertReturn(pMapName->u16Length < cb && pMapName->u16Size < pMapName->u16Length,
+            AssertReturn(pMapName->u16Size < cb && pMapName->u16Length < pMapName->u16Size,
                          SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
                                            "Bad map name string: %#x/%#x cb=%#x\n",
@@ -293,5 +294,5 @@
                 rc = SSMR3GetMem(pSSM, pAutoMountPoint, cb);
                 AssertRCReturn(rc, rc);
-                AssertReturn(pAutoMountPoint->u16Length < cb && pAutoMountPoint->u16Size < pAutoMountPoint->u16Length,
+                AssertReturn(pAutoMountPoint->u16Size < cb && pAutoMountPoint->u16Length < pAutoMountPoint->u16Size,
                              SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
                                                "Bad auto mount point string: %#x/%#x cb=%#x\n",
@@ -331,5 +332,6 @@
 }
 
-static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
+                                   void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
 {
     RT_NOREF1(u32ClientID);
@@ -388,8 +390,11 @@
                     if (fu32Flags & SHFL_MF_UTF8)
                         pClient->fu32Flags |= SHFL_CF_UTF8;
-                    if (fu32Flags & SHFL_MF_AUTOMOUNT)
-                        pClient->fu32Flags |= SHFL_MF_AUTOMOUNT;
-
-                    rc = vbsfMappingsQuery(pClient, pMappings, &cMappings);
+                    /// @todo r=bird: Someone please explain this amusing code (r63916):
+                    //if (fu32Flags & SHFL_MF_AUTOMOUNT)
+                    //    pClient->fu32Flags |= SHFL_MF_AUTOMOUNT;
+                    //
+                    //rc = vbsfMappingsQuery(pClient, pMappings, &cMappings);
+
+                    rc = vbsfMappingsQuery(pClient, RT_BOOL(fu32Flags & SHFL_MF_AUTOMOUNT), pMappings, &cMappings);
                     if (RT_SUCCESS(rc))
                     {
@@ -1295,4 +1300,56 @@
         }
 
+        case SHFL_FN_QUERY_MAP_INFO:
+        {
+            Log(("SharedFolders host service: svnCall: SHFL_FN_QUERY_MAP_INFO\n"));
+
+            /* Validate input: */
+            rc = VERR_INVALID_PARAMETER;
+            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_QUERY_MAP_INFO);
+            ASSERT_GUEST_BREAK(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); /* root */
+            ASSERT_GUEST_BREAK(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR);   /* name */
+            PSHFLSTRING  pNameBuf  = (PSHFLSTRING)paParms[1].u.pointer.addr;
+            ASSERT_GUEST_BREAK(ShflStringIsValidOut(pNameBuf, paParms[1].u.pointer.size));
+            ASSERT_GUEST_BREAK(paParms[2].type == VBOX_HGCM_SVC_PARM_PTR);   /* mountPoint */
+            PSHFLSTRING  pMntPtBuf = (PSHFLSTRING)paParms[2].u.pointer.addr;
+            ASSERT_GUEST_BREAK(ShflStringIsValidOut(pMntPtBuf, paParms[2].u.pointer.size));
+            ASSERT_GUEST_BREAK(paParms[3].type == VBOX_HGCM_SVC_PARM_64BIT); /* flags */
+            ASSERT_GUEST_BREAK(!(paParms[3].u.uint64 & ~(SHFL_MIQF_DRIVE_LETTER | SHFL_MIQF_PATH))); /* flags */
+            ASSERT_GUEST_BREAK(paParms[4].type == VBOX_HGCM_SVC_PARM_32BIT); /* version */
+
+            /* Execute the function: */
+            rc = vbsfMappingsQueryInfo(pClient, paParms[0].u.uint32, pNameBuf, pMntPtBuf,
+                                       &paParms[3].u.uint64, &paParms[4].u.uint32);
+            break;
+        }
+
+        case SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES:
+        {
+            Log(("SharedFolders host service: svnCall: SHFL_FN_WAIT_FOR_CHANGES\n"));
+
+            /* Validate input: */
+            rc = VERR_INVALID_PARAMETER;
+            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES);
+            ASSERT_GUEST_BREAK(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); /* uFolderMappingsVersion */
+
+            /* Execute the function: */
+            rc = vbsfMappingsWaitForChanges(pClient, callHandle, paParms, g_pHelpers->pfnIsCallRestored(callHandle));
+            fAsynchronousProcessing = rc == VINF_HGCM_ASYNC_EXECUTE;
+            break;
+        }
+
+        case SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS:
+        {
+            Log(("SharedFolders host service: svnCall: SHFL_FN_CANCEL_WAIT_FOR_CHANGES\n"));
+
+            /* Validate input: */
+            rc = VERR_INVALID_PARAMETER;
+            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS);
+
+            /* Execute the function: */
+            rc = vbsfMappingsCancelChangesWaits(pClient);
+            break;
+        }
+
         default:
         {
Index: /trunk/src/VBox/HostServices/SharedFolders/shfl.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedFolders/shfl.h	(revision 75406)
+++ /trunk/src/VBox/HostServices/SharedFolders/shfl.h	(revision 75407)
@@ -43,4 +43,8 @@
 #define SHFL_CF_SYMLINKS         (0x00000008)
 
+/** The call to SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES will return immediately
+ *  because of a SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS call. */
+#define SHFL_CF_CANCEL_NEXT_WAIT (0x00000010)
+
 /** @} */
 
Index: /trunk/src/VBox/HostServices/SharedFolders/vbsf.h
===================================================================
--- /trunk/src/VBox/HostServices/SharedFolders/vbsf.h	(revision 75406)
+++ /trunk/src/VBox/HostServices/SharedFolders/vbsf.h	(revision 75407)
@@ -1,2 +1,3 @@
+/* $Id$ */
 /** @file
  * VBox Shared Folders header.
@@ -15,6 +16,6 @@
  */
 
-#ifndef __VBSF__H
-#define __VBSF__H
+#ifndef ___vbsf_h___
+#define ___vbsf_h___
 
 #include "shfl.h"
@@ -41,3 +42,4 @@
 int vbsfSymlink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pNewPath, SHFLSTRING *pOldPath, SHFLFSOBJINFO *pInfo);
 
-#endif /* __VBSF__H */
+#endif /* !___vbsf_h___ */
+
