VirtualBox

Changeset 75407 in vbox


Ignore:
Timestamp:
Nov 12, 2018 8:06:57 PM (6 years ago)
Author:
vboxsync
Message:

VBoxSharedFolders,VBoxService,VBoxTray: New go at auto mounting shared folders, now also at runtime. bugref:3544

  • Added three new functions to the shared folders service:
    1. query mountpoint and everything else about a shared folder.
    2. wait for folder (mappings) config changes.
    3. cancel such waits.
  • Relaxed some of the check wrt placeholder folders so that the GUI can succesfully make changes to a folder while it is being used. The old code would end up failing if the guest was using the folder because of a (placeholder) duplicate.
  • Ran into some weird weird flag passing between service.cpp and vbsfMappingsQuery via pClient->fu32Flags. Didn't make sense to me and clashed with a new flag I added for the wait cancellation, so I changed it to use a parameter (fOnlyAutoMounts) for the purpose.
  • Pointed out that vbsfMappingsQuery is weird in a the way it doesn't return an overflow indicator, meaning that the guest library wrapper's checks for VINF_BUFFER_OVERFLOW is pointless.
  • In VBoxService I've reimplemented the automounter subservice. Only tested with a windows 7 guest so far. Highlights:
    • Use host specified mount points / drive letters.
    • Adjust to changes in mapping configuration.
    • Mappings should be global on windows guests, given that VBoxService runs under the System user (only verified on Win7).
  • One TODO is that I would like to try relocate a mapping that's not on the specified mount point once the mount point is freed up.
  • VBoxTray no longer maps shared folder on startup.
Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/VBoxGuestLib.h

    r74535 r75407  
    682682                                                  PVBGLR3SHAREDFOLDERMAPPING *ppaMappings, uint32_t *pcMappings);
    683683VBGLR3DECL(void)    VbglR3SharedFolderFreeMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings);
    684 VBGLR3DECL(int)     VbglR3SharedFolderGetName(HGCMCLIENTID  idClient,uint32_t u32Root, char **ppszName);
    685 VBGLR3DECL(int)     VbglR3SharedFolderGetMountPrefix(char **ppszPrefix);
    686 VBGLR3DECL(int)     VbglR3SharedFolderGetMountDir(char **ppszDir);
     684VBGLR3DECL(int)     VbglR3SharedFolderGetName(HGCMCLIENTID  idClient,uint32_t u32Root, char **ppszName); /**< @todo r=bird: GET functions return the value, not a status code!*/
     685VBGLR3DECL(int)     VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags,
     686                                                      char **ppszName, char **ppszMountPoint,
     687                                                      uint64_t *pfFlags, uint32_t *puRootIdVersion);
     688VBGLR3DECL(int)     VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion);
     689VBGLR3DECL(int)     VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient);
     690
     691VBGLR3DECL(int)     VbglR3SharedFolderGetMountPrefix(char **ppszPrefix); /**< @todo r=bird: GET functions return the value, not a status code! */
     692VBGLR3DECL(int)     VbglR3SharedFolderGetMountDir(char **ppszDir);       /**< @todo r=bird: GET functions return the value, not a status code! */
    687693/** @}  */
    688694# endif /* VBOX_WITH_SHARED_FOLDERS defined */
  • trunk/include/VBox/shflsvc.h

    r75384 r75407  
    7777 * @{
    7878 */
    79 /** Query mappings changes. */
     79/** Query mappings changes.
     80 * @note Description is currently misleading, it will always return all
     81 *       current mappings with SHFL_MS_NEW status.  Only modification is the
     82 *       SHFL_MF_AUTOMOUNT flag that causes filtering out non-auto mounts. */
    8083#define SHFL_FN_QUERY_MAPPINGS      (1)
    81 /** Query mappings changes. */
     84/** Query the name of a map. */
    8285#define SHFL_FN_QUERY_MAP_NAME      (2)
    8386/** Open/create object. */
     
    118121 * @since VBox 4.0  */
    119122#define SHFL_FN_SET_SYMLINKS        (20)
     123/** Query information about a map.
     124 * @since VBox 6.0  */
     125#define SHFL_FN_QUERY_MAP_INFO      (21)
     126/** Wait for changes to the mappings.
     127 * @since VBox 6.0  */
     128#define SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES       (22)
     129/** Cancel all waits for changes to the mappings for the calling client.
     130 * The wait calls will return VERR_CANCELLED.
     131 * @since VBox 6.0  */
     132#define SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS   (23)
    120133/** @} */
    121134
     
    240253 * Helper for copying one string into another.
    241254 *
    242  * @returns pDst
    243  * @param   pDst        The destination string. Assumed to be the same size as
    244  *                      the source.
     255 * @returns IPRT status code.
     256 * @retval  VERR_BUFFER_OVERFLOW and pDst->u16Length set to source length.
     257 * @param   pDst        The destination string.
    245258 * @param   pSrc        The source string.
    246  */
    247 DECLINLINE(PSHFLSTRING) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
    248 {
     259 * @param   cbTerm      The size of the string terminator.
     260 */
     261DECLINLINE(int) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc, size_t cbTerm)
     262{
     263    int rc = VINF_SUCCESS;
     264    if (pDst->u16Size >= pSrc->u16Length + cbTerm)
     265    {
     266        memcpy(&pDst->String, &pSrc->String, pSrc->u16Length);
     267        switch (cbTerm)
     268        {
     269            default:
     270            case 2: pDst->String.ach[pSrc->u16Length + 1] = '\0'; RT_FALL_THROUGH();
     271            case 1: pDst->String.ach[pSrc->u16Length + 0] = '\0'; break;
     272            case 0: break;
     273        }
     274    }
     275    else
     276        rc = VERR_BUFFER_OVERFLOW;
    249277    pDst->u16Length = pSrc->u16Length;
    250     pDst->u16Size   = pSrc->u16Size;
    251     memcpy(&pDst->String, &pSrc->String, pSrc->u16Size);
    252     return pDst;
     278    return rc;
    253279}
    254280
     
    265291    PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Size);
    266292    if (pDst)
    267         return ShflStringCopy(pDst, pSrc);
     293    {
     294        pDst->u16Length = pSrc->u16Length;
     295        pDst->u16Size   = pSrc->u16Size;
     296        memcpy(&pDst->String, &pSrc->String, pSrc->u16Size);
     297    }
    268298    return pDst;
    269299}
     
    355385    AssertMsgFailed(("rc=%Rrc cwcConversion=%#x\n", rc, cwcConversion));
    356386    return NULL;
     387}
     388
     389/**
     390 * Copies a UTF-8 string to a buffer as UTF-16.
     391 *
     392 * @returns IPRT status code.
     393 * @param   pDst        The destination buffer.
     394 * @param   pszSrc      The source string.
     395 * @param   cchSrc      The source string length, or RTSTR_MAX.
     396 */
     397DECLINLINE(int) ShflStringCopyUtf8AsUtf16(PSHFLSTRING pDst, const char *pszSrc, size_t cchSrc)
     398{
     399    int rc;
     400    size_t cwcDst = 0;
     401    if (pDst->u16Size >= sizeof(RTUTF16))
     402    {
     403        PRTUTF16 pwszDst = pDst->String.utf16;
     404        rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, pDst->u16Size / sizeof(RTUTF16), &cwcDst);
     405    }
     406    else
     407    {
     408        RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcDst);
     409        rc = VERR_BUFFER_OVERFLOW;
     410    }
     411    pDst->u16Length = (uint16_t)(cwcDst * sizeof(RTUTF16));
     412    return rc != VERR_BUFFER_OVERFLOW || cwcDst < UINT16_MAX / sizeof(RTUTF16) ? rc : VERR_TOO_MUCH_DATA;
     413}
     414
     415/**
     416 * Copies a UTF-8 string buffer to another buffer as UTF-16
     417 *
     418 * @returns IPRT status code.
     419 * @param   pDst        The destination buffer (UTF-16).
     420 * @param   pSrc        The source buffer (UTF-8).
     421 */
     422DECLINLINE(int) ShflStringCopyUtf8BufAsUtf16(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
     423{
     424    return ShflStringCopyUtf8AsUtf16(pDst, pSrc->String.ach, pSrc->u16Length);
     425}
     426
     427/**
     428 * Copies a UTF-16 string to a buffer as UTF-8
     429 *
     430 * @returns IPRT status code.
     431 * @param   pDst        The destination buffer.
     432 * @param   pwszSrc     The source string.
     433 * @param   cwcSrc      The source string length, or RTSTR_MAX.
     434 */
     435DECLINLINE(int) ShflStringCopyUtf16AsUtf8(PSHFLSTRING pDst, PCRTUTF16 pwszSrc, size_t cwcSrc)
     436{
     437    int rc;
     438    size_t cchDst = 0;
     439    if (pDst->u16Size > 0)
     440    {
     441        char *pszDst = pDst->String.ach;
     442        rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, pDst->u16Size, &cchDst);
     443    }
     444    else
     445    {
     446        RTUtf16CalcUtf8LenEx(pwszSrc, cwcSrc, &cchDst);
     447        rc = VERR_BUFFER_OVERFLOW;
     448    }
     449    pDst->u16Length = (uint16_t)cchDst;
     450    return rc != VERR_BUFFER_OVERFLOW || cchDst < UINT16_MAX ? rc : VERR_TOO_MUCH_DATA;
     451}
     452
     453/**
     454 * Copies a UTF-16 string buffer to another buffer as UTF-8
     455 *
     456 * @returns IPRT status code.
     457 * @param   pDst        The destination buffer (UTF-8).
     458 * @param   pSrc        The source buffer (UTF-16).
     459 */
     460DECLINLINE(int) ShflStringCopyUtf16BufAsUtf8(PSHFLSTRING pDst, PCSHFLSTRING pSrc)
     461{
     462    return ShflStringCopyUtf16AsUtf8(pDst, pSrc->String.utf16, pSrc->u16Length / sizeof(RTUTF16));
    357463}
    358464
     
    802908typedef struct _SHFLMAPPING
    803909{
    804     /** Mapping status. */
     910    /** Mapping status.
     911     * @note Currently always set to SHFL_MS_NEW.  */
    805912    uint32_t u32Status;
    806913    /** Root handle. */
     
    15581665
    15591666
     1667/** @name SHFL_FN_QUERY_MAP_INFO
     1668 * @{
     1669 */
     1670/** Query flag: Guest prefers drive letters as mount points. */
     1671#define SHFL_MIQF_DRIVE_LETTER      RT_BIT_64(0)
     1672/** Query flag: Guest prefers paths as mount points. */
     1673#define SHFL_MIQF_PATH              RT_BIT_64(1)
     1674
     1675/** Set if writable. */
     1676#define SHFL_MIF_WRITABLE           RT_BIT_64(0)
     1677/** Indicates that the mapping should be auto-mounted. */
     1678#define SHFL_MIF_AUTO_MOUNT         RT_BIT_64(1)
     1679/** Set if host is case insensitive. */
     1680#define SHFL_MIF_HOST_ICASE         RT_BIT_64(2)
     1681/** Set if guest is case insensitive. */
     1682#define SHFL_MIF_GUEST_ICASE        RT_BIT_64(3)
     1683/** Symbolic link creation is allowed. */
     1684#define SHFL_MIF_SYMLINK_CREATION   RT_BIT_64(4)
     1685
     1686/** Parameters structure. */
     1687typedef struct VBoxSFQueryMapInfo
     1688{
     1689    /** Common header. */
     1690    VBGLIOCHGCMCALL callInfo;
     1691    /** 32-bit, in: SHFLROOT - root handle of the mapping to query. */
     1692    HGCMFunctionParameter root;
     1693    /** pointer, in/out: SHFLSTRING buffer for the name. */
     1694    HGCMFunctionParameter name;
     1695    /** pointer, in/out: SHFLSTRING buffer for the auto mount point. */
     1696    HGCMFunctionParameter mountPoint;
     1697    /** 64-bit, in: SHFL_MIQF_XXX; out: SHFL_MIF_XXX. */
     1698    HGCMFunctionParameter flags;
     1699    /** 32-bit, out: Root ID version number - root handle reuse guard. */
     1700    HGCMFunctionParameter rootIdVersion;
     1701} VBoxSFQueryMapInfo;
     1702/** Number of parameters */
     1703#define SHFL_CPARMS_QUERY_MAP_INFO (5)
     1704/** @} */
     1705
     1706
     1707/** @name SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES
     1708 *
     1709 * Returns VINF_SUCCESS on change and VINF_TRY_AGAIN when restored from saved
     1710 * state.  If the guest makes too many calls (max 64) VERR_OUT_OF_RESOURCES will
     1711 * be returned.
     1712 *
     1713 * @{
     1714 */
     1715/** Parameters structure. */
     1716typedef struct VBoxSFWaitForMappingsChanges
     1717{
     1718    /** Common header. */
     1719    VBGLIOCHGCMCALL callInfo;
     1720    /** 32-bit, in/out: The mappings configuration version.
     1721     * On input the client sets it to the last config it knows about, on return
     1722     * it holds the current version.  */
     1723    HGCMFunctionParameter version;
     1724} VBoxSFWaitForMappingsChanges;
     1725/** Number of parameters */
     1726#define SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES       (1)
     1727/** @} */
     1728
     1729
     1730/** @name SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS
     1731 * @{
     1732 */
     1733/** Number of parameters */
     1734#define SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS   (0)
     1735/** @} */
     1736
    15601737
    15611738/** @name SHFL_FN_ADD_MAPPING
  • trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk

    r70378 r75407  
    6565        VBoxLA.cpp
    6666endif
    67 ifdef VBOX_WITH_SHARED_FOLDERS
    68  VBoxTray_DEFS     += VBOX_WITH_SHARED_FOLDERS
    69  VBoxTray_SOURCES  += \
    70         VBoxSharedFolders.cpp
    71  VBoxTray_LIBS.win += \
    72         mpr.lib
    73 endif
     67## Now handled by VBoxService.
     68#ifdef VBOX_WITH_SHARED_FOLDERS
     69# VBoxTray_DEFS     += VBOX_WITH_SHARED_FOLDERS
     70# VBoxTray_SOURCES  += \
     71#       VBoxSharedFolders.cpp
     72# VBoxTray_LIBS.win += \
     73#       mpr.lib
     74#endif
    7475ifdef VBOX_WITH_WDDM
    7576 VBoxTray_DEFS   += VBOX_WITH_WDDM
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp

    r74528 r75407  
    3131#include "VBoxVRDP.h"
    3232#include "VBoxHostVersion.h"
    33 #include "VBoxSharedFolders.h"
     33#ifdef VBOX_WITH_SHARED_FOLDERS
     34# include "VBoxSharedFolders.h"
     35#endif
    3436#ifdef VBOX_WITH_DRAG_AND_DROP
    3537# include "VBoxDnD.h"
     
    825827            if (RT_SUCCESS(rc))
    826828            {
     829#ifdef VBOX_WITH_SHARED_FOLDERS
    827830                /* Do the Shared Folders auto-mounting stuff. */
    828831                rc = VBoxSharedFoldersAutoMount();
     832#endif
    829833                if (RT_SUCCESS(rc))
    830834                {
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibSharedFolders.cpp

    r69500 r75407  
    161161            }
    162162        }
    163     } while (rc == VINF_BUFFER_OVERFLOW);
     163    } while (rc == VINF_BUFFER_OVERFLOW); /** @todo r=bird: This won't happen because the weird host code never returns it. */
    164164
    165165    if (   RT_FAILURE(rc)
     
    211211
    212212    int         rc;
    213     uint32_t    cbString = SHFLSTRING_HEADER_SIZE + SHFL_MAX_LEN;
     213    uint32_t    cbString = SHFLSTRING_HEADER_SIZE + SHFL_MAX_LEN * sizeof(RTUTF16);
    214214    PSHFLSTRING pString = (PSHFLSTRING)RTMemAlloc(cbString);
    215215    if (pString)
     
    233233    }
    234234    else
    235         rc = VERR_INVALID_PARAMETER;
    236     return rc;
    237 }
     235        rc = VERR_NO_MEMORY;
     236    return rc;
     237}
     238
     239
     240/**
     241 * Queries information about a shared folder.
     242 *
     243 * @returns VBox status code.
     244 *
     245 * @param   idClient        The client ID.
     246 * @param   idRoot          The root ID of the folder to query information for.
     247 * @param   fQueryFlags     SHFL_MIQF_XXX.
     248 * @param   ppszName        Where to return the pointer to the name.
     249 *                          Free using RTStrFree.  Optional.
     250 * @param   ppszMountPoint  Where to return the pointer to the auto mount point.
     251 *                          Free using RTStrFree.  Optional.
     252 * @param   pfFlags         Where to return the flags (SHFL_MIF_XXX).  Optional.
     253 * @param   puRootIdVersion where to return the root ID version.  Optional.
     254 *                          This helps detecting root-id reuse.
     255 *
     256 * @remarks ASSUMES UTF-16 connection to host.
     257 */
     258VBGLR3DECL(int) VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags,
     259                                                  char **ppszName, char **ppszMountPoint,
     260                                                  uint64_t *pfFlags, uint32_t *puRootIdVersion)
     261{
     262    AssertReturn(!(fQueryFlags & ~(SHFL_MIQF_DRIVE_LETTER | SHFL_MIQF_PATH), VERR_INVALID_FLAGS);
     263
     264    /*
     265     * Allocate string buffers first.
     266     */
     267    int rc;
     268    PSHFLSTRING pNameBuf    = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (SHFL_MAX_LEN + 1) * sizeof(RTUTF16));
     269    PSHFLSTRING pMountPoint = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (260          + 1) * sizeof(RTUTF16));
     270    if (pNameBuf && pMountPoint)
     271    {
     272        ShflStringInitBuffer(pNameBuf,    SHFLSTRING_HEADER_SIZE + (SHFL_MAX_LEN + 1) * sizeof(RTUTF16));
     273        ShflStringInitBuffer(pMountPoint, SHFLSTRING_HEADER_SIZE + (260          + 1) * sizeof(RTUTF16));
     274
     275        /*
     276         * Make the call.
     277         */
     278        VBoxSFQueryMapInfo Msg;
     279        VBGL_HGCM_HDR_INIT(&Msg.callInfo, idClient, SHFL_FN_QUERY_MAP_INFO, 5);
     280        VbglHGCMParmUInt32Set(&Msg.root, idRoot);
     281        VbglHGCMParmPtrSet(&Msg.name, pNameBuf, SHFLSTRING_HEADER_SIZE + pNameBuf->u16Size);
     282        VbglHGCMParmPtrSet(&Msg.mountPoint, pMountPoint, SHFLSTRING_HEADER_SIZE + pMountPoint->u16Size);
     283        VbglHGCMParmUInt64Set(&Msg.flags, fQueryFlags);
     284        VbglHGCMParmUInt32Set(&Msg.rootIdVersion, 0);
     285
     286        rc = VbglR3HGCMCall(&Msg.callInfo, sizeof(Msg));
     287        if (RT_SUCCESS(rc))
     288        {
     289            /*
     290             * Copy out the results.
     291             */
     292            if (puRootIdVersion)
     293                *puRootIdVersion = Msg.rootIdVersion.u.value64;
     294
     295            if (pfFlags)
     296                *pfFlags = Msg.flags.u.value64;
     297
     298            if (ppszName)
     299            {
     300                *ppszName = NULL;
     301                rc = RTUtf16ToUtf8Ex(pNameBuf->String.utf16, pNameBuf->u16Length / sizeof(RTUTF16), ppszName, 0, NULL);
     302            }
     303
     304            if (ppszMountPoint && RT_SUCCESS(rc))
     305            {
     306                *ppszMountPoint = NULL;
     307                rc = RTUtf16ToUtf8Ex(pMountPoint->String.utf16, pMountPoint->u16Length / sizeof(RTUTF16), ppszMountPoint, 0, NULL);
     308                if (RT_FAILURE(rc) && ppszName)
     309                {
     310                    RTStrFree(*ppszName);
     311                    *ppszName = NULL;
     312                }
     313            }
     314        }
     315    }
     316    else
     317        rc = VERR_NO_MEMORY;
     318    RTMemFree(pMountPoint);
     319    RTMemFree(pNameBuf);
     320    return rc;
     321}
     322
     323
     324/**
     325 * Waits for changes to the mappings (add, remove, restore).
     326 *
     327 * @returns VBox status code.
     328 * @retval  VINF_SUCCESS on change
     329 * @retval  VINF_TRY_AGAIN on restore.
     330 * @retval  VERR_OUT_OF_RESOURCES if there are too many guys waiting.
     331 *
     332 * @param   idClient        The client ID.
     333 * @param   uPrevVersion    The mappings config version number returned the last
     334 *                          time around.  Use UINT32_MAX for the first call.
     335 * @param   puCurVersion    Where to return the current mappings config version.
     336 */
     337VBGLR3DECL(int) VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion)
     338{
     339    VBoxSFWaitForMappingsChanges Msg;
     340    VBGL_HGCM_HDR_INIT(&Msg.callInfo, idClient, SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES, 1);
     341    VbglHGCMParmUInt32Set(&Msg.version, uPrevVersion);
     342
     343    int rc = VbglR3HGCMCall(&Msg.callInfo, sizeof(Msg));
     344
     345    *puCurVersion = Msg.version.u.value32;
     346    return rc;
     347}
     348
     349
     350/**
     351 * Cancels all threads currently waiting for changes for this client.
     352 *
     353 * @returns VBox status code.
     354 * @param   idClient        The client ID.
     355 */
     356VBGLR3DECL(int) VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient)
     357{
     358    VBGLIOCHGCMCALL CallInfo;
     359    VBGL_HGCM_HDR_INIT(&CallInfo, idClient, SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS, 0);
     360
     361    return VbglR3HGCMCall(&CallInfo, sizeof(CallInfo));
     362}
     363
    238364
    239365/**
     
    258384        {
    259385#endif
     386/** @todo r=bird: Inconsistent! VbglR3SharedFolderGetMountDir does not return a default. */
    260387            rc = RTStrDupEx(ppszPrefix, "sf_");
    261388#ifdef VBOX_WITH_GUEST_PROPS
     
    266393    return rc;
    267394}
     395
    268396
    269397/**
  • trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk

    r70346 r75407  
    4040if1of ($(KBUILD_TARGET), linux)
    4141 # CPU hotplugging.
    42  VBOX_WITH_VBOXSERVICE_CPUHOTPLUG   := 1
    43 endif
    44 
     42VBOX_WITH_VBOXSERVICE_CPUHOTPLUG    := 1
     43endif
     44
     45# Page Sharing (Page Fusion).
    4546if1of ($(KBUILD_TARGET), win)
    46  # Page Sharing (Page Fusion).
    47  VBOX_WITH_VBOXSERVICE_PAGE_SHARING := 1
     47VBOX_WITH_VBOXSERVICE_PAGE_SHARING  := 1
    4848endif
    4949
    5050ifdef VBOX_WITH_GUEST_PROPS
    51  VBOX_WITH_VBOXSERVICE_VMINFO       := 1
    52 endif
    53 
     51VBOX_WITH_VBOXSERVICE_VMINFO        := 1
     52endif
     53
     54# Guest Control.
    5455ifdef VBOX_WITH_GUEST_CONTROL
    55  # Guest Control.
    56  VBOX_WITH_VBOXSERVICE_CONTROL      := 1
     56VBOX_WITH_VBOXSERVICE_CONTROL       := 1
    5757endif
    5858
     
    6868# Define features to be activate.
    6969VBoxService_DEFS         += \
    70         $(if $(VBOX_WITH_VBOXSERVICE_CONTROL),VBOX_WITH_VBOXSERVICE_CONTROL,)           \
    71         $(if $(VBOX_WITH_VBOXSERVICE_CPUHOTPLUG),VBOX_WITH_VBOXSERVICE_CPUHOTPLUG,)     \
    72         $(if $(VBOX_WITH_VBOXSERVICE_MANAGEMENT),VBOX_WITH_VBOXSERVICE_MANAGEMENT,)     \
     70        $(if $(VBOX_WITH_VBOXSERVICE_CONTROL),VBOX_WITH_VBOXSERVICE_CONTROL,) \
     71        $(if $(VBOX_WITH_VBOXSERVICE_CPUHOTPLUG),VBOX_WITH_VBOXSERVICE_CPUHOTPLUG,) \
     72        $(if $(VBOX_WITH_VBOXSERVICE_MANAGEMENT),VBOX_WITH_VBOXSERVICE_MANAGEMENT,) \
    7373        $(if $(VBOX_WITH_VBOXSERVICE_PAGE_SHARING),VBOX_WITH_VBOXSERVICE_PAGE_SHARING,) \
    74         $(if $(VBOX_WITH_VBOXSERVICE_TIMESYNC),VBOX_WITH_VBOXSERVICE_TIMESYNC,)         \
    75         $(if $(VBOX_WITH_VBOXSERVICE_TOOLBOX),VBOX_WITH_VBOXSERVICE_TOOLBOX,)           \
     74        $(if $(VBOX_WITH_VBOXSERVICE_TIMESYNC),VBOX_WITH_VBOXSERVICE_TIMESYNC,) \
     75        $(if $(VBOX_WITH_VBOXSERVICE_TOOLBOX),VBOX_WITH_VBOXSERVICE_TOOLBOX,) \
    7676        $(if $(VBOX_WITH_VBOXSERVICE_VMINFO),VBOX_WITH_VBOXSERVICE_VMINFO,)
    7777
    7878# Import global defines.
    79 VBoxService_DEFS         +=                                       \
    80         $(if $(VBOX_WITH_DBUS),VBOX_WITH_DBUS,)                   \
     79VBoxService_DEFS         += \
     80        $(if $(VBOX_WITH_DBUS),VBOX_WITH_DBUS,) \
    8181        $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,) \
    82         $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,)     \
     82        $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
    8383        $(if $(VBOX_WITH_HGCM),VBOX_WITH_HGCM,)
    8484
     
    8888VBoxService_DEFS.os2      = VBOX_WITH_HGCM VBOX_WITH_VBOXSERVICE_CLIPBOARD
    8989
    90 ifdef VBOX_WITH_SHARED_FOLDERS
    91  # darwin freebsd
    92  if1of ($(KBUILD_TARGET), linux solaris)
    93   VBoxService_DEFS       += VBOX_WITH_SHARED_FOLDERS
    94  endif
    95 endif
    96 
    97 VBoxService_SOURCES       =  \
    98         VBoxService.cpp      \
     90VBoxService_SOURCES       = \
     91        VBoxService.cpp \
    9992        VBoxServiceUtils.cpp \
    10093        VBoxServiceStats.cpp
    10194
    10295ifdef VBOX_WITH_VBOXSERVICE_TIMESYNC
    103  VBoxService_SOURCES     += \
     96VBoxService_SOURCES      += \
    10497        VBoxServiceTimeSync.cpp
    10598endif
    10699
    107100ifdef VBOX_WITH_VBOXSERVICE_TOOLBOX
    108  VBoxService_SOURCES     += \
     101VBoxService_SOURCES      += \
    109102        VBoxServiceToolBox.cpp
    110103endif
    111104
    112105ifdef VBOX_WITH_VBOXSERVICE_CONTROL
    113  VBoxService_SOURCES     +=      \
    114         VBoxServiceControl.cpp        \
     106VBoxService_SOURCES      += \
     107        VBoxServiceControl.cpp  \
    115108        VBoxServiceControlProcess.cpp \
    116109        VBoxServiceControlSession.cpp
     
    118111
    119112ifdef VBOX_WITH_VBOXSERVICE_MANAGEMENT
    120  VBoxService_SOURCES     += \
    121         VBoxServiceBalloon.cpp
    122  VBoxService_DEFS        += $(if $(VBOX_WITH_MEMBALLOON),VBOX_WITH_MEMBALLOON,)
     113VBoxService_SOURCES      += \
     114        VBoxServiceBalloon.cpp
     115 ifdef VBOX_WITH_MEMBALLOON
     116VBoxService_DEFS         += VBOX_WITH_MEMBALLOON
     117 endif
    123118endif
    124119
    125120if1of ($(KBUILD_TARGET), win)
    126  VBoxService_SOURCES    += \
     121VBoxService_SOURCES      += \
    127122        VBoxServicePageSharing.cpp
    128123endif
    129124
    130125ifdef VBOX_WITH_VBOXSERVICE_VMINFO
    131  VBoxService_SOURCES.win += \
     126VBoxService_SOURCES.win += \
    132127        VBoxServiceVMInfo-win.cpp
    133  VBoxService_SOURCES     += \
    134         VBoxServiceVMInfo.cpp    \
    135         VBoxServicePropCache.cpp
     128VBoxService_SOURCES      += \
     129        VBoxServiceVMInfo.cpp \
     130        VBoxServicePropCache.cpp
    136131endif
    137132
    138133ifdef VBOX_WITH_VBOXSERVICE_CPUHOTPLUG
    139  VBoxService_SOURCES     += \
     134VBoxService_SOURCES      += \
    140135        VBoxServiceCpuHotPlug.cpp
    141136endif
    142137
    143138ifdef VBOX_WITH_SHARED_FOLDERS
    144  if1of ($(KBUILD_TARGET), linux solaris)
    145   VBoxService_SOURCES          += \
     139 if1of ($(KBUILD_TARGET), win linux solaris)
     140VBoxService_DEFS         += VBOX_WITH_SHARED_FOLDERS
     141VBoxService_SOURCES      += \
    146142        VBoxServiceAutoMount.cpp
    147   VBoxService_SOURCES.linux    += \
     143VBoxService_SOURCES.linux += \
    148144        ../../linux/sharedfolders/vbsfmount.c
     145VBoxService_LIBS.win     += \
     146        Mpr.Lib
    149147 endif
    150148endif
     
    160158VBoxService_LDFLAGS.darwin = -framework IOKit
    161159
    162 VBoxService_LIBS        += \
     160VBoxService_LIBS         += \
    163161        $(VBOX_LIB_IPRT_GUEST_R3) \
    164162        $(VBOX_LIB_VBGL_R3) \
     
    170168ifdef VBOX_WITH_DBUS
    171169 if1of ($(KBUILD_TARGET), linux solaris) # FreeBSD?
    172   VBoxService_LIBS       += \
     170VBoxService_LIBS         += \
    173171        dl
    174172 endif
    175173endif
    176174ifdef VBOX_WITH_GUEST_PROPS
    177  VBoxService_LIBS.win    += \
    178         Secur32.lib \
    179         WtsApi32.lib \
    180         Psapi.lib
    181  VBoxService_LIBS.solaris += \
    182         nsl \
     175VBoxService_LIBS.win     += \
     176        Secur32.lib \
     177        WtsApi32.lib \
     178        Psapi.lib
     179VBoxService_LIBS.solaris += \
     180        nsl \
    183181        kstat \
    184182        contract
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceAutoMount.cpp

    r69500 r75407  
    3838*********************************************************************************************************************************/
    3939#include <iprt/assert.h>
     40#include <iprt/ctype.h>
    4041#include <iprt/dir.h>
    4142#include <iprt/mem.h>
    4243#include <iprt/path.h>
     44#include <iprt/semaphore.h>
     45#include <iprt/sort.h>
    4346#include <iprt/string.h>
    44 #include <iprt/semaphore.h>
    4547#include <VBox/VBoxGuestLib.h>
     48#include <VBox/shflsvc.h>
    4649#include "VBoxServiceInternal.h"
    4750#include "VBoxServiceUtils.h"
    4851
    49 #include <errno.h>
    50 #include <grp.h>
    51 #include <sys/mount.h>
    52 #ifdef RT_OS_SOLARIS
    53 # include <sys/mntent.h>
    54 # include <sys/mnttab.h>
    55 # include <sys/vfs.h>
     52#ifdef RT_OS_WINDOWS
     53#elif defined(RT_OS_OS2)
    5654#else
    57 # include <mntent.h>
    58 # include <paths.h>
     55# include <errno.h>
     56# include <grp.h>
     57# include <sys/mount.h>
     58# ifdef RT_OS_SOLARIS
     59#  include <sys/mntent.h>
     60#  include <sys/mnttab.h>
     61#  include <sys/vfs.h>
     62# elif defined(RT_OS_LINUX)
     63#  include <mntent.h>
     64#  include <paths.h>
     65RT_C_DECLS_BEGIN
     66#  include "../../linux/sharedfolders/vbsfmount.h"
     67RT_C_DECLS_END
     68# else
     69#  error "Port me!"
     70# endif
     71# include <unistd.h>
    5972#endif
    60 #include <unistd.h>
    61 
    62 RT_C_DECLS_BEGIN
    63 #include "../../linux/sharedfolders/vbsfmount.h"
    64 RT_C_DECLS_END
    65 
    66 #ifdef RT_OS_SOLARIS
    67 # define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR       "/mnt"
    68 #else
    69 # define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR       "/media"
     73
     74
     75
     76/*********************************************************************************************************************************
     77*   Defined Constants And Macros                                                                                                 *
     78*********************************************************************************************************************************/
     79/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
     80 * Default mount directory (unix only).
     81 */
     82#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR
     83# ifdef RT_OS_SOLARIS
     84#  define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR      "/mnt"
     85# else
     86#  define VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR      "/media"
     87# endif
     88#endif
     89
     90/** @def VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
     91 * Default mount prefix (unix only).
     92 */
     93#ifndef VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX
     94# define VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX   "sf_"
    7095#endif
    7196
     
    78103#endif
    79104
     105/** @def VBOXSERVICE_AUTOMOUNT_MIQF
     106 * The drive letter / path mount point flag.  */
     107#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     108# define VBOXSERVICE_AUTOMOUNT_MIQF             SHFL_MIQF_DRIVE_LETTER
     109#else
     110# define VBOXSERVICE_AUTOMOUNT_MIQF             SHFL_MIQF_PATH
     111#endif
     112
     113
     114/*********************************************************************************************************************************
     115*   Structures and Typedefs                                                                                                      *
     116*********************************************************************************************************************************/
     117/**
     118 * Automounter mount table entry.
     119 *
     120 * This holds the information returned by SHFL_FN_QUERY_MAP_INFO and
     121 * additional mount state info.  We only keep entries for mounted mappings.
     122 */
     123typedef struct VBSVCAUTOMOUNTERENTRY
     124{
     125    /** The root ID. */
     126    uint32_t     idRoot;
     127    /** The root ID version. */
     128    uint32_t     uRootIdVersion;
     129    /** Map info flags, SHFL_MIF_XXX. */
     130    uint64_t     fFlags;
     131    /** The shared folder (mapping) name. */
     132    char        *pszName;
     133    /** The configured mount point, NULL if none. */
     134    char        *pszMountPoint;
     135    /** The actual mount point, NULL if not mount.  */
     136    char        *pszActualMountPoint;
     137} VBSVCAUTOMOUNTERENTRY;
     138/** Pointer to an automounter entry.   */
     139typedef VBSVCAUTOMOUNTERENTRY *PVBSVCAUTOMOUNTERENTRY;
     140
     141/** Automounter mount table. */
     142typedef struct VBSVCAUTOMOUNTERTABLE
     143{
     144    /** Current number of entries in the array. */
     145    uint32_t                cEntries;
     146    /** Max number of entries the array can hold w/o growing it. */
     147    uint32_t                cAllocated;
     148    /** Pointer to an array of entry pointers. */
     149    PVBSVCAUTOMOUNTERENTRY   *papEntries;
     150} VBSVCAUTOMOUNTERTABLE;
     151/** Pointer to an automounter mount table.   */
     152typedef  VBSVCAUTOMOUNTERTABLE *PVBSVCAUTOMOUNTERTABLE;
     153
    80154
    81155/*********************************************************************************************************************************
     
    83157*********************************************************************************************************************************/
    84158/** The semaphore we're blocking on. */
    85 static RTSEMEVENTMULTI  g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
     159static RTSEMEVENTMULTI  g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
    86160/** The Shared Folders service client ID. */
    87 static uint32_t         g_SharedFoldersSvcClientID = 0;
     161static uint32_t         g_idClientSharedFolders = 0;
     162/** Set if we can wait on changes to the mappings. */
     163static bool             g_fHostSupportsWaitAndInfoQuery = false;
     164
     165#ifdef RT_OS_OS2
     166/** The attachment tag we use to identify attchments that belongs to us. */
     167static char const       g_szTag[] = "VBoxAutomounter";
     168#elif defined(RT_OS_SOLARIS)
     169/** Dummy mount option that lets us identify mounts that belongs to us. */
     170static char const       g_szTag[] = ",VBoxService=auto";
     171#endif
     172
    88173
    89174
     
    91176 * @interface_method_impl{VBOXSERVICE,pfnInit}
    92177 */
    93 static DECLCALLBACK(int) vbsvcAutoMountInit(void)
    94 {
    95     VGSvcVerbose(3, "vbsvcAutoMountInit\n");
    96 
    97     int rc = RTSemEventMultiCreate(&g_AutoMountEvent);
     178static DECLCALLBACK(int) vbsvcAutomounterInit(void)
     179{
     180    VGSvcVerbose(3, "vbsvcAutomounterInit\n");
     181
     182    int rc = RTSemEventMultiCreate(&g_hAutoMountEvent);
    98183    AssertRCReturn(rc, rc);
    99184
    100     rc = VbglR3SharedFolderConnect(&g_SharedFoldersSvcClientID);
     185    rc = VbglR3SharedFolderConnect(&g_idClientSharedFolders);
    101186    if (RT_SUCCESS(rc))
    102187    {
    103         VGSvcVerbose(3, "vbsvcAutoMountInit: Service Client ID: %#x\n", g_SharedFoldersSvcClientID);
     188        VGSvcVerbose(3, "vbsvcAutomounterInit: Service Client ID: %#x\n", g_idClientSharedFolders);
     189        g_fHostSupportsWaitAndInfoQuery = RT_SUCCESS(VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders));
    104190    }
    105191    else
     
    109195        if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
    110196        {
    111             VGSvcVerbose(0, "vbsvcAutoMountInit: Shared Folders service is not available\n");
     197            VGSvcVerbose(0, "vbsvcAutomounterInit: Shared Folders service is not available\n");
    112198            rc = VERR_SERVICE_DISABLED;
    113199        }
    114200        else
    115201            VGSvcError("Control: Failed to connect to the Shared Folders service! Error: %Rrc\n", rc);
    116         RTSemEventMultiDestroy(g_AutoMountEvent);
    117         g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
     202        RTSemEventMultiDestroy(g_hAutoMountEvent);
     203        g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
    118204    }
    119205
     
    122208
    123209
     210#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) /* The old code: */
     211
    124212/**
    125213 * @todo Integrate into RTFsQueryMountpoint()?
    126214 */
    127 static bool vbsvcAutoMountShareIsMounted(const char *pszShare, char *pszMountPoint, size_t cbMountPoint)
    128 {
    129     AssertPtrReturn(pszShare, VERR_INVALID_PARAMETER);
    130     AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
    131     AssertReturn(cbMountPoint, VERR_INVALID_PARAMETER);
     215static bool vbsvcAutoMountShareIsMountedOld(const char *pszShare, char *pszMountPoint, size_t cbMountPoint)
     216{
     217    AssertPtrReturn(pszShare, false);
     218    AssertPtrReturn(pszMountPoint, false);
     219    AssertReturn(cbMountPoint, false);
    132220
    133221    bool fMounted = false;
     222
     223# if defined(RT_OS_SOLARIS)
    134224    /** @todo What to do if we have a relative path in mtab instead
    135225     *       of an absolute one ("temp" vs. "/media/temp")?
    136226     * procfs contains the full path but not the actual share name ...
    137227     * FILE *pFh = setmntent("/proc/mounts", "r+t"); */
    138 #ifdef RT_OS_SOLARIS
    139228    FILE *pFh = fopen(_PATH_MOUNTED, "r");
    140229    if (!pFh)
    141         VGSvcError("vbsvcAutoMountShareIsMounted: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
     230        VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
    142231    else
    143232    {
     
    154243        fclose(pFh);
    155244    }
    156 #else
     245# elif defined(RT_OS_LINUX)
    157246    FILE *pFh = setmntent(_PATH_MOUNTED, "r+t"); /** @todo r=bird: why open it for writing? (the '+') */
    158247    if (pFh == NULL)
    159         VGSvcError("vbsvcAutoMountShareIsMounted: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
     248        VGSvcError("vbsvcAutoMountShareIsMountedOld: Could not open mount tab '%s'!\n", _PATH_MOUNTED);
    160249    else
    161250    {
     
    172261        endmntent(pFh);
    173262    }
    174 #endif
    175 
    176     VGSvcVerbose(4, "vbsvcAutoMountShareIsMounted: Share '%s' at mount point '%s' = %s\n",
     263# else
     264#  error "PORTME!"
     265# endif
     266
     267    VGSvcVerbose(4, "vbsvcAutoMountShareIsMountedOld: Share '%s' at mount point '%s' = %s\n",
    177268                       pszShare, fMounted ? pszMountPoint : "<None>", fMounted ? "Yes" : "No");
    178269    return fMounted;
     
    186277 * @param   pszMountPoint   The shared folder mount point.
    187278 */
    188 static int vbsvcAutoMountUnmount(const char *pszMountPoint)
     279static int vbsvcAutoMountUnmountOld(const char *pszMountPoint)
    189280{
    190281    AssertPtrReturn(pszMountPoint, VERR_INVALID_PARAMETER);
     
    217308 * @param   pOpts           For getting the group ID.
    218309 */
    219 static int vbsvcAutoMountPrepareMountPoint(const char *pszMountPoint, const char *pszShareName, vbsf_mount_opts *pOpts)
     310static int vbsvcAutoMountPrepareMountPointOld(const char *pszMountPoint, const char *pszShareName, vbsf_mount_opts *pOpts)
    220311{
    221312    AssertPtrReturn(pOpts, VERR_INVALID_PARAMETER);
     
    235326                if (rc == VERR_WRITE_PROTECT)
    236327                {
    237                     VGSvcVerbose(3, "vbsvcAutoMountPrepareMountPoint: Mount directory '%s' already is used/mounted\n",
    238                                        pszMountPoint);
     328                    VGSvcVerbose(3, "vbsvcAutoMountPrepareMountPointOld: Mount directory '%s' already is used/mounted\n",
     329                                 pszMountPoint);
    239330                    rc = VINF_SUCCESS;
    240331                }
    241332                else
    242                     VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not set mode %RTfmode for mount directory '%s', rc = %Rrc\n",
    243                                      fMode, pszMountPoint, rc);
     333                    VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set mode %RTfmode for mount directory '%s', rc = %Rrc\n",
     334                               fMode, pszMountPoint, rc);
    244335            }
    245336        }
    246337        else
    247             VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not set permissions for mount directory '%s', rc = %Rrc\n",
    248                              pszMountPoint, rc);
     338            VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not set permissions for mount directory '%s', rc = %Rrc\n",
     339                       pszMountPoint, rc);
    249340    }
    250341    else
    251         VGSvcError("vbsvcAutoMountPrepareMountPoint: Could not create mount directory '%s' with mode %RTfmode, rc = %Rrc\n",
    252                          pszMountPoint, fMode, rc);
     342        VGSvcError("vbsvcAutoMountPrepareMountPointOld: Could not create mount directory '%s' with mode %RTfmode, rc = %Rrc\n",
     343                   pszMountPoint, fMode, rc);
    253344    return rc;
    254345}
     
    265356 * @param   pOpts           The mount options.
    266357 */
    267 static int vbsvcAutoMountSharedFolder(const char *pszShareName, const char *pszMountPoint, struct vbsf_mount_opts *pOpts)
    268 {
    269     AssertPtr(pOpts);
    270 
    271     int rc = VINF_SUCCESS;
    272     bool fSkip = false;
    273 
    274     /* Already mounted? */
    275     char szAlreadyMountedTo[RTPATH_MAX];
    276     if (vbsvcAutoMountShareIsMounted(pszShareName, szAlreadyMountedTo, sizeof(szAlreadyMountedTo)))
    277     {
    278         fSkip = true;
    279         /* Do if it not mounted to our desired mount point */
    280         if (RTStrICmp(pszMountPoint, szAlreadyMountedTo))
    281         {
    282             VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted to '%s', unmounting ...\n",
    283                                pszShareName, szAlreadyMountedTo);
    284             rc = vbsvcAutoMountUnmount(szAlreadyMountedTo);
    285             if (RT_SUCCESS(rc))
    286                 fSkip = false;
    287             else
    288                 VGSvcError("vbsvcAutoMountWorker: Failed to unmount '%s', %s (%d)! (rc=%Rrc)\n",
    289                                  szAlreadyMountedTo, strerror(errno), errno, rc); /** @todo errno isn't reliable at this point */
    290         }
    291         if (fSkip)
    292             VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted to '%s', skipping\n",
    293                                pszShareName, szAlreadyMountedTo);
    294     }
    295 
    296     if (!fSkip && RT_SUCCESS(rc))
    297         rc = vbsvcAutoMountPrepareMountPoint(pszMountPoint, pszShareName, pOpts);
    298     if (!fSkip && RT_SUCCESS(rc))
    299     {
    300 #ifdef RT_OS_SOLARIS
     358static int vbsvcAutoMountSharedFolderOld(const char *pszShareName, const char *pszMountPoint)
     359{
     360    /*
     361     * Linux and solaris share the same mount structure.
     362     */
     363    struct group *grp_vboxsf = getgrnam("vboxsf");
     364    if (!grp_vboxsf)
     365    {
     366        VGSvcError("vbsvcAutoMountWorker: Group 'vboxsf' does not exist\n");
     367        return VINF_SUCCESS;
     368    }
     369
     370    struct vbsf_mount_opts Opts =
     371    {
     372        0,                     /* uid */
     373        (int)grp_vboxsf->gr_gid, /* gid */
     374        0,                     /* ttl */
     375        0770,                  /* dmode, owner and group "vboxsf" have full access */
     376        0770,                  /* fmode, owner and group "vboxsf" have full access */
     377        0,                     /* dmask */
     378        0,                     /* fmask */
     379        0,                     /* ronly */
     380        0,                     /* sloppy */
     381        0,                     /* noexec */
     382        0,                     /* nodev */
     383        0,                     /* nosuid */
     384        0,                     /* remount */
     385        "\0",                  /* nls_name */
     386        NULL,                  /* convertcp */
     387    };
     388
     389    int rc = vbsvcAutoMountPrepareMountPointOld(pszMountPoint, pszShareName, &Opts);
     390    if (RT_SUCCESS(rc))
     391    {
     392# ifdef RT_OS_SOLARIS
     393        int fFlags = 0;
     394        if (Opts.ronly)
     395            fFlags |= MS_RDONLY;
    301396        char szOptBuf[MAX_MNTOPT_STR] = { '\0', };
    302         int fFlags = 0;
    303         if (pOpts->ronly)
    304             fFlags |= MS_RDONLY;
    305397        RTStrPrintf(szOptBuf, sizeof(szOptBuf), "uid=%d,gid=%d,dmode=%0o,fmode=%0o,dmask=%0o,fmask=%0o",
    306                     pOpts->uid, pOpts->gid, pOpts->dmode, pOpts->fmode, pOpts->dmask, pOpts->fmask);
     398                    Opts.uid, Opts.gid, Opts.dmode, Opts.fmode, Opts.dmask, Opts.fmask);
    307399        int r = mount(pszShareName,
    308400                      pszMountPoint,
     
    317409        else if (errno != EBUSY) /* Share is already mounted? Then skip error msg. */
    318410            VGSvcError("vbsvcAutoMountWorker: Could not mount shared folder '%s' to '%s', error = %s\n",
    319                              pszShareName, pszMountPoint, strerror(errno));
    320 
    321 #elif defined(RT_OS_LINUX)
     411                       pszShareName, pszMountPoint, strerror(errno));
     412
     413# else /* RT_OS_LINUX */
    322414        unsigned long fFlags = MS_NODEV;
    323415
     
    331423        mntinf.length       = sizeof(mntinf);
    332424
    333         mntinf.uid   = pOpts->uid;
    334         mntinf.gid   = pOpts->gid;
    335         mntinf.ttl   = pOpts->ttl;
    336         mntinf.dmode = pOpts->dmode;
    337         mntinf.fmode = pOpts->fmode;
    338         mntinf.dmask = pOpts->dmask;
    339         mntinf.fmask = pOpts->fmask;
     425        mntinf.uid   = Opts.uid;
     426        mntinf.gid   = Opts.gid;
     427        mntinf.ttl   = Opts.ttl;
     428        mntinf.dmode = Opts.dmode;
     429        mntinf.fmode = Opts.fmode;
     430        mntinf.dmask = Opts.dmask;
     431        mntinf.fmask = Opts.fmask;
    340432
    341433        strcpy(mntinf.name, pszShareName);
     
    351443            VGSvcVerbose(0, "vbsvcAutoMountWorker: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
    352444
    353             r = vbsfmount_complete(pszShareName, pszMountPoint, fFlags, pOpts);
     445            r = vbsfmount_complete(pszShareName, pszMountPoint, fFlags, &Opts);
    354446            switch (r)
    355447            {
     
    360452                case 1:
    361453                    VGSvcError("vbsvcAutoMountWorker: Could not update mount table (failed to create memstream): %s\n",
    362                                      strerror(errno));
     454                               strerror(errno));
    363455                    break;
    364456
     
    427519            }
    428520        }
    429 #else
    430 # error "PORTME"
    431 #endif
     521# endif
    432522    }
    433523    VGSvcVerbose(3, "vbsvcAutoMountWorker: Mounting returned with rc=%Rrc\n", rc);
     
    446536 * @param   uClientID       The shared folder service (HGCM) client ID.
    447537 */
    448 static int vbsvcAutoMountProcessMappings(PCVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
    449                                          const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
     538static int vbsvcAutoMountProcessMappingsOld(PCVBGLR3SHAREDFOLDERMAPPING paMappings, uint32_t cMappings,
     539                                            const char *pszMountDir, const char *pszSharePrefix, uint32_t uClientID)
    450540{
    451541    if (cMappings == 0)
     
    490580                    VGSvcVerbose(4, "vbsvcAutoMountWorker: Processing mount point '%s'\n", szMountPoint);
    491581
    492                     struct group *grp_vboxsf = getgrnam("vboxsf");
    493                     if (grp_vboxsf)
     582                    /*
     583                     * Already mounted?
     584                     */
     585                    /** @todo r-bird: this does not take into account that a shared folder could
     586                     *        be mounted twice... We're really just interested in whether the
     587                     *        folder is mounted on 'szMountPoint', no where else... */
     588                    bool fSkip = false;
     589                    char szAlreadyMountedOn[RTPATH_MAX];
     590                    if (vbsvcAutoMountShareIsMountedOld(pszShareName, szAlreadyMountedOn, sizeof(szAlreadyMountedOn)))
    494591                    {
    495                         struct vbsf_mount_opts mount_opts =
     592                        /* Do if it not mounted to our desired mount point */
     593                        if (RTStrICmp(szMountPoint, szAlreadyMountedOn))
    496594                        {
    497                             0,                     /* uid */
    498                             (int)grp_vboxsf->gr_gid, /* gid */
    499                             0,                     /* ttl */
    500                             0770,                  /* dmode, owner and group "vboxsf" have full access */
    501                             0770,                  /* fmode, owner and group "vboxsf" have full access */
    502                             0,                     /* dmask */
    503                             0,                     /* fmask */
    504                             0,                     /* ronly */
    505                             0,                     /* sloppy */
    506                             0,                     /* noexec */
    507                             0,                     /* nodev */
    508                             0,                     /* nosuid */
    509                             0,                     /* remount */
    510                             "\0",                  /* nls_name */
    511                             NULL,                  /* convertcp */
    512                         };
    513 
    514                         rc = vbsvcAutoMountSharedFolder(pszShareName, szMountPoint, &mount_opts);
     595                            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', unmounting ...\n",
     596                                         pszShareName, szAlreadyMountedOn);
     597                            rc = vbsvcAutoMountUnmountOld(szAlreadyMountedOn);
     598                            if (RT_SUCCESS(rc))
     599                                fSkip = false;
     600                            else
     601                                VGSvcError("vbsvcAutoMountWorker: Failed to unmount '%s', %s (%d)! (rc=%Rrc)\n",
     602                                           szAlreadyMountedOn, strerror(errno), errno, rc); /** @todo errno isn't reliable at this point */
     603                        }
     604                        if (fSkip)
     605                            VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder '%s' already mounted on '%s', skipping\n",
     606                                         pszShareName, szAlreadyMountedOn);
    515607                    }
    516                     else
    517                         VGSvcError("vbsvcAutoMountWorker: Group 'vboxsf' does not exist\n");
     608                    if (!fSkip)
     609                    {
     610                        /*
     611                         * Mount it.
     612                         */
     613                        rc = vbsvcAutoMountSharedFolderOld(pszShareName, szMountPoint);
     614                    }
    518615                }
    519616                else
     
    532629}
    533630
    534 
    535 /**
    536  * @interface_method_impl{VBOXSERVICE,pfnWorker}
    537  */
    538 static DECLCALLBACK(int) vbsvcAutoMountWorker(bool volatile *pfShutdown)
    539 {
    540     /*
    541      * Tell the control thread that it can continue
    542      * spawning services.
    543      */
    544     RTThreadUserSignal(RTThreadSelf());
    545 
     631#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) - the old code*/
     632
     633
     634/**
     635 * Service worker function for old host.
     636 *
     637 * This only mount stuff on startup.
     638 *
     639 * @returns VBox status code.
     640 * @param   pfShutdown          Shutdown indicator.
     641 */
     642static int vbsvcAutoMountWorkerOld(bool volatile *pfShutdown)
     643{
     644#if defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX)
     645    /*
     646     * We only do a single pass here.
     647     */
    546648    uint32_t cMappings;
    547649    PVBGLR3SHAREDFOLDERMAPPING paMappings;
    548     int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
     650    int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /* Only process auto-mounted folders */,
    549651                                           &paMappings, &cMappings);
    550652    if (   RT_SUCCESS(rc)
     
    564666            {
    565667                VGSvcVerbose(3, "vbsvcAutoMountWorker: Shared folder mount prefix set to '%s'\n", pszSharePrefix);
    566 #ifdef USE_VIRTUAL_SHARES
     668# ifdef USE_VIRTUAL_SHARES
    567669                /* Check for a fixed/virtual auto-mount share. */
    568                 if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount"))
    569                 {
     670                if (VbglR3SharedFolderExists(g_idClientSharedFolders, "vbsfAutoMount"))
    570671                    VGSvcVerbose(3, "vbsvcAutoMountWorker: Host supports auto-mount root\n");
    571                 }
    572672                else
    573673                {
    574 #endif
     674# endif
    575675                    VGSvcVerbose(3, "vbsvcAutoMountWorker: Got %u shared folder mappings\n", cMappings);
    576                     rc = vbsvcAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
    577 #ifdef USE_VIRTUAL_SHARES
     676                    rc = vbsvcAutoMountProcessMappingsOld(paMappings, cMappings, pszMountDir, pszSharePrefix,
     677                                                          g_idClientSharedFolders);
     678# ifdef USE_VIRTUAL_SHARES
    578679                }
    579 #endif
     680# endif
    580681                RTStrFree(pszSharePrefix);
    581682            } /* Mount share prefix. */
     
    593694        VGSvcVerbose(3, "vbsvcAutoMountWorker: No shared folder mappings found\n");
    594695
    595     /*
    596      * Because this thread is a one-timer at the moment we don't want to break/change
    597      * the semantics of the main thread's start/stop sub-threads handling.
     696#else
     697    int rc = VINF_SUCCESS;
     698#endif /* defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) */
     699
     700
     701    /*
     702     * Wait on shutdown (this used to be a silly RTThreadSleep(500) loop).
     703     */
     704    while (!*pfShutdown)
     705    {
     706        rc = RTSemEventMultiWait(g_hAutoMountEvent, RT_MS_1MIN);
     707        if (rc != VERR_TIMEOUT)
     708            break;
     709    }
     710
     711    VGSvcVerbose(3, "vbsvcAutoMountWorkerOld: Finished with rc=%Rrc\n", rc);
     712    return rc;
     713}
     714
     715#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
     716/**
     717 * Assembles the mount directory and prefix into @a pszDst.
     718 *
     719 * Will fall back on defaults if we have trouble with the configuration from the
     720 * host.  This ASSUMES that @a cbDst is rather large and won't cause trouble
     721 * with the default.
     722 *
     723 * @returns IPRT status code.
     724 * @param   pszDst          Where to return the prefix.
     725 * @param   cbDst           The size of the prefix buffer.
     726 */
     727static int vbsvcAutomounterQueryMountDirAndPrefix(char *pszDst, size_t cbDst)
     728{
     729    /*
     730     * Query the config first.
     731     */
     732    /* Mount directory: */
     733    const char *pszDir = VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR;
     734    char       *pszCfgDir;
     735    int rc = VbglR3SharedFolderGetMountDir(&pszCfgDir);
     736    if (RT_SUCCESS(rc))
     737    {
     738        if (*pszCfgDir == '/')
     739            pszDir = pszCfgDir;
     740    }
     741    else
     742        pszCfgDir = NULL;
     743
     744    /* Prefix: */
     745    const char *pszPrefix = VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX;
     746    char *pszCfgPrefix;
     747    rc = VbglR3SharedFolderGetMountPrefix(&pszCfgPrefix);
     748    if (RT_SUCCESS(rc))
     749    {
     750        if (   strchr(pszCfgPrefix, '/')  == NULL
     751            && strchr(pszCfgPrefix, '\\') == NULL
     752            && strcmp(pszCfgPrefix, "..") != 0)
     753            pszPrefix = pszCfgPrefix;
     754    }
     755    else
     756        pszCfgPrefix = NULL;
     757
     758    /*
     759     * Try combine the two.
     760     */
     761    rc = RTPathAbs(pszDir, pszDst, cbDst);
     762    if (RT_SUCCESS(rc))
     763    {
     764        if (*pszPrefix)
     765        {
     766            rc = RTPathAppend(pszDst, cbDst, pszPrefix);
     767            if (RT_FAILURE(rc))
     768                VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAppend(%s,,%s) -> %Rrc\n", pszDst, pszPrefix, rc);
     769        }
     770        else
     771        {
     772            rc = RTPathEnsureTrailingSeparator(pszDst, cbDst);
     773            if (RT_FAILURE(rc))
     774                VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathEnsureTrailingSeparator(%s) -> %Rrc\n", pszDst, rc);
     775        }
     776    }
     777    else
     778        VGSvcError("vbsvcAutomounterQueryMountDirAndPrefix: RTPathAbs(%s) -> %Rrc\n", rc);
     779
     780
     781    /*
     782     * Return the default dir + prefix if the above failed.
     783     */
     784    if (RT_FAILURE(rc))
     785    {
     786        rc = RTStrCopy(pszDst, cbDst, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR "/" VBOXSERVICE_AUTOMOUNT_DEFAULT_PREFIX);
     787        AssertRC(rc);
     788    }
     789
     790    RTStrFree(pszCfgDir);
     791    RTStrFree(pszCfgPrefix);
     792    return rc;
     793}
     794#endif /* !RT_OS_WINDOW && !RT_OS_OS2 */
     795
     796
     797/**
     798 * @callback_method_impl{FNRTSORTCMP, For sorting mount table by root ID. }
     799 */
     800static DECLCALLBACK(int) vbsvcAutomounterCompareEntry(void const *pvElement1, void const *pvElement2, void *pvUser)
     801{
     802    RT_NOREF_PV(pvUser);
     803    PVBSVCAUTOMOUNTERENTRY pEntry1 = (PVBSVCAUTOMOUNTERENTRY)pvElement1;
     804    PVBSVCAUTOMOUNTERENTRY pEntry2 = (PVBSVCAUTOMOUNTERENTRY)pvElement2;
     805    return pEntry1->idRoot < pEntry2->idRoot ? -1
     806         : pEntry1->idRoot > pEntry2->idRoot ? 1 : 0;
     807}
     808
     809
     810/**
     811 * Worker for vbsvcAutomounterPopulateTable for adding discovered entries.
     812 *
     813 * This is puts dummies in for missing values, depending on
     814 * vbsvcAutomounterPopulateTable to query them later.
     815 *
     816 * @returns VINF_SUCCESS or VERR_NO_MEMORY;
     817 * @param   pMountTable     The mount table to add an entry to.
     818 * @param   pszName         The shared folder name.
     819 * @param   pszMountPoint   The mount point.
     820 */
     821static int vbsvcAutomounterAddEntry(PVBSVCAUTOMOUNTERTABLE pMountTable, const char *pszName, const char *pszMountPoint)
     822{
     823    VGSvcVerbose(2, "vbsvcAutomounterAddEntry: %s -> %s\n", pszMountPoint, pszName);
     824    PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
     825    pEntry->idRoot              = UINT32_MAX;
     826    pEntry->uRootIdVersion      = UINT32_MAX;
     827    pEntry->fFlags              = UINT64_MAX;
     828    pEntry->pszName             = RTStrDup(pszName);
     829    pEntry->pszMountPoint       = NULL;
     830    pEntry->pszActualMountPoint = RTStrDup(pszMountPoint);
     831    if (pEntry->pszName && pEntry->pszActualMountPoint)
     832    {
     833        if (pMountTable->cEntries + 1 <= pMountTable->cAllocated)
     834        {
     835            pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
     836            return VINF_SUCCESS;
     837        }
     838
     839        void *pvNew = RTMemRealloc(pMountTable->papEntries, (pMountTable->cAllocated + 8) * sizeof(pMountTable->papEntries[0]));
     840        if (pvNew)
     841        {
     842            pMountTable->cAllocated += 8;
     843            pMountTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvNew;
     844
     845            pMountTable->papEntries[pMountTable->cEntries++] = pEntry;
     846            return VINF_SUCCESS;
     847        }
     848    }
     849    RTMemFree(pEntry->pszActualMountPoint);
     850    RTMemFree(pEntry->pszName);
     851    RTMemFree(pEntry);
     852    return VERR_NO_MEMORY;
     853}
     854
     855
     856/**
     857 * Populates the mount table as best we can with existing automount entries.
     858 *
     859 * @returns VINF_SUCCESS or VERR_NO_MEMORY;
     860 * @param   pMountTable     The mount table (empty).
     861 */
     862static int vbsvcAutomounterPopulateTable(PVBSVCAUTOMOUNTERTABLE pMountTable)
     863{
     864    int rc;
     865
     866#ifdef RT_OS_WINDOWS
     867    /*
     868     * Loop thru the drive letters and check out each of them using QueryDosDeviceW.
     869     */
     870    static const char s_szDevicePath[] = "\\Device\\VBoxMiniRdr\\;";
     871    for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
     872    {
     873        RTUTF16 const wszMountPoint[4] = { chDrive, ':', '\0', '\0' };
     874        RTUTF16       wszTargetPath[RTPATH_MAX];
     875        DWORD const   cwcResult = QueryDosDeviceW(wszMountPoint, wszTargetPath, RT_ELEMENTS(wszTargetPath));
     876        if (   cwcResult > sizeof(s_szDevicePath)
     877            && RTUtf16NICmpAscii(wszTargetPath, RT_STR_TUPLE(s_szDevicePath)) == 0)
     878        {
     879            PCRTUTF16 pwsz = &wszTargetPath[RT_ELEMENTS(s_szDevicePath) - 1];
     880            Assert(pwsz[-1] == ';');
     881            if (   (pwsz[0] & ~(RTUTF16)0x20) == chDrive
     882                && pwsz[1] == ':'
     883                && pwsz[2] == '\\')
     884            {
     885                /* For now we'll just use the special capitalization of the
     886                   "server" name to identify it as our work.  We could check
     887                   if the symlink is from \Global?? or \??, but that trick does
     888                   work for older OS versions (<= XP) or when running the
     889                   service manually for testing/wathever purposes. */
     890                /** @todo Modify the windows shared folder driver to allow tagging drives.*/
     891                if (RTUtf16NCmpAscii(&pwsz[3], RT_STR_TUPLE("VBoxSvr\\")) == 0)
     892                {
     893                    pwsz += 3 + 8;
     894                    if (*pwsz != '\\' && *pwsz)
     895                    {
     896                        /* The shared folder name should follow immediately after the server prefix. */
     897                        char *pszMountedName = NULL;
     898                        rc = RTUtf16ToUtf8(pwsz, &pszMountedName);
     899                        if (RT_SUCCESS(rc))
     900                        {
     901                            char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
     902                            rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
     903                            RTStrFree(pszMountedName);
     904                        }
     905                        if (RT_FAILURE(rc))
     906                            return rc;
     907                    }
     908                    else
     909                        VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Malformed, not ours: %ls -> %ls\n",
     910                                     wszMountPoint, wszTargetPath);
     911                }
     912                else
     913                    VGSvcVerbose(3, "vbsvcAutomounterPopulateTable: Not ours: %ls -> %ls\n", wszMountPoint, wszTargetPath);
     914            }
     915        }
     916    }
     917
     918#elif defined(RT_OS_OS2)
     919    /*
     920     * Just loop thru the drive letters and check the attachment of each.
     921     */
     922    for (char chDrive = 'Z'; chDrive >= 'A'; chDrive--)
     923    {
     924        char const szMountPoint[4] = { chDrive, ':', '\0', '\0' };
     925        union
     926        {
     927            FSQBUFFER2  FsQueryBuf;
     928            char        achPadding[1024];
     929        } uBuf;
     930        RT_ZERO(uBuf);
     931        ULONG  cbBuf = sizeof(uBuf) - 2;
     932        APIRET rcOs2 = DosQueryFSAttach(szMountPoint, 0, FSAIL_QUERYNAME, uBuf, &cbBuf);
     933        if (rcOs2 == NO_ERROR)
     934        {
     935            const char *pszFsdName = &uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
     936            if (   uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
     937                && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
     938            {
     939                const char *pszMountedName = &pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
     940                const char *pszTag         = strlen(pszMountedName) + 1; /* (Safe. Always two trailing zero bytes, see above.) */
     941                if (strcmp(pszTag, g_szTag) == 0)
     942                {
     943                    rc = vbsvcAutomounterAddEntry(pMountTable, pszMountedName, szMountPoint);
     944                    if (RT_FAILURE(rc))
     945                        return rc;
     946                }
     947            }
     948        }
     949    }
     950
     951#elif defined(RT_OS_LINUX)
     952    /*
     953     * Scan the mount table file for the mount point and then match file system
     954     * and device/share.  We identify our mounts by mount path + prefix for now,
     955     * but later we may use the same approach as on solaris.
     956     */
     957    char szMountPrefix[RTPATH_MAX];
     958    rc = vbsvcAutomounterQueryMountDirAndPrefix(szMountPrefix, sizeof(szMountPrefix));
     959    AssertRCReturn(rc, rc);
     960    size_t const cchMountPrefix = strlen(szMountPrefix);
     961
     962    FILE *pFile = setmntent(_PATH_MOUNTED, "r");
     963    if (pFile)
     964    {
     965        rc = VWRN_NOT_FOUND;
     966        struct mntent *pEntry;
     967        while ((pEntry = getmntent(pFile)) != NULL)
     968            if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
     969            {
     970                /** @todo add mount option for tagging a mount, make kernel show it by
     971                 *        implementing super_operations::show_options. */
     972                if (strncmp(pEntry->mnt_dir, szMountPrefix, cchMountPrefix) == 0)
     973                {
     974                    rc = vbsvcAutomounterAddEntry(pMountTable, pEntry->mnt_fsname, pEntry->mnt_dir);
     975                    if (RT_FAILURE(rc))
     976                    {
     977                        endmntent(pFile);
     978                        return rc;
     979                    }
     980                }
     981            }
     982        endmntent(pFile);
     983    }
     984    else
     985        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d) or '/proc/mounts' (errno=%d)\n",
     986                   _PATH_MOUNTED, errno);
     987    return rc;
     988
     989#elif defined(RT_OS_SOLARIS)
     990    /*
     991     * Look thru the system mount table and inspect the vboxsf mounts.
     992     */
     993    FILE *pFile = fopen(_PATH_MOUNTED, "r");
     994    if (pFile)
     995    {
     996        rc = VINF_SUCCESS;
     997        struct mnttab Entry;
     998        while (getmntent(pFile, &Entry) == 0)
     999            if (strcmp(Entry.mnt_fstype, "vboxsf") == 0)
     1000            {
     1001                /* Look for the dummy automounter option. */
     1002                if (   Entry.mnt_opts != NULL
     1003                    && strstr(Entry.mnt_opts, g_szTag) != NULL)
     1004                {
     1005                    rc = vbsvcAutomounterAddEntry(pMountTable, Entry.mnt_special, Entry.mnt_mountp);
     1006                    if (RT_FAILURE(rc))
     1007                    {
     1008                        fclose(pFile);
     1009                        return rc;
     1010                    }
     1011                }
     1012            }
     1013        fclose(pFile);
     1014    }
     1015    else
     1016        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
     1017
     1018#else
     1019# error "PORTME!"
     1020#endif
     1021
     1022    /*
     1023     * Try reconcile the detected folders with data from the host.
     1024     */
     1025    uint32_t                    cMappings = 0;
     1026    PVBGLR3SHAREDFOLDERMAPPING  paMappings = NULL;
     1027    rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
     1028    if (RT_SUCCESS(rc))
     1029    {
     1030        for (uint32_t i = 0; i < cMappings && RT_SUCCESS(rc); i++)
     1031        {
     1032            uint32_t const idRootSrc = paMappings[i].u32Root;
     1033
     1034            uint32_t uRootIdVer = UINT32_MAX;
     1035            uint64_t fFlags     = 0;
     1036            char    *pszName    = NULL;
     1037            char    *pszMntPt   = NULL;
     1038            int rc2 = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc,  VBOXSERVICE_AUTOMOUNT_MIQF,
     1039                                                        &pszName, &pszMntPt, &fFlags, &uRootIdVer);
     1040            if (RT_SUCCESS(rc2))
     1041            {
     1042                uint32_t iPrevHit = UINT32_MAX;
     1043                for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
     1044                {
     1045                    PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
     1046                    if (RTStrICmp(pEntry->pszName, pszName) == 0)
     1047                    {
     1048                        VGSvcVerbose(2, "vbsvcAutomounterPopulateTable: Identified %s -> %s: idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
     1049                                     pEntry->pszActualMountPoint, pEntry->pszName, idRootSrc, uRootIdVer, fFlags, pszMntPt);
     1050                        pEntry->fFlags         = fFlags;
     1051                        pEntry->idRoot         = idRootSrc;
     1052                        pEntry->uRootIdVersion = uRootIdVer;
     1053                        RTStrFree(pEntry->pszMountPoint);
     1054                        pEntry->pszMountPoint = RTStrDup(pszMntPt);
     1055                        if (!pEntry->pszMountPoint)
     1056                        {
     1057                            rc = VERR_NO_MEMORY;
     1058                            break;
     1059                        }
     1060
     1061                        /* If multiple mappings of the same folder, pick the first or the one
     1062                           with matching mount point. */
     1063                        if (iPrevHit == UINT32_MAX)
     1064                            iPrevHit = iTable;
     1065                        else if (RTPathCompare(pszMntPt, pEntry->pszActualMountPoint) == 0)
     1066                        {
     1067                            if (iPrevHit != UINT32_MAX)
     1068                                pMountTable->papEntries[iPrevHit]->uRootIdVersion -= 1;
     1069                            iPrevHit = iTable;
     1070                        }
     1071                        else
     1072                            pEntry->uRootIdVersion -= 1;
     1073                    }
     1074                }
     1075
     1076                RTStrFree(pszName);
     1077                RTStrFree(pszMntPt);
     1078            }
     1079            else
     1080                VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderQueryFolderInfo(%u) failed: %Rrc\n", idRootSrc, rc2);
     1081        }
     1082
     1083        VbglR3SharedFolderFreeMappings(paMappings);
     1084
     1085        /*
     1086         * Sort the table by root ID.
     1087         */
     1088        if (pMountTable->cEntries > 1)
     1089            RTSortApvShell((void **)pMountTable->papEntries, pMountTable->cEntries, vbsvcAutomounterCompareEntry, NULL);
     1090
     1091        for (uint32_t iTable = 0; iTable < pMountTable->cEntries; iTable++)
     1092        {
     1093            PVBSVCAUTOMOUNTERENTRY pEntry = pMountTable->papEntries[iTable];
     1094            if (pMountTable->papEntries[iTable]->idRoot != UINT32_MAX)
     1095                VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s idRoot=%u ver=%u fFlags=%#x AutoMntPt=%s\n",
     1096                             iTable, pEntry->pszActualMountPoint, pEntry->pszName, pEntry->idRoot, pEntry->uRootIdVersion,
     1097                             pEntry->fFlags, pEntry->pszMountPoint);
     1098            else
     1099                VGSvcVerbose(1, "vbsvcAutomounterPopulateTable: #%u: %s -> %s - not identified!\n",
     1100                             iTable, pEntry->pszActualMountPoint, pEntry->pszName);
     1101        }
     1102    }
     1103    else
     1104        VGSvcError("vbsvcAutomounterPopulateTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
     1105    return rc;
     1106}
     1107
     1108
     1109/**
     1110 * Checks whether the shared folder @a pszName is mounted on @a pszMountPoint.
     1111 *
     1112 * @returns Exactly one of the following IPRT status codes;
     1113 * @retval  VINF_SUCCESS if mounted
     1114 * @retval  VWRN_NOT_FOUND if nothing is mounted at @a pszMountPoint.
     1115 * @retval  VERR_RESOURCE_BUSY if a different shared folder is mounted there.
     1116 * @retval  VERR_ACCESS_DENIED if a non-shared folder file system is mounted
     1117 *          there.
     1118 *
     1119 * @param   pszMountPoint   The mount point to check.
     1120 * @param   pszName         The name of the shared folder (mapping).
     1121 */
     1122static int vbsvcAutomounterQueryMountPoint(const char *pszMountPoint, const char *pszName)
     1123{
     1124    VGSvcVerbose(4, "vbsvcAutomounterQueryMountPoint: pszMountPoint=%s pszName=%s\n", pszMountPoint, pszName);
     1125
     1126#ifdef RT_OS_WINDOWS
     1127    /*
     1128     * We could've used RTFsQueryType here but would then have to
     1129     * calling RTFsQueryLabel for the share name hint, ending up
     1130     * doing the same work twice.  We could also use QueryDosDeviceW,
     1131     * but output is less clear...
     1132     */
     1133    PRTUTF16 pwszMountPoint = NULL;
     1134    int rc = RTStrToUtf16(pszMountPoint, &pwszMountPoint);
     1135    if (RT_SUCCESS(rc))
     1136    {
     1137        DWORD   uSerial = 0;
     1138        DWORD   cchCompMax = 0;
     1139        DWORD   fFlags = 0;
     1140        RTUTF16 wszLabel[512];
     1141        RTUTF16 wszFileSystem[256];
     1142        RT_ZERO(wszLabel);
     1143        RT_ZERO(wszFileSystem);
     1144        if (GetVolumeInformationW(pwszMountPoint, wszLabel, RT_ELEMENTS(wszLabel) - 1, &uSerial, &cchCompMax, &fFlags,
     1145                                  wszFileSystem, RT_ELEMENTS(wszFileSystem) - 1))
     1146        {
     1147            if (RTUtf16ICmpAscii(wszFileSystem, "VBoxSharedFolderFS") == 0)
     1148            {
     1149                char *pszLabel = NULL;
     1150                rc = RTUtf16ToUtf8(wszLabel, &pszLabel);
     1151                if (RT_SUCCESS(rc))
     1152                {
     1153                    const char *pszMountedName = pszLabel;
     1154                    if (RTStrStartsWith(pszMountedName, "VBOX_"))
     1155                        pszMountedName += sizeof("VBOX_") - 1;
     1156                    if (RTStrICmp(pszMountedName, pszName) == 0)
     1157                    {
     1158                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
     1159                                     pszMountPoint, pszName);
     1160                        rc = VINF_SUCCESS;
     1161                    }
     1162                    else
     1163                    {
     1164                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
     1165                                     pszMountedName, pszMountPoint, pszName);
     1166                        rc = VERR_RESOURCE_BUSY;
     1167                    }
     1168                    RTStrFree(pszLabel);
     1169                }
     1170                else
     1171                {
     1172                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: RTUtf16ToUtf8(%ls,) failed: %Rrc\n", wszLabel, rc);
     1173                    rc = VERR_RESOURCE_BUSY;
     1174                }
     1175            }
     1176            else
     1177            {
     1178                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%ls' with label '%ls' mount at '%s', not '%s'...\n",
     1179                             wszFileSystem, wszLabel, pszMountPoint, pszName);
     1180                rc = VERR_ACCESS_DENIED;
     1181            }
     1182        }
     1183        else
     1184        {
     1185            rc = GetLastError();
     1186            if (rc != ERROR_PATH_NOT_FOUND || g_cVerbosity >= 4)
     1187                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: GetVolumeInformationW('%ls',,,,) failed: %u\n", pwszMountPoint, rc);
     1188            rc = VWRN_NOT_FOUND;
     1189        }
     1190        RTUtf16Free(pwszMountPoint);
     1191    }
     1192    else
     1193    {
     1194        VGSvcError("vbsvcAutomounterQueryMountPoint: RTStrToUtf16(%s,) -> %Rrc\n", pszMountPoint, rc);
     1195        rc = VWRN_NOT_FOUND;
     1196    }
     1197    return rc;
     1198
     1199#elif defined(RT_OS_OS2)
     1200    /*
     1201     * Query file system attachment info for the given drive letter.
     1202     */
     1203    union
     1204    {
     1205        FSQBUFFER2  FsQueryBuf;
     1206        char        achPadding[512];
     1207    } uBuf;
     1208    RT_ZERO(uBuf);
     1209
     1210    ULONG cbBuf = sizeof(uBuf);
     1211    APIRET rcOs2 = DosQueryFSAttach((PCSZ)pFsInfo->szMountpoint, 0, FSAIL_QUERYNAME, uBuf, &cbBuf);
     1212    int rc;
     1213    if (rcOs2 == NO_ERROR)
     1214    {
     1215        const char *pszFsdName = &uBuf.FsQueryBuf.szName[uBuf.FsQueryBuf.cbName + 1];
     1216        if (   uBuf.FsQueryBuf.iType == FSAT_REMOTEDRV
     1217            && RTStrICmpAscii(pszFsdName, "VBOXSF") == 0)
     1218        {
     1219            const char *pszMountedName = &pszFsdName[uBuf.FsQueryBuf.cbFSDName + 1];
     1220            if (RTStrICmp(pszMountedName, pszName) == 0)
     1221            {
     1222                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
     1223                             pszMountPoint, pszName);
     1224                rc = VINF_SUCCESS;
     1225            }
     1226            else
     1227            {
     1228                VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
     1229                             pszMountedName, pszMountPoint, pszName);
     1230                rc = VERR_RESOURCE_BUSY;
     1231            }
     1232        }
     1233        else
     1234        {
     1235            VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' type %u mount at '%s', not '%s'...\n",
     1236                         pszFsdName, uBuf.FsQueryBuf.iType, pszMountPoint, pszName);
     1237            rc = VERR_ACCESS_DENIED;
     1238        }
     1239    }
     1240    else
     1241    {
     1242        rc = VWRN_NOT_FOUND;
     1243        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: DosQueryFSAttach(%s) -> %u\n", pszMountPoint, rcOs2);
     1244        AssertMsgStmt(rcOs2 != ERROR_BUFFER_OVERFLOW && rcOs2 != ERROR_INVALID_PARAMETER,
     1245                      ("%s -> %u\n", pszMountPoint, rcOs2), rc = VERR_ACCESS_DENIED);
     1246    }
     1247    return rc;
     1248
     1249#elif defined(RT_OS_LINUX)
     1250    /*
     1251     * Scan one of the mount table file for the mount point and then
     1252     * match file system and device/share.
     1253     */
     1254    FILE *pFile = setmntent(_PATH_MOUNTED, "r");
     1255    int rc = errno;
     1256    if (!pFile)
     1257        pFile = setmntent("/proc/mounts", "r");
     1258    if (pFile)
     1259    {
     1260        rc = VWRN_NOT_FOUND;
     1261        struct mntent *pEntry;
     1262        while ((pEntry = getmntent(pFile)) != NULL)
     1263            if (RTPathCompare(pEntry->mnt_dir, pszMountPoint) == 0)
     1264            {
     1265                if (strcmp(pEntry->mnt_type, "vboxsf") == 0)
     1266                {
     1267                    if (RTStrICmp(pEntry->mnt_fsname, pszName) == 0)
     1268                    {
     1269                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
     1270                                     pszMountPoint, pszName);
     1271                        rc = VINF_SUCCESS;
     1272                    }
     1273                    else
     1274                    {
     1275                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
     1276                                     pEntry->mnt_fsname, pszMountPoint, pszName);
     1277                        rc = VERR_RESOURCE_BUSY;
     1278                    }
     1279                }
     1280                else
     1281                {
     1282                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
     1283                                 pEntry->mnt_type, pEntry->mnt_fsname, pszMountPoint, pszName);
     1284                    rc = VERR_ACCESS_DENIED;
     1285                }
     1286                /* We continue searching in case of stacked mounts, we want the last one. */
     1287            }
     1288        endmntent(pFile);
     1289    }
     1290    else
     1291    {
     1292        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d) or '/proc/mounts' (errno=%d)\n",
     1293                   _PATH_MOUNTED, rc, errno);
     1294        rc = VERR_ACCESS_DENIED;
     1295    }
     1296    return rc;
     1297
     1298#elif defined(RT_OS_SOLARIS)
     1299    /*
     1300     * Similar to linux.
     1301     */
     1302    int rc;
     1303    FILE *pFile = fopen(_PATH_MOUNTED, "r");
     1304    if (pFile)
     1305    {
     1306        rc = VWRN_NOT_FOUND;
     1307        struct mnttab Entry;
     1308        while (getmntent(pFile, &Entry) == 0)
     1309            if (RTPathCompare(Entry.mnt_mountp, pszMountPoint) == 0)
     1310            {
     1311                if (strcmp(Entry.mnt_fstype, "vboxsf") == 0)
     1312                {
     1313                    if (RTStrICmp(Entry.mnt_special, pszName) == 0)
     1314                    {
     1315                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s' as expected.\n",
     1316                                     pszMountPoint, pszName);
     1317                        rc = VINF_SUCCESS;
     1318                    }
     1319                    else
     1320                    {
     1321                        VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found shared folder '%s' at '%s', not '%s'...\n",
     1322                                     Entry.mnt_special, pszMountPoint, pszName);
     1323                        rc = VERR_RESOURCE_BUSY;
     1324                    }
     1325                }
     1326                else
     1327                {
     1328                    VGSvcVerbose(3, "vbsvcAutomounterQueryMountPoint: Found a '%s' mount of '%s' at '%s', not '%s'...\n",
     1329                                 Entry.mnt_fstype, Entry.mnt_special, pszMountPoint, pszName);
     1330                    rc = VERR_ACCESS_DENIED;
     1331                }
     1332                /* We continue searching in case of stacked mounts, we want the last one. */
     1333            }
     1334        fclose(pFile);
     1335    }
     1336    else
     1337    {
     1338        VGSvcError("vbsvcAutomounterQueryMountPoint: Could not open mount tab '%s' (errno=%d)\n", _PATH_MOUNTED, errno);
     1339        rc = VERR_ACCESS_DENIED;
     1340    }
     1341    return rc;
     1342#else
     1343# error "PORTME"
     1344#endif
     1345}
     1346
     1347
     1348/**
     1349 * Worker for vbsvcAutomounterMountNewEntry that does the OS mounting.
     1350 *
     1351 * @returns IPRT status code.
     1352 * @param   pEntry      The entry to try mount.
     1353 */
     1354static int vbsvcAutomounterMountIt(PVBSVCAUTOMOUNTERENTRY pEntry)
     1355{
     1356    VGSvcVerbose(3, "vbsvcAutomounterMountIt: Trying to mount '%s' (idRoot=%#x) on '%s'...\n",
     1357                 pEntry->pszName, pEntry->idRoot, pEntry->pszActualMountPoint);
     1358#ifdef RT_OS_WINDOWS
     1359    /*
     1360     * Attach the shared folder using WNetAddConnection2W.
    5981361     *
    599      * This thread exits so fast while doing its own startup in VGSvcStartServices()
    600      * that this->fShutdown flag is set to true in VGSvcThread() before we have the
    601      * chance to check for a service failure in VGSvcStartServices() to indicate
    602      * a VBoxService startup error.
     1362     * According to google we should get a drive symlink in \\GLOBAL?? when
     1363     * we are running under the system account.  Otherwise it will a session
     1364     * local link (\\??).
     1365     */
     1366    Assert(RT_C_IS_UPPER(pEntry->pszActualMountPoint[0]) && pEntry->pszActualMountPoint[1] == ':' && pEntry->pszActualMountPoint[2] == '\0');
     1367    RTUTF16 wszDrive[4] = { pEntry->pszActualMountPoint[0], ':', '\0', '\0' };
     1368
     1369    RTUTF16 wszPrefixedName[RTPATH_MAX];
     1370    int rc = RTUtf16CopyAscii(wszPrefixedName, RT_ELEMENTS(wszPrefixedName), "\\\\VBoxSvr\\");
     1371    AssertRC(rc);
     1372
     1373    PRTUTF16 pwszName = &wszPrefixedName[RTUtf16Len(wszPrefixedName)];
     1374    rc = RTStrToUtf16Ex(pEntry->pszName, RTSTR_MAX, &pwszName, pwszName - wszPrefixedName, NULL);
     1375    if (RT_FAILURE(rc))
     1376    {
     1377        VGSvcError("vbsvcAutomounterMountIt: RTStrToUtf16Ex failed on '%s': %Rrc\n", pEntry->pszName, rc);
     1378        return rc;
     1379    }
     1380
     1381    NETRESOURCEW NetRsrc;
     1382    RT_ZERO(NetRsrc);
     1383    NetRsrc.dwType          = RESOURCETYPE_DISK;
     1384    NetRsrc.lpLocalName     = wszDrive;
     1385    NetRsrc.lpRemoteName    = wszPrefixedName;
     1386    NetRsrc.lpProvider      = L"VirtualBox Shared Folders"; /* Only try our provider. */
     1387    NetRsrc.lpComment       = pwszName;
     1388
     1389    DWORD dwErr = WNetAddConnection2W(&NetRsrc, NULL /*pwszPassword*/, NULL /*pwszUserName*/, 0 /*dwFlags*/);
     1390    if (dwErr == NO_ERROR)
     1391    {
     1392        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
     1393                     pEntry->pszName, pEntry->pszActualMountPoint);
     1394        return VINF_SUCCESS;
     1395    }
     1396    VGSvcError("vbsvcAutomounterMountIt: Failed to attach '%s' to '%s': %u\n",
     1397               pEntry->pszName, pEntry->pszActualMountPoint, rc);
     1398    return VERR_OPEN_FAILED;
     1399
     1400#elif defined(RT_OS_OS2)
     1401    /*
     1402     * It's a rather simple affair on OS/2.
    6031403     *
    604      * Therefore *no* service threads are allowed to quit themselves and need to wait
    605      * for the pfShutdown flag to be set by the main thread.
    606      */
    607 /** @todo r=bird: Shared folders have always been configurable at run time, so
    608  * this service must be changed to check for changes and execute those changes!
    609  *
    610  * The 0.5sec sleep here is just soo crude and must go!
    611  */
     1404     * In order to be able to detect our mounts we add a 2nd string after
     1405     * the folder name that tags the attachment.  The IFS will remember this
     1406     * and return it when DosQueryFSAttach is called.
     1407     *
     1408     * Note! Kernel currently accepts limited 7-bit ASCII names.  We could
     1409     *       change that to UTF-8 if we like as that means no extra string
     1410     *       encoding conversion fun here.
     1411     */
     1412    char    szzNameAndTag[256];
     1413    size_t  cchName = strlen(pEntry->pszName);
     1414    if (cchName + 1 + sizeof(g_szTag) <= sizeof(szzNameAndTag))
     1415    {
     1416        memcpy(szzNameAndTag, pEntry->pszName, cchName);
     1417        szzNameAndTag[cchName] = '\0';
     1418        memcpy(&szzNameAndTag[cchName + 1], g_szTag, sizeof(g_szTag));
     1419
     1420        APIRET rc = DosFSAttach(pEntry->pszActualMountPoint, "VBOXSF", szzNameAndTag, cchName + 1 + sizeof(g_szzTag), FS_ATTACH);
     1421        if (rc == NO_ERROR)
     1422        {
     1423            VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
     1424                         pEntry->pszName, pEntry->pszActualMountPoint);
     1425            return VINF_SUCCESS;
     1426        }
     1427        VGSvcError("vbsvcAutomounterMountIt: DosFSAttach failed to attach '%s' to '%s': %u\n",
     1428                   pEntry->pszName, pEntry->pszActualMountPoint, rc);
     1429    }
     1430    else
     1431        VGSvcError("vbsvcAutomounterMountIt: Share name for attach to '%s' is too long: %u chars - '%s'\n",
     1432                   pEntry->pszActualMountPoint, cchName, pEntry->pszName;
     1433    return VERR_OPEN_FAILED;
     1434
     1435#else
     1436    /*
     1437     * Common work for unix-like systems: Get group, make sure mount directory exist.
     1438     */
     1439    int rc = RTDirCreateFullPath(pEntry->pszActualMountPoint,
     1440                                 RTFS_UNIX_IRWXU | RTFS_UNIX_IXGRP | RTFS_UNIX_IRGRP | RTFS_UNIX_IXOTH | RTFS_UNIX_IROTH);
     1441    if (RT_FAILURE(rc))
     1442    {
     1443        VGSvcError("vbsvcAutomounterMountIt: Failed to create mount path '%s' for share '%s': %Rrc\n",
     1444                   pEntry->pszActualMountPoint, pEntry->pszName, rc);
     1445        return rc;
     1446    }
     1447
     1448    gid_t gidMount;
     1449    struct group *grp_vboxsf = getgrnam("vboxsf");
     1450    if (grp_vboxsf)
     1451        gidMount = grp_vboxsf->gr_gid;
     1452    else
     1453    {
     1454        VGSvcError("vbsvcAutomounterMountIt: Group 'vboxsf' does not exist\n");
     1455        gidMount = 0;
     1456    }
     1457
     1458#  if defined(RT_OS_LINUX)
     1459    /*
     1460     * Linux a bit more work...
     1461     */
     1462    struct vbsf_mount_info_new MntInfo;
     1463    RT_ZERO(MntInfo);
     1464    struct vbsf_mount_opts MntOpts;
     1465    RT_ZERO(MntOpts);
     1466    MntInfo.nullchar     = '\0';
     1467    MntInfo.signature[0] = VBSF_MOUNT_SIGNATURE_BYTE_0;
     1468    MntInfo.signature[1] = VBSF_MOUNT_SIGNATURE_BYTE_1;
     1469    MntInfo.signature[2] = VBSF_MOUNT_SIGNATURE_BYTE_2;
     1470    MntInfo.length       = sizeof(MntInfo);
     1471    MntInfo.uid          = MntOpts.uid   = 0;
     1472    MntInfo.gid          = MntOpts.gid   = gidMount;
     1473    MntInfo.dmode        = MntOpts.dmode = 0770;
     1474    MntInfo.fmode        = MntOpts.fmode = 0770;
     1475    MntInfo.dmask        = MntOpts.dmask = 0000;
     1476    MntInfo.fmask        = MntOpts.fmask = 0000;
     1477    rc = RTStrCopy(MntInfo.name, sizeof(MntInfo.name), pEntry->pszName);
     1478    if (RT_FAILURE(rc))
     1479    {
     1480        VGSvcError("vbsvcAutomounterMountIt: Share name '%s' is too long for the MntInfo.name field!\n", pEntry->pszName);
     1481        return rc;
     1482    }
     1483
     1484    errno = 0;
     1485    unsigned long fFlags = MS_NODEV;
     1486    rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, "vboxsf", fFlags, &MntInfo);
     1487    if (rc == 0)
     1488    {
     1489        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Successfully mounted '%s' on '%s'\n",
     1490                     pEntry->pszName, pEntry->pszActualMountPoint);
     1491
     1492        errno = 0;
     1493        rc = vbsfmount_complete(pEntry->pszName, pEntry->pszActualMountPoint, fFlags, &MntOpts);
     1494        if (rc == 0)
     1495            return VINF_SUCCESS;
     1496
     1497        VGSvcError("vbsvcAutomounterMountIt: vbsfmount_complete failed: %s (%d/%d)\n",
     1498                   rc == 1 ? "open_memstream" : rc == 2 ? "setmntent" : rc == 3 ? "addmntent" : "unknown", rc, errno);
     1499    }
     1500    else if (errno == EINVAL)
     1501        VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s' because it is probably mounted elsewhere arleady! (%d,%d)\n",
     1502                   pEntry->pszName, pEntry->pszActualMountPoint, rc, errno);
     1503    else
     1504        VGSvcError("vbsvcAutomounterMountIt: Failed to mount '%s' on '%s': %s (%d,%d)\n",
     1505                   pEntry->pszName, pEntry->pszActualMountPoint, strerror(errno), rc, errno);
     1506    return VERR_WRITE_ERROR;
     1507
     1508#  elif defined(RT_OS_SOLARIS)
     1509    /*
     1510     * Solaris is rather simple compared to linux.
     1511     *
     1512     * The ',VBoxService=auto' option (g_szTag) is ignored by the kernel but helps
     1513     * us identify our own mounts on restart.  See vbsvcAutomounterPopulateTable().
     1514     */
     1515    char szOpts[MAX_MNTOPT_STR] = { '\0', };
     1516    ssize_t cchOpts = RTStrPrintf2(szOpts, sizeof(szOpts),
     1517                                   "uid=0,gid=%d,dmode=0770,fmode=0770,dmask=0000,fmask=0000%s", gidMount, g_szTag);
     1518    if (cchOpts <= 0)
     1519    {
     1520        VGSvcError("vbsvcAutomounterMountIt: szOpts overflow! %zd\n", cchOpts);
     1521        return VERR_BUFFER_OVERFLOW;
     1522    }
     1523
     1524    rc = mount(pEntry->pszName, pEntry->pszActualMountPoint, MS_OPTIONSTR, "vboxfs",
     1525               NULL /*dataptr*/, 0 /* datalen */, szOptBuf, cchOpts + 1);
     1526    if (rc == 0)
     1527    {
     1528        VGSvcVerbose(0, "vbsvcAutomounterMountIt: Shared folder '%s' was mounted to '%s'\n", pszShareName, pszMountPoint);
     1529        return VINF_SUCCESS;
     1530    }
     1531
     1532    rc = errno;
     1533    VGSvcError("vbsvcAutomounterMountIt: mount failed for '%s' at '%s': %s (%d)\n",
     1534               pEntry->pszName, pEntry->pszActualMountPoint, strerror(rc), rc);
     1535    return VERR_OPEN_FAILED;
     1536
     1537# else
     1538#  error "PORTME!"
     1539# endif
     1540#endif
     1541}
     1542
     1543
     1544/**
     1545 * Attempts to mount the given shared folder, adding it to the mount table on
     1546 * success.
     1547 *
     1548 * @returns iTable + 1 on success, iTable on failure.
     1549 * @param   pTable          The mount table.
     1550 * @param   iTable          The mount table index at which to add the mount.
     1551 * @param   pszName         The name of the shared folder mapping.
     1552 * @param   pszMntPt        The mount point (hint) specified by the host.
     1553 * @param   fFlags          The shared folder flags, SHFL_MIF_XXX.
     1554 * @param   idRoot          The root ID.
     1555 * @param   uRootIdVersion  The root ID version.
     1556 * @param   fAutoMntPt      Whether to try automatically assign a mount point if
     1557 *                          pszMntPt doesn't work out.  This is set in pass \#3.
     1558 */
     1559static uint32_t vbsvcAutomounterMountNewEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable,
     1560                                              const char *pszName, const char *pszMntPt, uint64_t fFlags,
     1561                                              uint32_t idRoot, uint32_t uRootIdVersion, bool fAutoMntPt)
     1562{
     1563    VGSvcVerbose(3, "vbsvcAutomounterMountNewEntry: #%u: '%s' at '%s'%s\n",
     1564                 iTable, pszName, pszMntPt, fAutoMntPt ? " auto-assign" : "");
     1565
     1566    /*
     1567     * First we need to figure out the actual mount point.
     1568     */
     1569    char szActualMountPoint[RTPATH_MAX];
     1570
     1571#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
     1572    /*
     1573     * Drive letter based:
     1574     */
     1575    char chNextLetter = 'Z';
     1576    if (RT_C_IS_UPPER(pszMntPt[0]) && pszMntPt[1] == ':')
     1577        szActualMountPoint[0] = RT_C_TO_UPPER(pszMntPt[0]);
     1578    else if (!fAutoMntPt)
     1579        return iTable;
     1580    else
     1581        szActualMountPoint[0] = chNextLetter--;
     1582    szActualMountPoint[1] = ':';
     1583    szActualMountPoint[2] = '\0';
     1584
     1585    int rc;
    6121586    for (;;)
    6131587    {
    614         /* Do we need to shutdown? */
    615         if (*pfShutdown)
     1588        rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
     1589        if (rc == VWRN_NOT_FOUND)
    6161590            break;
    6171591
    618         /* Let's sleep for a bit and let others run ... */
    619         RTThreadSleep(500);
    620     }
    621 
    622     VGSvcVerbose(3, "vbsvcAutoMountWorker: Finished with rc=%Rrc\n", rc);
     1592        /* next */
     1593        if (chNextLetter == 'A' || !fAutoMntPt)
     1594            return iTable;
     1595        szActualMountPoint[0] = chNextLetter--;
     1596    }
     1597
     1598#else
     1599    /*
     1600     * Path based #1: Host specified mount point.
     1601     */
     1602    int rc = VERR_ACCESS_DENIED;
     1603    if (*pszMntPt == '/')
     1604    {
     1605        rc = RTPathAbs(pszMntPt, szActualMountPoint, sizeof(szActualMountPoint));
     1606        if (RT_SUCCESS(rc))
     1607        {
     1608            static const char * const s_apszBlacklist[] =
     1609            { "/", "/dev", "/bin", "/sbin", "/lib", "/etc", "/var", "/tmp", "/usr", "/usr/bin", "/usr/sbin", "/usr/lib" };
     1610            for (size_t i = 0; i < RT_ELEMENTS(s_apszBlacklist); i++)
     1611                if (strcmp(szActualMountPoint, s_apszBlacklist[i]) == 0)
     1612                {
     1613                    rc = VERR_ACCESS_DENIED;
     1614                    break;
     1615                }
     1616            if (RT_SUCCESS(rc))
     1617                rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
     1618        }
     1619    }
     1620    if (rc != VWRN_NOT_FOUND)
     1621    {
     1622        if (!fAutoMntPt)
     1623            return iTable;
     1624
     1625        /*
     1626         * Path based #2: Mount dir + prefix + share.
     1627         */
     1628        /* Mount base directory: */
     1629        szActualMountPoint[0] = '\0';
     1630        char *pszProp;
     1631        rc = VbglR3SharedFolderGetMountDir(&pszProp);
     1632        if (RT_SUCCESS(rc))
     1633        {
     1634            if (*pszProp == '/')
     1635                rc = RTPathAbs(pszProp, szActualMountPoint, sizeof(szActualMountPoint));
     1636            else
     1637                VGSvcError("vbsvcAutomounterMountNewEntry: Invalid mount directory: '%s'\n", pszProp);
     1638            RTStrFree(pszProp);
     1639        }
     1640        if (RT_FAILURE(rc) || szActualMountPoint[0] != '/')
     1641            memcpy(szActualMountPoint, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR, sizeof(VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR));
     1642
     1643        /* Add prefix: */
     1644        rc = VbglR3SharedFolderGetMountPrefix(&pszProp);
     1645        if (RT_SUCCESS(rc))
     1646        {
     1647            if (   strchr(pszProp, '/')  == NULL
     1648                && strchr(pszProp, '\\') == NULL
     1649                && strcmp(pszProp, "..") != 0)
     1650                rc = RTPathAppend(szActualMountPoint, sizeof(szActualMountPoint), pszProp);
     1651            else
     1652                VGSvcError("vbsvcAutomounterMountNewEntry: Invalid mount prefix: '%s'\n", pszProp);
     1653            RTStrFree(pszProp);
     1654        }
     1655        else
     1656            rc = RTPathEnsureTrailingSeparator(szActualMountPoint, sizeof(szActualMountPoint)) != 0
     1657               ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
     1658        if (RT_SUCCESS(rc))
     1659        {
     1660            /* Add sanitized share name: */
     1661            size_t const offShare = strlen(szActualMountPoint);
     1662            size_t offDst = offShare;
     1663            size_t offSrc = 0;
     1664            for (;;)
     1665            {
     1666                char ch = pszName[offSrc++];
     1667                if (ch == ' ' || ch == '/' || ch == '\\' || ch == ':' || ch == '$')
     1668                    ch = '_';
     1669                else if (!ch)
     1670                    break;
     1671                else if (ch < 0x20 || ch == 0x7f)
     1672                    continue;
     1673                if (offDst < sizeof(szActualMountPoint) - 1)
     1674                    szActualMountPoint[offDst++] = ch;
     1675            }
     1676            szActualMountPoint[offDst] = '\0';
     1677            if (offDst > offShare)
     1678            {
     1679                rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
     1680                if (rc != VWRN_NOT_FOUND)
     1681                {
     1682                    /*
     1683                     * Path based #3: Mount dir + prefix + share + _ + number.
     1684                     */
     1685                    if (offDst + 2 >= sizeof(szActualMountPoint))
     1686                        return iTable;
     1687
     1688                    szActualMountPoint[offDst++] = '_';
     1689                    for (uint32_t iTry = 1; iTry < 10 && rc != VWRN_NOT_FOUND; iTry++)
     1690                    {
     1691                        szActualMountPoint[offDst] = '0' + iTry;
     1692                        szActualMountPoint[offDst + 1] = '\0';
     1693                        rc = vbsvcAutomounterQueryMountPoint(szActualMountPoint, pszName);
     1694                    }
     1695                    if (rc != VWRN_NOT_FOUND)
     1696                       return iTable;
     1697                }
     1698            }
     1699            else
     1700                VGSvcError("vbsvcAutomounterMountNewEntry: Bad share name: %.*Rhxs", strlen(pszName), pszName);
     1701        }
     1702        else
     1703            VGSvcError("vbsvcAutomounterMountNewEntry: Failed to construct basic auto mount point for '%s'", pszName);
     1704    }
     1705#endif
     1706
     1707    /*
     1708     * Prepare a table entry and ensure space in the table..
     1709     */
     1710    if (pTable->cEntries + 1 > pTable->cAllocated)
     1711    {
     1712        void *pvEntries = RTMemRealloc(pTable->papEntries, sizeof(pTable->papEntries[0]) * (pTable->cAllocated + 8));
     1713        if (!pvEntries)
     1714        {
     1715            VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for growing table (size %u)\n", pTable->cAllocated);
     1716            return iTable;
     1717        }
     1718        pTable->cAllocated += 8;
     1719        pTable->papEntries = (PVBSVCAUTOMOUNTERENTRY *)pvEntries;
     1720    }
     1721
     1722    PVBSVCAUTOMOUNTERENTRY pEntry = (PVBSVCAUTOMOUNTERENTRY)RTMemAlloc(sizeof(*pEntry));
     1723    if (pEntry)
     1724    {
     1725        pEntry->idRoot              = idRoot;
     1726        pEntry->uRootIdVersion      = uRootIdVersion;
     1727        pEntry->fFlags              = fFlags;
     1728        pEntry->pszName             = RTStrDup(pszName);
     1729        pEntry->pszMountPoint       = RTStrDup(pszMntPt);
     1730        pEntry->pszActualMountPoint = RTStrDup(szActualMountPoint);
     1731        if (pEntry->pszName && pEntry->pszMountPoint && pEntry->pszActualMountPoint)
     1732        {
     1733            /*
     1734             * Now try mount it.
     1735             */
     1736            rc = vbsvcAutomounterMountIt(pEntry);
     1737            if (RT_SUCCESS(rc))
     1738            {
     1739                uint32_t cToMove = pTable->cEntries - iTable;
     1740                if (cToMove > 0)
     1741                    memmove(&pTable->papEntries[iTable + 1], &pTable->papEntries[iTable], cToMove * sizeof(pTable->papEntries[0]));
     1742                pTable->papEntries[iTable] = pEntry;
     1743                pTable->cEntries++;
     1744                return iTable + 1;
     1745            }
     1746        }
     1747        else
     1748            VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
     1749        RTMemFree(pEntry->pszActualMountPoint);
     1750        RTMemFree(pEntry->pszMountPoint);
     1751        RTMemFree(pEntry->pszName);
     1752        RTMemFree(pEntry);
     1753    }
     1754    else
     1755        VGSvcError("vbsvcAutomounterMountNewEntry: Out of memory for table entry!\n");
     1756    return iTable;
     1757}
     1758
     1759
     1760
     1761/**
     1762 * Does the actual unmounting.
     1763 *
     1764 * @returns Exactly one of the following IPRT status codes;
     1765 * @retval  VINF_SUCCESS if successfully umounted or nothing was mounted there.
     1766 * @retval  VERR_TRY_AGAIN if the shared folder is busy.
     1767 * @retval  VERR_RESOURCE_BUSY if a different shared folder is mounted there.
     1768 * @retval  VERR_ACCESS_DENIED if a non-shared folder file system is mounted
     1769 *          there.
     1770 *
     1771 * @param   pszMountPoint       The mount point.
     1772 * @param   pszName             The shared folder (mapping) name.
     1773 */
     1774static int vbsvcAutomounterUnmount(const char *pszMountPoint, const char *pszName)
     1775{
     1776    /*
     1777     * Retry for 5 seconds in a hope that busy mounts will quiet down.
     1778     */
     1779    for (unsigned iTry = 0; ; iTry++)
     1780    {
     1781        /*
     1782         * Check what's mounted there before we start umounting stuff.
     1783         */
     1784        int rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
     1785        if (rc == VINF_SUCCESS)
     1786        { /* pszName is mounted there */ }
     1787        else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
     1788            return VINF_SUCCESS;
     1789        else
     1790        {
     1791            Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
     1792            return VERR_RESOURCE_BUSY;
     1793        }
     1794
     1795        /*
     1796         * Do host specific unmounting.
     1797         */
     1798#ifdef RT_OS_WINDOWS
     1799        Assert(RT_C_IS_UPPER(pszMountPoint[0]) && pszMountPoint[1] == ':' && pszMountPoint[2] == '\0');
     1800        RTUTF16 const wszDrive[4] = { pszMountPoint[0], ':', '\0', '\0' };
     1801        DWORD dwErr = WNetCancelConnection2W(wszDrive, 0 /*dwFlags*/, FALSE /*fForce*/);
     1802        if (dwErr == NO_ERROR)
     1803            return VINF_SUCCESS;
     1804        VGSvcVerbose(2, "vbsvcAutomounterUnmount: WNetCancelConnection2W returns %u for '%s' ('%s')\n", dwErr, pszMountPoint, pszName);
     1805        if (dwErr == ERROR_NOT_CONNECTED)
     1806            return VINF_SUCCESS;
     1807
     1808#elif defined(RT_OS_OS2)
     1809        APIRET rcOs2 = DosFSAttach(pszMountPoint, "VBOXSF", NULL, 0, FS_DETACH);
     1810        if (rcOs2 == NO_ERROR)
     1811            return VINF_SUCCESS;
     1812        VGSvcVerbose(2, "vbsvcAutomounterUnmount: DosFSAttach failed on '%s' ('%s'): %u\n", pszMountPoint, pszName, rcOs2);
     1813        if (rcOs2 == ERROR_INVALID_FSD_NAME)
     1814            return VERR_ACCESS_DENIED;
     1815        if (   rcOs2 == ERROR_INVALID_DRIVE
     1816            || rcOs2 == ERROR_INVALID_PATH)
     1817            return VERR_TRY_AGAIN;
     1818
     1819#else
     1820        int rc2 = umount(pszMountPoint);
     1821        if (rc2 == 0)
     1822            return VINF_SUCCESS;
     1823        rc2 = errno;
     1824        VGSvcVerbose(2, "vbsvcAutomounterUnmount: umount failed on '%s' ('%s'): %d\n", pszMountPoint, pszName, rc2);
     1825        if (rc2 != EBUSY && rc2 != EAGAIN)
     1826            return VERR_ACCESS_DENIED;
     1827#endif
     1828
     1829        /*
     1830         * Check what's mounted there before we start delaying.
     1831         */
     1832        RTThreadSleep(8); /* fudge */
     1833        rc = vbsvcAutomounterQueryMountPoint(pszMountPoint, pszName);
     1834        if (rc == VINF_SUCCESS)
     1835        { /* pszName is mounted there */ }
     1836        else if (rc == VWRN_NOT_FOUND) /* nothing mounted there */
     1837            return VINF_SUCCESS;
     1838        else
     1839        {
     1840            Assert(rc == VERR_RESOURCE_BUSY || rc == VERR_ACCESS_DENIED);
     1841            return VERR_RESOURCE_BUSY;
     1842        }
     1843
     1844        if (iTry >= 5)
     1845            return VERR_TRY_AGAIN;
     1846        RTThreadSleep(1000);
     1847    }
     1848}
     1849
     1850
     1851/**
     1852 * Unmounts a mount table entry and evicts it from the table if successful.
     1853 *
     1854 * @returns The next iTable (same value on success, +1 on failure).
     1855 * @param   pTable              The mount table.
     1856 * @param   iTable              The table entry.
     1857 * @param   pszReason           Why we're here.
     1858 */
     1859static uint32_t vbsvcAutomounterUnmountEntry(PVBSVCAUTOMOUNTERTABLE pTable, uint32_t iTable, const char *pszReason)
     1860{
     1861    Assert(iTable < pTable->cEntries);
     1862    PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
     1863    VGSvcVerbose(3, "vbsvcAutomounterUnmountEntry: #%u: '%s' at '%s' (reason: %s)\n",
     1864                 iTable, pEntry->pszName, pEntry->pszMountPoint, pszReason);
     1865
     1866    /*
     1867     * Do we need to umount the entry?  Return if unmount fails and we .
     1868     */
     1869    if (pEntry->pszActualMountPoint)
     1870    {
     1871        int rc = vbsvcAutomounterUnmount(pEntry->pszActualMountPoint, pEntry->pszName);
     1872        if (rc == VERR_TRY_AGAIN)
     1873        {
     1874            VGSvcVerbose(2, "vbsvcAutomounterUnmountEntry: Keeping '%s' -> '%s' (VERR_TRY_AGAIN)\n",
     1875                         pEntry->pszActualMountPoint, pEntry->pszName);
     1876            return iTable + 1;
     1877        }
     1878    }
     1879
     1880    /*
     1881     * Remove the entry by shifting up the ones after it.
     1882     */
     1883    pTable->cEntries -= 1;
     1884    uint32_t cAfter = pTable->cEntries - iTable;
     1885    if (cAfter)
     1886        memmove(&pTable->papEntries[iTable], &pTable->papEntries[iTable + 1], cAfter * sizeof(pTable->papEntries[0]));
     1887    pTable->papEntries[pTable->cEntries] = NULL;
     1888
     1889    RTStrFree(pEntry->pszActualMountPoint);
     1890    pEntry->pszActualMountPoint = NULL;
     1891    RTStrFree(pEntry->pszMountPoint);
     1892    pEntry->pszMountPoint = NULL;
     1893    RTStrFree(pEntry->pszName);
     1894    pEntry->pszName = NULL;
     1895    RTMemFree(pEntry);
     1896
     1897    return iTable;
     1898}
     1899
     1900
     1901/**
     1902 * @callback_method_impl{FNRTSORTCMP,  For sorting the mappings by ID,}
     1903 */
     1904static DECLCALLBACK(int) vbsvcSharedFolderMappingCompare(void const *pvElement1, void const *pvElement2, void *pvUser)
     1905{
     1906    RT_NOREF_PV(pvUser);
     1907    PVBGLR3SHAREDFOLDERMAPPING pMapping1 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement1;
     1908    PVBGLR3SHAREDFOLDERMAPPING pMapping2 = (PVBGLR3SHAREDFOLDERMAPPING)pvElement2;
     1909    return pMapping1->u32Root < pMapping2->u32Root ? -1 : pMapping1->u32Root != pMapping2->u32Root ? 1 : 0;
     1910}
     1911
     1912
     1913/**
     1914 * Refreshes the mount table.
     1915 *
     1916 * @returns true if we've processed the current config, false if we failed to
     1917 *          query the mappings.
     1918 * @param   pTable          The mount table to refresh.
     1919 */
     1920static bool vbsvcAutomounterRefreshTable(PVBSVCAUTOMOUNTERTABLE pTable)
     1921{
     1922    /*
     1923     * Query the root IDs of all auto-mountable shared folder mappings.
     1924     */
     1925    uint32_t                    cMappings = 0;
     1926    PVBGLR3SHAREDFOLDERMAPPING  paMappings = NULL;
     1927    int rc = VbglR3SharedFolderGetMappings(g_idClientSharedFolders, true /*fAutoMountOnly*/, &paMappings, &cMappings);
     1928    if (RT_FAILURE(rc))
     1929    {
     1930        VGSvcError("vbsvcAutomounterRefreshTable: VbglR3SharedFolderGetMappings failed: %Rrc\n", rc);
     1931        return false;
     1932    }
     1933
     1934    /*
     1935     * Walk the table and the mappings in parallel, so we have to make sure
     1936     * they are both sorted by root ID.
     1937     */
     1938    if (cMappings > 1)
     1939        RTSortShell(paMappings, cMappings, sizeof(paMappings[0]), vbsvcSharedFolderMappingCompare, NULL);
     1940
     1941    /*
     1942     * Pass #1: Do all the umounting.
     1943     *
     1944     * By doing the umount pass separately from the mount pass, we can
     1945     * better handle changing involving the same mount points (switching
     1946     * mount points between two shares, new share on same mount point but
     1947     * with lower root ID, ++).
     1948     */
     1949    uint32_t iTable = 0;
     1950    for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
     1951    {
     1952        /*
     1953         * Unmount table entries up to idRootSrc.
     1954         */
     1955        uint32_t const idRootSrc = paMappings[iSrc].u32Root;
     1956        while (   iTable < pTable->cEntries
     1957               && pTable->papEntries[iTable]->idRoot < idRootSrc)
     1958            iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped");
     1959
     1960        /*
     1961         * If the paMappings entry and the mount table entry has the same
     1962         * root ID, umount if anything has changed or if we cannot query
     1963         * the mapping data.
     1964         */
     1965        if (iTable < pTable->cEntries)
     1966        {
     1967            PVBSVCAUTOMOUNTERENTRY pEntry = pTable->papEntries[iTable];
     1968            if (pEntry->idRoot == idRootSrc)
     1969            {
     1970                uint32_t uRootIdVer = UINT32_MAX;
     1971                uint64_t fFlags     = 0;
     1972                char    *pszName    = NULL;
     1973                char    *pszMntPt   = NULL;
     1974                rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
     1975                                                       &pszName, &pszMntPt, &fFlags, &uRootIdVer);
     1976                if (RT_FAILURE(rc))
     1977                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "VbglR3SharedFolderQueryFolderInfo failed");
     1978                else if (pEntry->uRootIdVersion != uRootIdVer)
     1979                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "root ID version changed");
     1980                else if (RTPathCompare(pEntry->pszMountPoint, pszMntPt) != 0)
     1981                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "mount point changed");
     1982                else if (RTStrICmp(pEntry->pszName, pszName) != 0)
     1983                    iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "name changed");
     1984                else
     1985                {
     1986                    VGSvcVerbose(3, "vbsvcAutomounterRefreshTable: Unchanged: %s -> %s\n", pEntry->pszMountPoint, pEntry->pszName);
     1987                    iTable++;
     1988                }
     1989                if (RT_SUCCESS(rc))
     1990                {
     1991                    RTStrFree(pszName);
     1992                    RTStrFree(pszMntPt);
     1993                }
     1994            }
     1995        }
     1996    }
     1997
     1998    while (iTable < pTable->cEntries)
     1999        iTable = vbsvcAutomounterUnmountEntry(pTable, iTable, "dropped (tail)");
     2000
     2001    VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u entries in mount table after pass #1.\n", pTable->cEntries);
     2002
     2003    /*
     2004     * Pass #2: Try mount new folders that has mount points assigned.
     2005     * Pass #3: Try mount new folders not mounted in pass #2.
     2006     */
     2007    for (uint32_t iPass = 2; iPass <= 3; iPass++)
     2008    {
     2009        iTable = 0;
     2010        for (uint32_t iSrc = 0; iSrc < cMappings; iSrc++)
     2011        {
     2012            uint32_t const idRootSrc = paMappings[iSrc].u32Root;
     2013
     2014            /*
     2015             * Skip tabel entries we couldn't umount in pass #1.
     2016             */
     2017            while (   iTable < pTable->cEntries
     2018                   && pTable->papEntries[iTable]->idRoot < idRootSrc)
     2019            {
     2020                VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Skipping idRoot=%u %s\n",
     2021                             iPass, iSrc, iTable, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
     2022                iTable++;
     2023            }
     2024
     2025            /*
     2026             * New share?
     2027             */
     2028            if (   iTable >= pTable->cEntries
     2029                || pTable->papEntries[iTable]->idRoot != idRootSrc)
     2030            {
     2031                uint32_t uRootIdVer = UINT32_MAX;
     2032                uint64_t fFlags     = 0;
     2033                char    *pszName    = NULL;
     2034                char    *pszMntPt   = NULL;
     2035                rc = VbglR3SharedFolderQueryFolderInfo(g_idClientSharedFolders, idRootSrc, VBOXSERVICE_AUTOMOUNT_MIQF,
     2036                                                       &pszName, &pszMntPt, &fFlags, &uRootIdVer);
     2037                if (RT_SUCCESS(rc))
     2038                {
     2039                    VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: Mounting idRoot=%u/%u %s\n", iPass, iSrc, iTable,
     2040                                 idRootSrc, iTable >= pTable->cEntries ? UINT32_MAX : pTable->papEntries[iTable]->idRoot, pszName);
     2041                    iTable = vbsvcAutomounterMountNewEntry(pTable, iTable, pszName, pszMntPt, fFlags,
     2042                                                           idRootSrc, uRootIdVer, iPass == 3);
     2043
     2044                    RTStrFree(pszName);
     2045                    RTStrFree(pszMntPt);
     2046                }
     2047                else
     2048                    VGSvcVerbose(1, "vbsvcAutomounterRefreshTable: VbglR3SharedFolderQueryFolderInfo failed: %Rrc\n", rc);
     2049            }
     2050            else
     2051                VGSvcVerbose(4, "vbsvcAutomounterRefreshTable: %u/#%u/%#u: idRootSrc=%u vs idRoot=%u %s\n", iPass, iSrc,
     2052                             iTable, idRootSrc, pTable->papEntries[iTable]->idRoot, pTable->papEntries[iTable]->pszName);
     2053        }
     2054    }
     2055
     2056    VbglR3SharedFolderFreeMappings(paMappings);
     2057    return true;
     2058}
     2059
     2060
     2061/**
     2062 * @interface_method_impl{VBOXSERVICE,pfnWorker}
     2063 */
     2064static DECLCALLBACK(int) vbsvcAutomounterWorker(bool volatile *pfShutdown)
     2065{
     2066    /*
     2067     * Tell the control thread that it can continue spawning services.
     2068     */
     2069    RTThreadUserSignal(RTThreadSelf());
     2070
     2071    /* Divert old hosts to original auto-mount code. */
     2072    if (!g_fHostSupportsWaitAndInfoQuery)
     2073        return vbsvcAutoMountWorkerOld(pfShutdown);
     2074
     2075    /*
     2076     * Initialize the state in case we're restarted...
     2077     */
     2078    VBSVCAUTOMOUNTERTABLE MountTable  = { 0, 0, NULL };
     2079    int rc = vbsvcAutomounterPopulateTable(&MountTable);
     2080    if (RT_FAILURE(rc))
     2081    {
     2082        VGSvcError("vbsvcAutomounterWorker: vbsvcAutomounterPopulateTable failed (%Rrc), quitting!\n", rc);
     2083        return rc;
     2084    }
     2085
     2086    /*
     2087     * Work loop.
     2088     */
     2089    uint32_t uConfigVer    = UINT32_MAX;
     2090    uint32_t uNewVersion   = 0;
     2091    bool     fForceRefresh = true;
     2092    while (!*pfShutdown)
     2093    {
     2094        /*
     2095         * Update the mounts.
     2096         */
     2097        if (   uConfigVer != uNewVersion
     2098            || fForceRefresh)
     2099        {
     2100            fForceRefresh = !vbsvcAutomounterRefreshTable(&MountTable);
     2101            uConfigVer    = uNewVersion;
     2102        }
     2103
     2104        /*
     2105         * Wait for more to do.
     2106         */
     2107        if (!*pfShutdown)
     2108        {
     2109            uNewVersion = uConfigVer - 1;
     2110            VGSvcVerbose(2, "vbsvcAutomounterWorker: Waiting with uConfigVer=%u\n", uConfigVer);
     2111            rc = VbglR3SharedFolderWaitForMappingsChanges(g_idClientSharedFolders, uConfigVer, &uNewVersion);
     2112            VGSvcVerbose(2, "vbsvcAutomounterWorker: Woke up with uNewVersion=%u and rc=%Rrc\n", uNewVersion, rc);
     2113
     2114            /* Delay a little before doing a table refresh so the GUI can finish
     2115               all its updates.  Delay a little longer on non-shutdown failure to
     2116               avoid eating too many CPU cycles if something goes wrong here... */
     2117            if (!*pfShutdown)
     2118                RTSemEventMultiWait(g_hAutoMountEvent, RT_SUCCESS(rc) ? 256 : 1000);
     2119        }
     2120    }
     2121
     2122    /*
     2123     * Destroy the mount table.
     2124     */
     2125    while (MountTable.cEntries-- > 0)
     2126        RTMemFree(MountTable.papEntries[MountTable.cEntries]);
     2127    MountTable.papEntries = NULL;
     2128
     2129    VGSvcVerbose(3, "vbsvcAutomounterWorker: Finished\n");
    6232130    return VINF_SUCCESS;
    6242131}
     
    6262133
    6272134/**
     2135 * @interface_method_impl{VBOXSERVICE,pfnStop}
     2136 */
     2137static DECLCALLBACK(void) vbsvcAutomounterStop(void)
     2138{
     2139    RTSemEventMultiSignal(g_hAutoMountEvent);
     2140    if (g_fHostSupportsWaitAndInfoQuery)
     2141        VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
     2142}
     2143
     2144
     2145/**
    6282146 * @interface_method_impl{VBOXSERVICE,pfnTerm}
    6292147 */
    630 static DECLCALLBACK(void) vbsvcAutoMountTerm(void)
     2148static DECLCALLBACK(void) vbsvcAutomounterTerm(void)
    6312149{
    6322150    VGSvcVerbose(3, "vbsvcAutoMountTerm\n");
    6332151
    634     VbglR3SharedFolderDisconnect(g_SharedFoldersSvcClientID);
    635     g_SharedFoldersSvcClientID = 0;
    636 
    637     if (g_AutoMountEvent != NIL_RTSEMEVENTMULTI)
    638     {
    639         RTSemEventMultiDestroy(g_AutoMountEvent);
    640         g_AutoMountEvent = NIL_RTSEMEVENTMULTI;
    641     }
    642     return;
    643 }
    644 
    645 
    646 /**
    647  * @interface_method_impl{VBOXSERVICE,pfnStop}
    648  */
    649 static DECLCALLBACK(void) vbsvcAutoMountStop(void)
    650 {
    651     RTSemEventMultiSignal(g_AutoMountEvent);
     2152    if (g_fHostSupportsWaitAndInfoQuery)
     2153        VbglR3SharedFolderCancelMappingsChangesWaits(g_idClientSharedFolders);
     2154
     2155    VbglR3SharedFolderDisconnect(g_idClientSharedFolders);
     2156    g_idClientSharedFolders = 0;
     2157
     2158    if (g_hAutoMountEvent != NIL_RTSEMEVENTMULTI)
     2159    {
     2160        RTSemEventMultiDestroy(g_hAutoMountEvent);
     2161        g_hAutoMountEvent = NIL_RTSEMEVENTMULTI;
     2162    }
    6522163}
    6532164
     
    6612172    "automount",
    6622173    /* pszDescription. */
    663     "Auto-mount for Shared Folders",
     2174    "Automounter for Shared Folders",
    6642175    /* pszUsage. */
    6652176    NULL,
     
    6692180    VGSvcDefaultPreInit,
    6702181    VGSvcDefaultOption,
    671     vbsvcAutoMountInit,
    672     vbsvcAutoMountWorker,
    673     vbsvcAutoMountStop,
    674     vbsvcAutoMountTerm
     2182    vbsvcAutomounterInit,
     2183    vbsvcAutomounterWorker,
     2184    vbsvcAutomounterStop,
     2185    vbsvcAutomounterTerm
    6752186};
     2187
  • trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c

    r72627 r75407  
    479479}
    480480
     481/** @todo Implement show_options (forever) or maybe set s_options (2.6.25+).
     482 *        Necessary for the automounter tagging.  */
    481483static struct super_operations sf_super_ops = {
    482484#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
  • trunk/src/VBox/HostServices/SharedFolders/mappings.cpp

    r75380 r75407  
    2323#include <iprt/alloc.h>
    2424#include <iprt/assert.h>
     25#include <iprt/list.h>
    2526#include <iprt/path.h>
    2627#include <iprt/string.h>
     
    3031#endif
    3132
    32 /* Shared folders order in the saved state and in the FolderMapping can differ.
     33extern PVBOXHGCMSVCHELPERS g_pHelpers; /* service.cpp */
     34
     35
     36/* Shared folders order in the saved state and in the g_FolderMapping can differ.
    3337 * So a translation array of root handle is needed.
    3438 */
    3539
    36 static MAPPING FolderMapping[SHFL_MAX_MAPPINGS];
    37 static SHFLROOT aIndexFromRoot[SHFL_MAX_MAPPINGS];
     40static MAPPING g_FolderMapping[SHFL_MAX_MAPPINGS];
     41static SHFLROOT g_aIndexFromRoot[SHFL_MAX_MAPPINGS];
     42/**< Array running parallel to g_aIndexFromRoot and which entries are increased
     43 * as an root handle is added or removed.
     44 *
     45 * This helps the guest figuring out that a mapping may have been reconfigured
     46 * or that saved state has been restored.  Entry reuse is very likely given that
     47 * vbsfRootHandleAdd() always starts searching at the start for an unused entry.
     48 */
     49static uint32_t g_auRootHandleVersions[SHFL_MAX_MAPPINGS];
     50/** Version number that is increased for every change made.
     51 * This is used by the automount guest service to wait for changes.
     52 * @note This does not need saving, the guest should be woken up and refresh
     53 *       its sate when restored. */
     54static uint32_t volatile g_uFolderMappingsVersion = 0;
     55
     56
     57/** For recording async vbsfMappingsWaitForChanges calls. */
     58typedef struct SHFLMAPPINGSWAIT
     59{
     60    RTLISTNODE          ListEntry;  /**< List entry. */
     61    PSHFLCLIENTDATA     pClient;    /**< The client that's waiting. */
     62    VBOXHGCMCALLHANDLE  hCall;      /**< The call handle to signal completion with. */
     63    PVBOXHGCMSVCPARM    pParm;      /**< The 32-bit unsigned parameter to stuff g_uFolderMappingsVersion into. */
     64} SHFLMAPPINGSWAIT;
     65/** Pointer to async mappings change wait. */
     66typedef SHFLMAPPINGSWAIT *PSHFLMAPPINGSWAIT;
     67/** List head for clients waiting on mapping changes (SHFLMAPPINGSWAIT). */
     68static RTLISTANCHOR g_MappingsChangeWaiters;
     69/** Number of clients waiting on mapping changes.
     70 * We use this to limit the number of waiting calls the clients can make.  */
     71static uint32_t     g_cMappingChangeWaiters = 0;
     72static void vbsfMappingsWakeupAllWaiters(void);
     73
    3874
    3975void vbsfMappingInit(void)
     
    4177    unsigned root;
    4278
    43     for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
    44     {
    45         aIndexFromRoot[root] = SHFL_ROOT_NIL;
    46     }
    47 }
    48 
    49 int vbsfMappingLoaded(const PMAPPING pLoadedMapping, SHFLROOT root)
     79    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
     80    {
     81        g_aIndexFromRoot[root] = SHFL_ROOT_NIL;
     82    }
     83
     84    RTListInit(&g_MappingsChangeWaiters);
     85}
     86
     87int vbsfMappingLoaded(const MAPPING *pLoadedMapping, SHFLROOT root)
    5088{
    5189    /* Mapping loaded from the saved state with the index. Which means
    5290     * the guest uses the iMapping as root handle for this folder.
    53      * Check whether there is the same mapping in FolderMapping and
    54      * update the aIndexFromRoot.
     91     * Check whether there is the same mapping in g_FolderMapping and
     92     * update the g_aIndexFromRoot.
    5593     *
    5694     * Also update the mapping properties, which were lost: cMappings.
     
    62100
    63101    SHFLROOT i;
    64     for (i = 0; i < RT_ELEMENTS(FolderMapping); i++)
    65     {
    66         MAPPING *pMapping = &FolderMapping[i];
     102    for (i = 0; i < RT_ELEMENTS(g_FolderMapping); i++)
     103    {
     104        MAPPING *pMapping = &g_FolderMapping[i];
    67105
    68106        /* Equal? */
     
    71109            && memcmp(pLoadedMapping->pMapName, pMapping->pMapName, ShflStringSizeOfBuffer(pMapping->pMapName)) == 0)
    72110        {
    73             /* Actual index is i. */
    74             aIndexFromRoot[root] = i;
    75 
    76             /* Update the mapping properties. */
    77             pMapping->cMappings = pLoadedMapping->cMappings;
    78 
    79             return VINF_SUCCESS;
     111            if (!pMapping->fLoadedRootId)
     112            {
     113                pMapping->fLoadedRootId = true;
     114                Log(("vbsfMappingLoaded: root=%u i=%u (was %u) (%ls)\n",
     115                     root, i, g_aIndexFromRoot[root], pLoadedMapping->pMapName->String.utf16));
     116
     117                /* Actual index is i. */
     118                /** @todo This will not work with global shared folders, as these can change
     119                 *        while state is saved and these blind assignments may hid new ones.  */
     120                g_aIndexFromRoot[root] = i;
     121
     122                /* Update the mapping properties. */
     123                pMapping->cMappings = pLoadedMapping->cMappings;
     124
     125                return VINF_SUCCESS;
     126            }
    80127        }
    81128    }
     
    93140MAPPING *vbsfMappingGetByRoot(SHFLROOT root)
    94141{
    95     if (root < RT_ELEMENTS(aIndexFromRoot))
    96     {
    97         SHFLROOT iMapping = aIndexFromRoot[root];
     142    if (root < RT_ELEMENTS(g_aIndexFromRoot))
     143    {
     144        SHFLROOT iMapping = g_aIndexFromRoot[root];
    98145
    99146        if (   iMapping != SHFL_ROOT_NIL
    100             && iMapping < RT_ELEMENTS(FolderMapping))
    101         {
    102             return &FolderMapping[iMapping];
     147            && iMapping < RT_ELEMENTS(g_FolderMapping))
     148        {
     149            return &g_FolderMapping[iMapping];
    103150        }
    104151    }
     
    111158    unsigned root;
    112159
    113     for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
    114     {
    115         if (iMapping == aIndexFromRoot[root])
     160    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
     161    {
     162        if (iMapping == g_aIndexFromRoot[root])
    116163        {
    117164            return root;
     
    122169}
    123170
    124 static MAPPING *vbsfMappingGetByName (PRTUTF16 pwszName, SHFLROOT *pRoot)
    125 {
    126     unsigned i;
    127 
    128     for (i=0; i<SHFL_MAX_MAPPINGS; i++)
    129     {
    130         if (FolderMapping[i].fValid == true)
    131         {
    132             if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pwszName))
     171static MAPPING *vbsfMappingGetByName(PRTUTF16 pwszName, SHFLROOT *pRoot)
     172{
     173    for (unsigned i = 0; i < SHFL_MAX_MAPPINGS; i++)
     174    {
     175        if (   g_FolderMapping[i].fValid
     176            && !g_FolderMapping[i].fPlaceholder) /* Don't allow mapping placeholders. */
     177        {
     178            if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pwszName))
    133179            {
    134180                SHFLROOT root = vbsfMappingGetRootFromIndex(i);
     
    140186                        *pRoot = root;
    141187                    }
    142                     return &FolderMapping[i];
     188                    return &g_FolderMapping[i];
    143189                }
    144                 else
    145                 {
    146                     AssertFailed();
    147                 }
     190                AssertFailed();
    148191            }
    149192        }
    150193    }
    151 
    152194    return NULL;
    153195}
     
    157199    unsigned root;
    158200
    159     for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
    160     {
    161         if (aIndexFromRoot[root] == SHFL_ROOT_NIL)
    162         {
    163             aIndexFromRoot[root] = iMapping;
     201    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
     202    {
     203        if (g_aIndexFromRoot[root] == SHFL_ROOT_NIL)
     204        {
     205            g_aIndexFromRoot[root] = iMapping;
     206            g_auRootHandleVersions[root] += 1;
    164207            return;
    165208        }
     
    173216    unsigned root;
    174217
    175     for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
    176     {
    177         if (aIndexFromRoot[root] == iMapping)
    178         {
    179             aIndexFromRoot[root] = SHFL_ROOT_NIL;
    180             return;
     218    for (root = 0; root < RT_ELEMENTS(g_aIndexFromRoot); root++)
     219    {
     220        if (g_aIndexFromRoot[root] == iMapping)
     221        {
     222            g_aIndexFromRoot[root] = SHFL_ROOT_NIL;
     223            g_auRootHandleVersions[root] += 1;
     224            Log(("vbsfRootHandleRemove: Removed root=%u (iMapping=%u)\n", root, iMapping));
     225
     226            /* Note! Do not stop here as g_aIndexFromRoot may (at least it could
     227                     prior to the introduction of fLoadedRootId) contain
     228                     duplicates after restoring save state. */
    181229        }
    182230    }
     
    209257    Log(("vbsfMappingsAdd %ls\n", pMapName->String.ucs2));
    210258
    211     /* check for duplicates */
    212     for (i=0; i<SHFL_MAX_MAPPINGS; i++)
    213     {
    214         if (FolderMapping[i].fValid == true)
    215         {
    216             if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
     259    /* Check for duplicates, ignoring placeholders to give the GUI to change stuff at runtime. */
     260    /** @todo bird: Not entirely sure about ignoring placeholders, but you cannot
     261     *        trigger auto-umounting without ignoring them. */
     262    if (!fPlaceholder)
     263    {
     264        for (i = 0; i < SHFL_MAX_MAPPINGS; i++)
     265        {
     266            if (   g_FolderMapping[i].fValid
     267                && !g_FolderMapping[i].fPlaceholder)
    217268            {
    218                 AssertMsgFailed(("vbsfMappingsAdd: %ls mapping already exists!!\n", pMapName->String.ucs2));
    219                 return VERR_ALREADY_EXISTS;
     269                if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
     270                {
     271                    AssertMsgFailed(("vbsfMappingsAdd: %ls mapping already exists!!\n", pMapName->String.ucs2));
     272                    return VERR_ALREADY_EXISTS;
     273                }
    220274            }
    221275        }
    222276    }
    223277
    224     for (i=0; i<SHFL_MAX_MAPPINGS; i++)
    225     {
    226         if (FolderMapping[i].fValid == false)
     278    for (i = 0; i < SHFL_MAX_MAPPINGS; i++)
     279    {
     280        if (g_FolderMapping[i].fValid == false)
    227281        {
    228282            /* Make sure the folder name is an absolute path, otherwise we're
     
    232286            AssertRCReturn(rc, rc);
    233287
    234             FolderMapping[i].pszFolderName   = RTStrDup(szAbsFolderName);
    235             FolderMapping[i].pMapName        = ShflStringDup(pMapName);
    236             FolderMapping[i].pAutoMountPoint = ShflStringDup(pAutoMountPoint);
    237             if (   !FolderMapping[i].pszFolderName
    238                 || !FolderMapping[i].pMapName
    239                 || !FolderMapping[i].pAutoMountPoint)
     288            g_FolderMapping[i].pszFolderName   = RTStrDup(szAbsFolderName);
     289            g_FolderMapping[i].pMapName        = ShflStringDup(pMapName);
     290            g_FolderMapping[i].pAutoMountPoint = ShflStringDup(pAutoMountPoint);
     291            if (   !g_FolderMapping[i].pszFolderName
     292                || !g_FolderMapping[i].pMapName
     293                || !g_FolderMapping[i].pAutoMountPoint)
    240294            {
    241                 RTStrFree(FolderMapping[i].pszFolderName);
    242                 RTMemFree(FolderMapping[i].pMapName);
    243                 RTMemFree(FolderMapping[i].pAutoMountPoint);
     295                RTStrFree(g_FolderMapping[i].pszFolderName);
     296                RTMemFree(g_FolderMapping[i].pMapName);
     297                RTMemFree(g_FolderMapping[i].pAutoMountPoint);
    244298                return VERR_NO_MEMORY;
    245299            }
    246300
    247             FolderMapping[i].fValid          = true;
    248             FolderMapping[i].cMappings       = 0;
    249             FolderMapping[i].fWritable       = fWritable;
    250             FolderMapping[i].fAutoMount      = fAutoMount;
    251             FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
    252             FolderMapping[i].fMissing        = fMissing;
    253             FolderMapping[i].fPlaceholder    = fPlaceholder;
     301            g_FolderMapping[i].fValid          = true;
     302            g_FolderMapping[i].cMappings       = 0;
     303            g_FolderMapping[i].fWritable       = fWritable;
     304            g_FolderMapping[i].fAutoMount      = fAutoMount;
     305            g_FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
     306            g_FolderMapping[i].fMissing        = fMissing;
     307            g_FolderMapping[i].fPlaceholder    = fPlaceholder;
     308            g_FolderMapping[i].fLoadedRootId   = false;
    254309
    255310            /* Check if the host file system is case sensitive */
    256311            RTFSPROPERTIES prop;
    257312            prop.fCaseSensitive = false; /* Shut up MSC. */
    258             rc = RTFsQueryProperties(FolderMapping[i].pszFolderName, &prop);
     313            rc = RTFsQueryProperties(g_FolderMapping[i].pszFolderName, &prop);
    259314            AssertRC(rc);
    260             FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
     315            g_FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
    261316            vbsfRootHandleAdd(i);
     317            vbsfMappingsWakeupAllWaiters();
    262318            break;
    263319        }
     
    269325    }
    270326
    271     Log(("vbsfMappingsAdd: added mapping %s to %ls\n", pszFolderName, pMapName->String.ucs2));
     327    Log(("vbsfMappingsAdd: added mapping %s to %ls (slot %u, root %u)\n",
     328         pszFolderName, pMapName->String.ucs2, i, vbsfMappingGetRootFromIndex(i)));
    272329    return VINF_SUCCESS;
    273330}
     
    285342int vbsfMappingsRemove(PSHFLSTRING pMapName)
    286343{
    287     unsigned i;
    288 
    289344    Assert(pMapName);
    290 
    291345    Log(("vbsfMappingsRemove %ls\n", pMapName->String.ucs2));
    292     for (i=0; i<SHFL_MAX_MAPPINGS; i++)
    293     {
    294         if (FolderMapping[i].fValid == true)
    295         {
    296             if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
     346
     347    /*
     348     * We must iterate thru the whole table as may have 0+ placeholder entries
     349     * and 0-1 regular entries with the same name.  Also, it is good to kick
     350     * the guest automounter into action wrt to evicting placeholders.
     351     */
     352    int rc = VERR_FILE_NOT_FOUND;
     353    for (unsigned i = 0; i < SHFL_MAX_MAPPINGS; i++)
     354    {
     355        if (g_FolderMapping[i].fValid == true)
     356        {
     357            if (!RTUtf16LocaleICmp(g_FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
    297358            {
    298                 if (FolderMapping[i].cMappings != 0)
     359                if (g_FolderMapping[i].cMappings != 0)
    299360                {
    300                     LogRel2(("SharedFolders: removing '%ls' -> '%s', which is still used by the guest\n",
    301                              pMapName->String.ucs2, FolderMapping[i].pszFolderName));
    302                     FolderMapping[i].fMissing = true;
    303                     FolderMapping[i].fPlaceholder = true;
    304                     return VINF_PERMISSION_DENIED;
     361                    LogRel2(("SharedFolders: removing '%ls' -> '%s'%s, which is still used by the guest\n", pMapName->String.ucs2,
     362                             g_FolderMapping[i].pszFolderName, g_FolderMapping[i].fPlaceholder ? " (again)" : ""));
     363                    g_FolderMapping[i].fMissing = true;
     364                    g_FolderMapping[i].fPlaceholder = true;
     365                    vbsfMappingsWakeupAllWaiters();
     366                    rc = VINF_PERMISSION_DENIED;
    305367                }
    306 
    307                 /* pMapName can be the same as FolderMapping[i].pMapName,
    308                  * log it before deallocating the memory.
    309                  */
    310                 Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
    311 
    312                 RTStrFree(FolderMapping[i].pszFolderName);
    313                 RTMemFree(FolderMapping[i].pMapName);
    314                 FolderMapping[i].pszFolderName = NULL;
    315                 FolderMapping[i].pMapName      = NULL;
    316                 FolderMapping[i].fValid        = false;
    317                 vbsfRootHandleRemove(i);
    318                 return VINF_SUCCESS;
     368                else
     369                {
     370                    /* pMapName can be the same as g_FolderMapping[i].pMapName when
     371                     * called from vbsfUnmapFolder, log it before deallocating the memory. */
     372                    Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
     373                    bool fSame = g_FolderMapping[i].pMapName == pMapName;
     374
     375                    RTStrFree(g_FolderMapping[i].pszFolderName);
     376                    RTMemFree(g_FolderMapping[i].pMapName);
     377                    g_FolderMapping[i].pszFolderName = NULL;
     378                    g_FolderMapping[i].pMapName      = NULL;
     379                    g_FolderMapping[i].fValid        = false;
     380                    vbsfRootHandleRemove(i);
     381                    vbsfMappingsWakeupAllWaiters();
     382                    if (rc == VERR_FILE_NOT_FOUND)
     383                        rc = VINF_SUCCESS;
     384                    if (fSame)
     385                        break;
     386                }
    319387            }
    320388        }
    321389    }
    322390
    323     AssertMsgFailed(("vbsfMappingsRemove: mapping %ls not found!!!!\n", pMapName->String.ucs2));
    324     return VERR_FILE_NOT_FOUND;
     391    return rc;
    325392}
    326393
     
    378445#endif
    379446/**
    380  * Note: If pMappings / *pcMappings is smaller than the actual amount of mappings
    381  *       that *could* have been returned *pcMappings contains the required buffer size
    382  *       so that the caller can retry the operation if wanted.
    383  */
    384 int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings)
    385 {
    386     int rc = VINF_SUCCESS;
    387 
    388     uint32_t cMappings = 0; /* Will contain actual valid mappings. */
    389     uint32_t idx = 0;       /* Current index in mappings buffer. */
    390 
     447 * @note If pMappings / *pcMappings is smaller than the actual amount of
     448 *       mappings that *could* have been returned *pcMappings contains the
     449 *       required buffer size so that the caller can retry the operation if
     450 *       wanted.
     451 */
     452int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, bool fOnlyAutoMounts, PSHFLMAPPING pMappings, uint32_t *pcMappings)
     453{
    391454    LogFlow(("vbsfMappingsQuery: pClient = %p, pMappings = %p, pcMappings = %p, *pcMappings = %d\n",
    392455             pClient, pMappings, pcMappings, *pcMappings));
    393456
     457    uint32_t const cMaxMappings = *pcMappings;
     458    uint32_t       idx          = 0;
    394459    for (uint32_t i = 0; i < SHFL_MAX_MAPPINGS; i++)
    395460    {
    396461        MAPPING *pFolderMapping = vbsfMappingGetByRoot(i);
    397462        if (   pFolderMapping != NULL
    398             && pFolderMapping->fValid == true)
    399         {
    400             if (idx < *pcMappings)
     463            && pFolderMapping->fValid
     464            && (   !fOnlyAutoMounts
     465                || (pFolderMapping->fAutoMount && !pFolderMapping->fPlaceholder)) )
     466        {
     467            if (idx < cMaxMappings)
    401468            {
    402                 /* Skip mappings which are not marked for auto-mounting if
    403                  * the SHFL_MF_AUTOMOUNT flag ist set. */
    404                 if (   (pClient->fu32Flags & SHFL_MF_AUTOMOUNT)
    405                     && !pFolderMapping->fAutoMount)
    406                     continue;
    407 
    408469                pMappings[idx].u32Status = SHFL_MS_NEW;
    409                 pMappings[idx].root = i;
    410                 idx++;
     470                pMappings[idx].root      = i;
    411471            }
    412             cMappings++;
     472            idx++;
    413473        }
    414474    }
     
    416476    /* Return actual number of mappings, regardless whether the handed in
    417477     * mapping buffer was big enough. */
    418     *pcMappings = cMappings;
    419 
    420     LogFlow(("vbsfMappingsQuery: return rc = %Rrc\n", rc));
    421     return rc;
     478    /** @todo r=bird: This is non-standard interface behaviour.  We return
     479     *        VERR_BUFFER_OVERFLOW or at least a VINF_BUFFER_OVERFLOW here.
     480     *
     481     *        Guess this goes well along with ORing SHFL_MF_AUTOMOUNT into
     482     *        pClient->fu32Flags rather than passing it as fOnlyAutoMounts...
     483     *        Not amused by this. */
     484    *pcMappings = idx;
     485
     486    LogFlow(("vbsfMappingsQuery: returns VINF_SUCCESS (idx=%u, cMaxMappings=%u)\n", idx, cMaxMappings));
     487    return VINF_SUCCESS;
    422488}
    423489
     
    437503int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString)
    438504{
    439     int rc = VINF_SUCCESS;
    440 
    441     LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n",
    442              pClient, root, pString));
    443 
     505    LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n", pClient, root, pString));
     506
     507    int rc;
    444508    MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
    445     if (pFolderMapping == NULL)
    446     {
    447         return VERR_INVALID_PARAMETER;
    448     }
    449 
    450     if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
    451     {
    452         /* Not implemented. */
    453         AssertFailed();
    454         return VERR_INVALID_PARAMETER;
    455     }
    456 
    457     if (pFolderMapping->fValid == true)
    458     {
    459         if (pString->u16Size < pFolderMapping->pMapName->u16Size)
    460         {
    461             Log(("vbsfMappingsQuery: passed string too short (%d < %d bytes)!\n",
    462                 pString->u16Size,  pFolderMapping->pMapName->u16Size));
    463             rc = VERR_INVALID_PARAMETER;
     509    if (pFolderMapping)
     510    {
     511        if (pFolderMapping->fValid)
     512        {
     513            if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
     514                rc = ShflStringCopyUtf16BufAsUtf8(pString, pFolderMapping->pMapName);
     515            else
     516            {
     517                /* Not using ShlfStringCopy here as behaviour shouldn't change... */
     518                if (pString->u16Size < pFolderMapping->pMapName->u16Size)
     519                {
     520                    Log(("vbsfMappingsQuery: passed string too short (%d < %d bytes)!\n",
     521                        pString->u16Size,  pFolderMapping->pMapName->u16Size));
     522                    rc = VERR_INVALID_PARAMETER;
     523                }
     524                else
     525                {
     526                    pString->u16Length = pFolderMapping->pMapName->u16Length;
     527                    memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2,
     528                           pFolderMapping->pMapName->u16Size);
     529                    rc = VINF_SUCCESS;
     530                }
     531            }
    464532        }
    465533        else
    466         {
    467             pString->u16Length = pFolderMapping->pMapName->u16Length;
    468             memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2,
    469                    pFolderMapping->pMapName->u16Size);
    470         }
     534            rc = VERR_FILE_NOT_FOUND;
    471535    }
    472536    else
    473         rc = VERR_FILE_NOT_FOUND;
     537        rc = VERR_INVALID_PARAMETER;
    474538
    475539    LogFlow(("vbsfMappingsQuery:Name return rc = %Rrc\n", rc));
    476 
    477540    return rc;
    478541}
     
    540603    return rc;
    541604}
     605
     606/**
     607 * Implements SHFL_FN_QUERY_MAP_INFO.
     608 * @since VBox 6.0
     609 */
     610int vbsfMappingsQueryInfo(PSHFLCLIENTDATA pClient, SHFLROOT root, PSHFLSTRING pNameBuf, PSHFLSTRING pMntPtBuf,
     611                          uint64_t *pfFlags, uint32_t *puVersion)
     612{
     613    LogFlow(("vbsfMappingsQueryInfo: pClient=%p root=%d\n", pClient, root));
     614
     615    /* Resolve the root handle. */
     616    int rc;
     617    PMAPPING pFolderMapping = vbsfMappingGetByRoot(root);
     618    if (pFolderMapping)
     619    {
     620        if (pFolderMapping->fValid)
     621        {
     622            /*
     623             * Produce the output.
     624             */
     625            *puVersion = g_auRootHandleVersions[root];
     626
     627            *pfFlags = 0;
     628            if (pFolderMapping->fWritable)
     629                *pfFlags |= SHFL_MIF_WRITABLE;
     630            if (pFolderMapping->fAutoMount)
     631                *pfFlags |= SHFL_MIF_AUTO_MOUNT;
     632            if (pFolderMapping->fHostCaseSensitive)
     633                *pfFlags |= SHFL_MIF_HOST_ICASE;
     634            if (pFolderMapping->fGuestCaseSensitive)
     635                *pfFlags |= SHFL_MIF_GUEST_ICASE;
     636            if (pFolderMapping->fSymlinksCreate)
     637                *pfFlags |= SHFL_MIF_SYMLINK_CREATION;
     638
     639            int rc2;
     640            if (pClient->fu32Flags & SHFL_CF_UTF8)
     641            {
     642                rc = ShflStringCopyUtf16BufAsUtf8(pNameBuf, pFolderMapping->pMapName);
     643                rc2 = ShflStringCopyUtf16BufAsUtf8(pMntPtBuf, pFolderMapping->pAutoMountPoint);
     644            }
     645            else
     646            {
     647                rc = ShflStringCopy(pNameBuf, pFolderMapping->pMapName, sizeof(RTUTF16));
     648                rc2 = ShflStringCopy(pMntPtBuf, pFolderMapping->pAutoMountPoint, sizeof(RTUTF16));
     649            }
     650            if (RT_SUCCESS(rc))
     651                rc = rc2;
     652        }
     653        else
     654            rc = VERR_FILE_NOT_FOUND;
     655    }
     656    else
     657        rc = VERR_INVALID_PARAMETER;
     658    LogFlow(("vbsfMappingsQueryInfo: returns %Rrc\n", rc));
     659    return rc;
     660}
     661
     662
    542663
    543664#ifdef UNITTEST
     
    662783    return rc;
    663784}
     785
     786/**
     787 * SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES implementation.
     788 *
     789 * @returns VBox status code.
     790 * @retval  VINF_SUCCESS on change.
     791 * @retval  VINF_TRY_AGAIN on resume.
     792 * @retval  VINF_HGCM_ASYNC_EXECUTE if waiting.
     793 * @retval  VERR_CANCELLED if cancelled.
     794 * @retval  VERR_OUT_OF_RESOURCES if there are too many pending waits.
     795 *
     796 * @param   pClient     The calling client.
     797 * @param   hCall       The call handle.
     798 * @param   pParm       The parameter (32-bit).
     799 * @param   fRestored   Set if this is a call restored & resubmitted from saved
     800 *                      state.
     801 * @since   VBox 6.0
     802 */
     803int vbsfMappingsWaitForChanges(PSHFLCLIENTDATA pClient, VBOXHGCMCALLHANDLE hCall, PVBOXHGCMSVCPARM pParm, bool fRestored)
     804{
     805    /*
     806     * Return immediately if the fodler mappings have changed since last call
     807     * or if we got restored from saved state (adding of global folders, etc).
     808     */
     809    uint32_t uCurVersion = g_uFolderMappingsVersion;
     810    if (   pParm->u.uint32 != uCurVersion
     811        || fRestored
     812        || (pClient->fu32Flags & SHFL_CF_CANCEL_NEXT_WAIT) )
     813    {
     814        int rc = VINF_SUCCESS;
     815        if (pClient->fu32Flags & SHFL_CF_CANCEL_NEXT_WAIT)
     816        {
     817            pClient->fu32Flags &= ~SHFL_CF_CANCEL_NEXT_WAIT;
     818            rc = VERR_CANCELLED;
     819        }
     820        else if (fRestored)
     821        {
     822            rc = VINF_TRY_AGAIN;
     823            if (pParm->u.uint32 == uCurVersion)
     824                uCurVersion = uCurVersion != UINT32_C(0x55555555) ? UINT32_C(0x55555555) : UINT32_C(0x99999999);
     825        }
     826        Log(("vbsfMappingsWaitForChanges: Version %#x -> %#x, returning %Rrc immediately.\n", pParm->u.uint32, uCurVersion, rc));
     827        pParm->u.uint32 = uCurVersion;
     828        return rc;
     829    }
     830
     831    /*
     832     * Setup a wait if we can.
     833     */
     834    if (g_cMappingChangeWaiters < 64)
     835    {
     836        PSHFLMAPPINGSWAIT pWait = (PSHFLMAPPINGSWAIT)RTMemAlloc(sizeof(*pWait));
     837        if (pWait)
     838        {
     839            pWait->pClient = pClient;
     840            pWait->hCall   = hCall;
     841            pWait->pParm   = pParm;
     842
     843            RTListAppend(&g_MappingsChangeWaiters, &pWait->ListEntry);
     844            g_cMappingChangeWaiters += 1;
     845            return VINF_HGCM_ASYNC_EXECUTE;
     846        }
     847        return VERR_NO_MEMORY;
     848    }
     849    LogRelMax(32, ("vbsfMappingsWaitForChanges: Too many threads waiting for changes!\n"));
     850    return VERR_OUT_OF_RESOURCES;
     851}
     852
     853/**
     854 * SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS implementation.
     855 *
     856 * @returns VINF_SUCCESS
     857 * @param   pClient     The calling client to cancel all waits for.
     858 * @since   VBox 6.0
     859 */
     860int vbsfMappingsCancelChangesWaits(PSHFLCLIENTDATA pClient)
     861{
     862    uint32_t const uCurVersion = g_uFolderMappingsVersion;
     863
     864    PSHFLMAPPINGSWAIT pCur, pNext;
     865    RTListForEachSafe(&g_MappingsChangeWaiters, pCur, pNext, SHFLMAPPINGSWAIT, ListEntry)
     866    {
     867        if (pCur->pClient == pClient)
     868        {
     869            RTListNodeRemove(&pCur->ListEntry);
     870            pCur->pParm->u.uint32 = uCurVersion;
     871            g_pHelpers->pfnCallComplete(pCur->hCall, VERR_CANCELLED);
     872            RTMemFree(pCur);
     873        }
     874    }
     875
     876    /* Set a flag to make sure the next SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES doesn't block.
     877       This should help deal with races between this call and a thread about to do a wait. */
     878    pClient->fu32Flags |= SHFL_CF_CANCEL_NEXT_WAIT;
     879
     880    return VINF_SUCCESS;
     881}
     882
     883/**
     884 * Wakes up all clients waiting on
     885 */
     886static void vbsfMappingsWakeupAllWaiters(void)
     887{
     888    uint32_t const uCurVersion = ++g_uFolderMappingsVersion;
     889
     890    PSHFLMAPPINGSWAIT pCur, pNext;
     891    RTListForEachSafe(&g_MappingsChangeWaiters, pCur, pNext, SHFLMAPPINGSWAIT, ListEntry)
     892    {
     893        RTListNodeRemove(&pCur->ListEntry);
     894        pCur->pParm->u.uint32 = uCurVersion;
     895        g_pHelpers->pfnCallComplete(pCur->hCall, VERR_CANCELLED);
     896        RTMemFree(pCur);
     897    }
     898}
     899
  • trunk/src/VBox/HostServices/SharedFolders/mappings.h

    r75380 r75407  
    3838    bool        fPlaceholder;           /**< Mapping does not exist in the VM settings but the guest
    3939                                             still has. fMissing is always true for this mapping. */
     40    bool        fLoadedRootId;          /**< Set if vbsfMappingLoaded has found this mapping already. */
    4041} MAPPING;
    4142/** Pointer to a MAPPING structure. */
     
    5051int vbsfMappingsRemove(PSHFLSTRING pMapName);
    5152
    52 int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings);
     53int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, bool fOnlyAutoMounts, PSHFLMAPPING pMappings, uint32_t *pcMappings);
    5354int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString);
    5455int vbsfMappingsQueryWritable(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fWritable);
    5556int vbsfMappingsQueryAutoMount(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fAutoMount);
    5657int vbsfMappingsQuerySymlinksCreate(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fSymlinksCreate);
     58int vbsfMappingsQueryInfo(PSHFLCLIENTDATA pClient, SHFLROOT root, PSHFLSTRING pNameBuf, PSHFLSTRING pMntPtBuf,
     59                          uint64_t *pfFlags, uint32_t *puVersion);
    5760
    5861int vbsfMapFolder(PSHFLCLIENTDATA pClient, PSHFLSTRING pszMapName, RTUTF16 delimiter,
    5962                  bool fCaseSensitive, SHFLROOT *pRoot);
    6063int vbsfUnmapFolder(PSHFLCLIENTDATA pClient, SHFLROOT root);
     64
     65int vbsfMappingsWaitForChanges(PSHFLCLIENTDATA pClient, VBOXHGCMCALLHANDLE hCall, PVBOXHGCMSVCPARM pParm, bool fRestored);
     66int vbsfMappingsCancelChangesWaits(PSHFLCLIENTDATA pClient);
    6167
    6268const char* vbsfMappingsQueryHostRoot(SHFLROOT root);
     
    6571bool vbsfIsHostMappingCaseSensitive(SHFLROOT root);
    6672
    67 int vbsfMappingLoaded(const PMAPPING pLoadedMapping, SHFLROOT root);
     73int vbsfMappingLoaded(MAPPING const *pLoadedMapping, SHFLROOT root);
    6874PMAPPING vbsfMappingGetByRoot(SHFLROOT root);
    6975
  • trunk/src/VBox/HostServices/SharedFolders/service.cpp

    r75380 r75407  
    2626#include <iprt/string.h>
    2727#include <iprt/assert.h>
     28#include <VBox/AssertGuest.h>
    2829#include <VBox/vmm/ssm.h>
    2930#include <VBox/vmm/pdmifs.h>
     
    237238                rc = SSMR3GetMem(pSSM, pFolderName, cb);
    238239                AssertRCReturn(rc, rc);
    239                 AssertReturn(pFolderName->u16Length < cb && pFolderName->u16Size < pFolderName->u16Length,
     240                AssertReturn(pFolderName->u16Size < cb && pFolderName->u16Length < pFolderName->u16Size,
    240241                             SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    241242                                               "Bad folder name string: %#x/%#x cb=%#x\n",
     
    267268            rc = SSMR3GetMem(pSSM, pMapName, cb);
    268269            AssertRCReturn(rc, rc);
    269             AssertReturn(pMapName->u16Length < cb && pMapName->u16Size < pMapName->u16Length,
     270            AssertReturn(pMapName->u16Size < cb && pMapName->u16Length < pMapName->u16Size,
    270271                         SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    271272                                           "Bad map name string: %#x/%#x cb=%#x\n",
     
    293294                rc = SSMR3GetMem(pSSM, pAutoMountPoint, cb);
    294295                AssertRCReturn(rc, rc);
    295                 AssertReturn(pAutoMountPoint->u16Length < cb && pAutoMountPoint->u16Size < pAutoMountPoint->u16Length,
     296                AssertReturn(pAutoMountPoint->u16Size < cb && pAutoMountPoint->u16Length < pAutoMountPoint->u16Size,
    296297                             SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    297298                                               "Bad auto mount point string: %#x/%#x cb=%#x\n",
     
    331332}
    332333
    333 static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     334static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
     335                                   void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    334336{
    335337    RT_NOREF1(u32ClientID);
     
    388390                    if (fu32Flags & SHFL_MF_UTF8)
    389391                        pClient->fu32Flags |= SHFL_CF_UTF8;
    390                     if (fu32Flags & SHFL_MF_AUTOMOUNT)
    391                         pClient->fu32Flags |= SHFL_MF_AUTOMOUNT;
    392 
    393                     rc = vbsfMappingsQuery(pClient, pMappings, &cMappings);
     392                    /// @todo r=bird: Someone please explain this amusing code (r63916):
     393                    //if (fu32Flags & SHFL_MF_AUTOMOUNT)
     394                    //    pClient->fu32Flags |= SHFL_MF_AUTOMOUNT;
     395                    //
     396                    //rc = vbsfMappingsQuery(pClient, pMappings, &cMappings);
     397
     398                    rc = vbsfMappingsQuery(pClient, RT_BOOL(fu32Flags & SHFL_MF_AUTOMOUNT), pMappings, &cMappings);
    394399                    if (RT_SUCCESS(rc))
    395400                    {
     
    12951300        }
    12961301
     1302        case SHFL_FN_QUERY_MAP_INFO:
     1303        {
     1304            Log(("SharedFolders host service: svnCall: SHFL_FN_QUERY_MAP_INFO\n"));
     1305
     1306            /* Validate input: */
     1307            rc = VERR_INVALID_PARAMETER;
     1308            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_QUERY_MAP_INFO);
     1309            ASSERT_GUEST_BREAK(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); /* root */
     1310            ASSERT_GUEST_BREAK(paParms[1].type == VBOX_HGCM_SVC_PARM_PTR);   /* name */
     1311            PSHFLSTRING  pNameBuf  = (PSHFLSTRING)paParms[1].u.pointer.addr;
     1312            ASSERT_GUEST_BREAK(ShflStringIsValidOut(pNameBuf, paParms[1].u.pointer.size));
     1313            ASSERT_GUEST_BREAK(paParms[2].type == VBOX_HGCM_SVC_PARM_PTR);   /* mountPoint */
     1314            PSHFLSTRING  pMntPtBuf = (PSHFLSTRING)paParms[2].u.pointer.addr;
     1315            ASSERT_GUEST_BREAK(ShflStringIsValidOut(pMntPtBuf, paParms[2].u.pointer.size));
     1316            ASSERT_GUEST_BREAK(paParms[3].type == VBOX_HGCM_SVC_PARM_64BIT); /* flags */
     1317            ASSERT_GUEST_BREAK(!(paParms[3].u.uint64 & ~(SHFL_MIQF_DRIVE_LETTER | SHFL_MIQF_PATH))); /* flags */
     1318            ASSERT_GUEST_BREAK(paParms[4].type == VBOX_HGCM_SVC_PARM_32BIT); /* version */
     1319
     1320            /* Execute the function: */
     1321            rc = vbsfMappingsQueryInfo(pClient, paParms[0].u.uint32, pNameBuf, pMntPtBuf,
     1322                                       &paParms[3].u.uint64, &paParms[4].u.uint32);
     1323            break;
     1324        }
     1325
     1326        case SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES:
     1327        {
     1328            Log(("SharedFolders host service: svnCall: SHFL_FN_WAIT_FOR_CHANGES\n"));
     1329
     1330            /* Validate input: */
     1331            rc = VERR_INVALID_PARAMETER;
     1332            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES);
     1333            ASSERT_GUEST_BREAK(paParms[0].type == VBOX_HGCM_SVC_PARM_32BIT); /* uFolderMappingsVersion */
     1334
     1335            /* Execute the function: */
     1336            rc = vbsfMappingsWaitForChanges(pClient, callHandle, paParms, g_pHelpers->pfnIsCallRestored(callHandle));
     1337            fAsynchronousProcessing = rc == VINF_HGCM_ASYNC_EXECUTE;
     1338            break;
     1339        }
     1340
     1341        case SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS:
     1342        {
     1343            Log(("SharedFolders host service: svnCall: SHFL_FN_CANCEL_WAIT_FOR_CHANGES\n"));
     1344
     1345            /* Validate input: */
     1346            rc = VERR_INVALID_PARAMETER;
     1347            ASSERT_GUEST_BREAK(cParms == SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS);
     1348
     1349            /* Execute the function: */
     1350            rc = vbsfMappingsCancelChangesWaits(pClient);
     1351            break;
     1352        }
     1353
    12971354        default:
    12981355        {
  • trunk/src/VBox/HostServices/SharedFolders/shfl.h

    r69500 r75407  
    4343#define SHFL_CF_SYMLINKS         (0x00000008)
    4444
     45/** The call to SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES will return immediately
     46 *  because of a SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS call. */
     47#define SHFL_CF_CANCEL_NEXT_WAIT (0x00000010)
     48
    4549/** @} */
    4650
  • trunk/src/VBox/HostServices/SharedFolders/vbsf.h

    r69500 r75407  
     1/* $Id$ */
    12/** @file
    23 * VBox Shared Folders header.
     
    1516 */
    1617
    17 #ifndef __VBSF__H
    18 #define __VBSF__H
     18#ifndef ___vbsf_h___
     19#define ___vbsf_h___
    1920
    2021#include "shfl.h"
     
    4142int vbsfSymlink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pNewPath, SHFLSTRING *pOldPath, SHFLFSOBJINFO *pInfo);
    4243
    43 #endif /* __VBSF__H */
     44#endif /* !___vbsf_h___ */
     45
Note: See TracChangeset for help on using the changeset viewer.

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