/**
 * Retrieves and clears the user credentials for logging into the guest OS.
 *
 * @returns IPRT status value
 * @param   ppszUser        Receives pointer of allocated user name string.
 *                          The returned pointer must be freed using VbglR3CredentialsDestroy().
 * @param   ppszPassword    Receives pointer of allocated user password string.
 *                          The returned pointer must be freed using VbglR3CredentialsDestroy().
 * @param   ppszDomain      Receives pointer of allocated domain name string.
 *                          The returned pointer must be freed using VbglR3CredentialsDestroy().
 */
VBGLR3DECL(int) VbglR3CredentialsRetrieve(char **ppszUser, char **ppszPassword, char **ppszDomain)
{
    AssertPtrReturn(ppszUser, VERR_INVALID_POINTER);
    AssertPtrReturn(ppszPassword, VERR_INVALID_POINTER);
    AssertPtrReturn(ppszDomain, VERR_INVALID_POINTER);

    VMMDevCredentials Req;
    RT_ZERO(Req);
    vmmdevInitRequest((VMMDevRequestHeader*)&Req, VMMDevReq_QueryCredentials);
    Req.u32Flags |= VMMDEV_CREDENTIALS_READ | VMMDEV_CREDENTIALS_CLEAR;

    int rc = vbglR3GRPerform(&Req.header);
    if (RT_SUCCESS(rc))
    {
        rc = RTStrDupEx(ppszUser, Req.szUserName);
        if (RT_SUCCESS(rc))
        {
            rc = RTStrDupEx(ppszPassword, Req.szPassword);
            if (RT_SUCCESS(rc))
            {
                rc = RTStrDupEx(ppszDomain, Req.szDomain);
                if (RT_SUCCESS(rc))
                    return VINF_SUCCESS;

                RTStrFree(*ppszPassword);
            }
            RTStrFree(*ppszUser);
        }
    }
    return rc;
}
Esempio n. 2
0
USBLIB_DECL(int) USBLibGetClientInfo(char *pszDeviceIdent, char **ppszClientPath, int *pInstance)
{
    LogFlow((USBLIBR3 ":USBLibGetClientInfo pszDeviceIdent=%s ppszClientPath=%p pInstance=%p\n",
                pszDeviceIdent, ppszClientPath, pInstance));

    AssertPtrReturn(pInstance, VERR_INVALID_PARAMETER);
    AssertPtrReturn(ppszClientPath, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszDeviceIdent, VERR_INVALID_PARAMETER);

    VBOXUSBREQ_CLIENT_INFO Req;
    bzero(&Req, sizeof(Req));
    RTStrPrintf(Req.szDeviceIdent, sizeof(Req.szDeviceIdent), "%s", pszDeviceIdent);

    int rc = usblibDoIOCtl(VBOXUSBMON_IOCTL_CLIENT_INFO, &Req, sizeof(Req));
    if (RT_SUCCESS(rc))
    {
        *pInstance = Req.Instance;
        rc = RTStrDupEx(ppszClientPath, Req.szClientPath);
        if (RT_SUCCESS(rc))
            return VINF_SUCCESS;

        LogRel((USBLIBR3 ":USBLibGetClientInfo RTStrDupEx failed! rc=%Rrc szClientPath=%s\n", rc, Req.szClientPath));
    }
    else
        LogRel((USBLIBR3 ":USBLibGetClientInfo VBOXUSBMON_IOCTL_CLIENTPATH failed! rc=%Rrc\n", rc));

    return rc;
}
Esempio n. 3
0
int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
{
    int rc = RTStrValidateEncodingEx(pszNativePath, RTSTR_MAX, 0 /*fFlags*/);
    if (RT_SUCCESS(rc))
        rc = RTStrDupEx(ppszPath, pszNativePath);
    NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
    return rc;
}
Esempio n. 4
0
int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
{
    /** @todo We must compose the codepoints in the string here.  We get file names
     *        in normalization form D so we'll end up with normalization form C
     *        whatever approach we take. */
    int rc = RTStrValidateEncodingEx(pszNativePath, RTSTR_MAX, 0 /*fFlags*/);
    if (RT_SUCCESS(rc))
        rc = RTStrDupEx(ppszPath, pszNativePath);
    NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
    return rc;
}
Esempio n. 5
0
/**
 * Schedules the setting of a property.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_STATE if not a SVN WC file.
 * @param   pState              The rewrite state to work on.
 * @param   pszName             The name of the property to set.
 * @param   pszValue            The value.  NULL means deleting it.
 */
int ScmSvnSetProperty(PSCMRWSTATE pState, const char *pszName, const char *pszValue)
{
    /*
     * Update any existing entry first.
     */
    size_t i = pState->cSvnPropChanges;
    while (i-- > 0)
        if (!strcmp(pState->paSvnPropChanges[i].pszName,  pszName))
        {
            if (!pszValue)
            {
                RTStrFree(pState->paSvnPropChanges[i].pszValue);
                pState->paSvnPropChanges[i].pszValue = NULL;
            }
            else
            {
                char *pszCopy;
                int rc = RTStrDupEx(&pszCopy, pszValue);
                if (RT_FAILURE(rc))
                    return rc;
                pState->paSvnPropChanges[i].pszValue = pszCopy;
            }
            return VINF_SUCCESS;
        }

    /*
     * Insert a new entry.
     */
    i = pState->cSvnPropChanges;
    if ((i % 32) == 0)
    {
        void *pvNew = RTMemRealloc(pState->paSvnPropChanges, (i + 32) * sizeof(SCMSVNPROP));
        if (!pvNew)
            return VERR_NO_MEMORY;
        pState->paSvnPropChanges = (PSCMSVNPROP)pvNew;
    }

    pState->paSvnPropChanges[i].pszName  = RTStrDup(pszName);
    pState->paSvnPropChanges[i].pszValue = pszValue ? RTStrDup(pszValue) : NULL;
    if (   pState->paSvnPropChanges[i].pszName
        && (pState->paSvnPropChanges[i].pszValue || !pszValue) )
        pState->cSvnPropChanges = i + 1;
    else
    {
        RTStrFree(pState->paSvnPropChanges[i].pszName);
        pState->paSvnPropChanges[i].pszName = NULL;
        RTStrFree(pState->paSvnPropChanges[i].pszValue);
        pState->paSvnPropChanges[i].pszValue = NULL;
        return VERR_NO_MEMORY;
    }
    return VINF_SUCCESS;
}
/**
 * Fallback for VbglR3GetAdditionsVersion.
 */
static int vbglR3GetAdditionsCompileTimeVersion(char **ppszVer, char **ppszVerEx, char **ppszRev)
{
    int rc = VINF_SUCCESS;
    if (ppszVer)
        rc = RTStrDupEx(ppszVer, VBOX_VERSION_STRING_RAW);
    if (RT_SUCCESS(rc))
    {
        if (ppszVerEx)
            rc = RTStrDupEx(ppszVerEx, VBOX_VERSION_STRING);
        if (RT_SUCCESS(rc))
        {
            if (ppszRev)
            {
#if 0
                char szRev[64];
                RTStrPrintf(szRev, sizeof(szRev), "%d", VBOX_SVN_REV);
                rc = RTStrDupEx(ppszRev, szRev);
#else
                rc = RTStrDupEx(ppszRev, RT_XSTR(VBOX_SVN_REV));
#endif
            }
            if (RT_SUCCESS(rc))
                return VINF_SUCCESS;

            /* bail out: */
        }
        if (ppszVerEx)
        {
            RTStrFree(*ppszVerEx);
            *ppszVerEx = NULL;
        }
    }
    if (ppszVer)
    {
        RTStrFree(*ppszVer);
        *ppszVer = NULL;
    }
    return rc;
}
int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
{
    int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
    if (RT_SUCCESS(rc))
    {
        if (g_fPassthruUtf8 || !*pszNativePath)
            rc = RTStrDupEx(ppszPath, pszNativePath);
        else
            rc = rtStrConvert(pszNativePath, strlen(pszNativePath), g_szFsCodeset,
                              ppszPath, 0, "UTF-8",
                              2, g_enmFsToUtf8Idx);
    }

    NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
    return rc;
}
/**
 * Retrieves the installation path of Guest Additions.
 *
 * @returns IPRT status value
 * @param   ppszPath    Receives pointer of allocated installation path string.
 *                      The returned pointer must be freed using
 *                      RTStrFree().
 */
VBGLR3DECL(int) VbglR3GetAdditionsInstallationPath(char **ppszPath)
{
    int rc;
#ifdef RT_OS_WINDOWS
    HKEY hKey;
    rc = vbglR3QueryAdditionsWinStoragePath(&hKey);
    if (RT_SUCCESS(rc))
    {
        /* Installation directory. */
        DWORD dwType;
        DWORD dwSize = _MAX_PATH * sizeof(char);
        char *pszTmp = (char*)RTMemAlloc(dwSize + 1);
        if (pszTmp)
        {
            LONG l = RegQueryValueEx(hKey, "InstallDir", NULL, &dwType, (BYTE*)(LPCTSTR)pszTmp, &dwSize);
            if ((l != ERROR_SUCCESS) && (l != ERROR_FILE_NOT_FOUND))
            {
                rc = RTErrConvertFromNtStatus(l);
            }
            else
            {
                if (dwType == REG_SZ)
                    rc = RTStrDupEx(ppszPath, pszTmp);
                else
                    rc = VERR_INVALID_PARAMETER;
                if (RT_SUCCESS(rc))
                {
                    /* Flip slashes. */
                    for (char *pszTmp2 = ppszPath[0]; *pszTmp2; ++pszTmp2)
                        if (*pszTmp2 == '\\')
                            *pszTmp2 = '/';
                }
            }
            RTMemFree(pszTmp);
        }
        else
            rc = VERR_NO_MEMORY;
        rc = vbglR3CloseAdditionsWinStoragePath(hKey);
    }
#else
    /** @todo implement me */
    rc = VERR_NOT_IMPLEMENTED;
#endif
    return rc;
}
/**
 * Worker common to RTManifestSetAttr and RTManifestEntrySetAttr.
 *
 * @returns IPRT status code.
 * @param   pEntry              Pointer to the entry.
 * @param   pszAttr             The name of the attribute to add.
 * @param   pszValue            The value string.
 * @param   fType               The attribute type type.
 */
static int rtManifestSetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, const char *pszValue, uint32_t fType)
{
    char *pszValueCopy;
    int rc = RTStrDupEx(&pszValueCopy, pszValue);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Does the attribute exist already?
     */
    AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0);
    PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr);
    if (pAttr)
    {
        RTStrFree(pAttr->pszValue);
        pAttr->pszValue = pszValueCopy;
        pAttr->fType    = fType;
    }
    else
    {
        size_t          cbName = strlen(pszAttr) + 1;
        pAttr = (PRTMANIFESTATTR)RTMemAllocVar(RT_OFFSETOF(RTMANIFESTATTR, szName[cbName]));
        if (!pAttr)
        {
            RTStrFree(pszValueCopy);
            return VERR_NO_MEMORY;
        }
        memcpy(pAttr->szName, pszAttr, cbName);
        pAttr->StrCore.pszString = pAttr->szName;
        pAttr->StrCore.cchString = cbName - 1;
        pAttr->pszValue = pszValueCopy;
        pAttr->fType    = fType;
        if (RT_UNLIKELY(!RTStrSpaceInsert(&pEntry->Attributes, &pAttr->StrCore)))
        {
            AssertFailed();
            RTStrFree(pszValueCopy);
            RTMemFree(pAttr);
            return VERR_INTERNAL_ERROR_4;
        }
        pEntry->cAttributes++;
    }

    return VINF_SUCCESS;
}
/**
 * Retrieves the prefix for a shared folder mount point.  If no prefix
 * is set in the guest properties "sf_" is returned.
 *
 * @returns VBox status code.
 * @param   ppszPrefix      Where to return the prefix string.  This shall be
 *                          freed by calling RTStrFree.
 */
VBGLR3DECL(int) VbglR3SharedFolderGetMountPrefix(char **ppszPrefix)
{
    AssertPtrReturn(ppszPrefix, VERR_INVALID_POINTER);
    int rc;
#ifdef VBOX_WITH_GUEST_PROPS
    uint32_t u32ClientIdGuestProp;
    rc = VbglR3GuestPropConnect(&u32ClientIdGuestProp);
    if (RT_SUCCESS(rc))
    {
        rc = VbglR3GuestPropReadValueAlloc(u32ClientIdGuestProp, "/VirtualBox/GuestAdd/SharedFolders/MountPrefix", ppszPrefix);
        if (rc == VERR_NOT_FOUND) /* No prefix set? Then set the default. */
        {
#endif
            rc = RTStrDupEx(ppszPrefix, "sf_");
#ifdef VBOX_WITH_GUEST_PROPS
        }
        VbglR3GuestPropDisconnect(u32ClientIdGuestProp);
    }
#endif
    return rc;
}
Esempio n. 11
0
/**
 * Basic API checks.
 * We'll return if any of these fails.
 */
static void tst1(void)
{
    RTTestISub("Basics");
    char *psz;
    int rc = VINF_SUCCESS;

    /* RTStrAlloc */
    RTTESTI_CHECK(psz = RTStrAlloc(0));
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrAlloc(1));
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrAlloc(128));
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    /* RTStrAllocEx */
    psz = (char*)"asdfasdf";
    RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 0), VINF_SUCCESS);
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 1), VINF_SUCCESS);
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 128), VINF_SUCCESS);
    RTTESTI_CHECK(psz && !*psz);
    RTStrFree(psz);

    /* RTStrRealloc */
    psz = NULL;
    RTTESTI_CHECK_RC(RTStrRealloc(&psz, 10), VINF_SUCCESS);
    RTTESTI_CHECK(psz && !psz[0]);
    RTTESTI_CHECK(psz && !psz[9]);
    RTStrFree(psz);

    psz = NULL;
    RTTESTI_CHECK_RC(RTStrRealloc(&psz, 0), VINF_SUCCESS);
    RTTESTI_CHECK(!psz);

    psz = NULL;
    RTTESTI_CHECK_RC(RTStrRealloc(&psz, 128), VINF_SUCCESS);
    RTTESTI_CHECK(psz && !psz[0]);
    RTTESTI_CHECK(psz && !psz[127]);
    if (psz)
    {
        memset(psz, 'a', 127);
        RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 160), VINF_SUCCESS);
        if (RT_SUCCESS(rc) && psz)
        {
            RTTESTI_CHECK(!psz[127]);
            RTTESTI_CHECK(!psz[159]);
            RTTESTI_CHECK(ASMMemIsAll8(psz, 127, 'a') == NULL);
            memset(psz, 'b', 159);

            RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 79), VINF_SUCCESS);
            if (RT_SUCCESS(rc))
            {
                RTTESTI_CHECK(!psz[78]);
                RTTESTI_CHECK(ASMMemIsAll8(psz, 78, 'b') == NULL);

                RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 0), VINF_SUCCESS);
                RTTESTI_CHECK(!psz);
            }
        }
    }
    RTStrFree(psz);

    /* RTStrDup */
    RTTESTI_CHECK(psz = RTStrDup(""));
    RTTESTI_CHECK(psz && *psz == '\0');
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDup("abcdefghijklmnop"));
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnop"));
    RTStrFree(psz);

    /* RTStrDupEx */
    psz = NULL;
    RTTESTI_CHECK_RC(RTStrDupEx(&psz, ""), VINF_SUCCESS);
    RTTESTI_CHECK(RT_FAILURE(rc) || *psz == '\0');
    if (RT_SUCCESS(rc))
        RTStrFree(psz);

    psz = (char*)"asdfasdfasdfasdf";
    RTTESTI_CHECK_RC(rc = RTStrDupEx(&psz, "abcdefghijklmnop"), VINF_SUCCESS);
    RTTESTI_CHECK(RT_FAILURE(rc) || !RTStrCmp(psz, "abcdefghijklmnop"));
    if (RT_SUCCESS(rc))
        RTStrFree(psz);

    /* RTStrDupN */
    RTTESTI_CHECK(psz = RTStrDupN("abcdefg", 3));
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDupN("abc", 100000));
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDupN("abc", 0));
    RTTESTI_CHECK(psz && *psz == '\0');
    RTStrFree(psz);

    /* RTStrAAppend */
    RTTESTI_CHECK(psz = RTStrDup("abc"));
    RTTESTI_CHECK_RC(RTStrAAppend(&psz, "def"), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdef"));
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDup("abc"));
    RTTESTI_CHECK_RC(RTStrAAppend(&psz, ""), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTTESTI_CHECK_RC(RTStrAAppend(&psz, NULL), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTStrFree(psz);

    psz = NULL;
    RTTESTI_CHECK_RC(RTStrAAppend(&psz, "xyz"), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "xyz"));
    RTStrFree(psz);

    /* RTStrAAppendN */
    RTTESTI_CHECK(psz = RTStrDup("abc"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "def", 1), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcd"));
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDup("abc"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", 0), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", RTSTR_MAX), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, NULL, 0), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTStrFree(psz);

    psz = NULL;
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "abc", 2), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "ab"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "cdefghijklm", 1), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abc"));
    RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "defghijklm", RTSTR_MAX), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklm"));
    RTStrFree(psz);

    /* RTStrAAppendExN / RTStrAAppendExNV */
    psz = NULL;
    RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", (size_t)1, "bc", (size_t)1, "cdefg", RTSTR_MAX, "hijkl", (size_t)2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
    RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 0), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
    RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, (size_t)0, "", (size_t)0), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
    RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", (size_t)1), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz-"));
    RTStrFree(psz);

    /* RTStrATruncate */
    psz = NULL;
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS);
    RTTESTI_CHECK(!psz);

    RTTESTI_CHECK(psz = RTStrDup(""));
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS);
    RTStrFree(psz);

    RTTESTI_CHECK(psz = RTStrDup("1234567890"));
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 5), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "12345"));
    RTStrFree(psz);

    psz = NULL;
    for (uint32_t i = 0; i < 128; i++)
        RTTESTI_CHECK_RC_RETV(RTStrAAppend(&psz, "abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS);
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, sizeof("abcdefghijklmnopqrstuvwxyz") - 1), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz"));
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 6), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "abcdef"));
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 1), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, "a"));
    RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS);
    RTTESTI_CHECK(!RTStrCmp(psz, ""));
    RTStrFree(psz);

}
/**
 * Retrieves the installed Guest Additions version and/or revision.
 *
 * @returns IPRT status value
 * @param   ppszVer     Receives pointer of allocated raw version string
 *                      (major.minor.build). NULL is accepted. The returned
 *                      pointer must be freed using RTStrFree().*
 * @param   ppszVerExt  Receives pointer of allocated full version string
 *                      (raw version + vendor suffix(es)). NULL is
 *                      accepted. The returned pointer must be freed using
 *                      RTStrFree().
 * @param   ppszRev     Receives pointer of allocated revision string. NULL is
 *                      accepted. The returned pointer must be freed using
 *                      RTStrFree().
 */
VBGLR3DECL(int) VbglR3GetAdditionsVersion(char **ppszVer, char **ppszVerExt, char **ppszRev)
{
    /*
     * Zap the return value up front.
     */
    if (ppszVer)
        *ppszVer    = NULL;
    if (ppszVerExt)
        *ppszVerExt = NULL;
    if (ppszRev)
        *ppszRev    = NULL;

#ifdef RT_OS_WINDOWS
    HKEY hKey;
    int rc = vbglR3QueryAdditionsWinStoragePath(&hKey);
    if (RT_SUCCESS(rc))
    {
        /*
         * Version.
         */
        char szTemp[32];
        if (ppszVer)
        {
            rc = vbglR3QueryRegistryString(hKey, "Version", szTemp, sizeof(szTemp));
            if (RT_SUCCESS(rc))
                rc = RTStrDupEx(ppszVer, szTemp);
        }

        if (   RT_SUCCESS(rc)
            && ppszVerExt)
        {
            rc = vbglR3QueryRegistryString(hKey, "VersionExt", szTemp, sizeof(szTemp));
            if (RT_SUCCESS(rc))
                rc = RTStrDupEx(ppszVerExt, szTemp);
        }

        /*
         * Revision.
         */
        if (   RT_SUCCESS(rc)
            && ppszRev)
        {
            rc = vbglR3QueryRegistryString(hKey, "Revision", szTemp, sizeof(szTemp));
            if (RT_SUCCESS(rc))
                rc = RTStrDupEx(ppszRev, szTemp);
        }

        int rc2 = vbglR3CloseAdditionsWinStoragePath(hKey);
        if (RT_SUCCESS(rc))
            rc = rc2;

        /* Clean up allocated strings on error. */
        if (RT_FAILURE(rc))
        {
            if (ppszVer)
                RTStrFree(*ppszVer);
            if (ppszVerExt)
                RTStrFree(*ppszVerExt);
            if (ppszRev)
                RTStrFree(*ppszRev);
        }
    }
    else
    {
        /*
         * No registry entries found, return the version string compiled
         * into this binary.
         */
        rc = vbglR3GetAdditionsCompileTimeVersion(ppszVer, ppszVerExt, ppszRev);
    }
    return rc;

#else  /* !RT_OS_WINDOWS */
    /*
     * On non-Windows platforms just return the compile-time version string.
     */
    return vbglR3GetAdditionsCompileTimeVersion(ppszVer, ppszVerExt, ppszRev);
#endif /* !RT_OS_WINDOWS */
}
Esempio n. 13
0
/**
 * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
 */
static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
{
    PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;

    /*
     * Dispense with the current object.
     */
    if (pThis->hVfsCurObj != NIL_RTVFSOBJ)
    {
        if (pThis->pCurIosData)
        {
            pThis->pCurIosData->fEndOfStream = true;
            pThis->pCurIosData->offFile      = pThis->pCurIosData->cbFile;
            pThis->pCurIosData = NULL;
        }

        RTVfsObjRelease(pThis->hVfsCurObj);
        pThis->hVfsCurObj = NIL_RTVFSOBJ;
    }

    /*
     * Check if we've already reached the end in some way.
     */
    if (pThis->fEndOfStream)
        return VERR_EOF;
    if (pThis->rcFatal != VINF_SUCCESS)
        return pThis->rcFatal;

    /*
     * Make sure the input stream is in the right place.
     */
    RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
    while (   offHdr >= 0
           && offHdr < pThis->offNextHdr)
    {
        int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr);
        if (RT_FAILURE(rc))
        {
            /** @todo Ignore if we're at the end of the stream? */
            return pThis->rcFatal = rc;
        }

        offHdr = RTVfsIoStrmTell(pThis->hVfsIos);
    }

    if (offHdr < 0)
        return pThis->rcFatal = (int)offHdr;
    if (offHdr > pThis->offNextHdr)
        return pThis->rcFatal = VERR_INTERNAL_ERROR_3;

    /*
     * Consume TAR headers.
     */
    size_t cbHdrs = 0;
    int rc;
    do
    {
        /*
         * Read the next header.
         */
        RTZIPTARHDR Hdr;
        size_t cbRead;
        rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
        if (RT_FAILURE(rc))
            return pThis->rcFatal = rc;
        if (rc == VINF_EOF && cbRead == 0)
        {
            pThis->fEndOfStream = true;
            return rtZipTarReaderIsAtEnd(&pThis->TarReader) ? VERR_EOF : VERR_TAR_UNEXPECTED_EOS;
        }
        if (cbRead != sizeof(Hdr))
            return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS;

        cbHdrs += sizeof(Hdr);

        /*
         * Parse the it.
         */
        rc = rtZipTarReaderParseHeader(&pThis->TarReader, &Hdr);
        if (RT_FAILURE(rc))
            return pThis->rcFatal = rc;
    } while (rtZipTarReaderExpectingMoreHeaders(&pThis->TarReader));

    pThis->offNextHdr = offHdr + cbHdrs;

    /*
     * Fill an object info structure from the current TAR state.
     */
    RTFSOBJINFO Info;
    rc = rtZipTarReaderGetFsObjInfo(&pThis->TarReader, &Info);
    if (RT_FAILURE(rc))
        return pThis->rcFatal = rc;

    /*
     * Create an object of the appropriate type.
     */
    RTVFSOBJTYPE    enmType;
    RTVFSOBJ        hVfsObj;
    RTFMODE         fType = Info.Attr.fMode & RTFS_TYPE_MASK;
    if (rtZipTarReaderIsHardlink(&pThis->TarReader))
        fType = RTFS_TYPE_SYMLINK;
    switch (fType)
    {
        /*
         * Files are represented by a VFS I/O stream.
         */
        case RTFS_TYPE_FILE:
        {
            RTVFSIOSTREAM       hVfsIos;
            PRTZIPTARIOSTREAM   pIosData;
            rc = RTVfsNewIoStream(&g_rtZipTarFssIosOps,
                                  sizeof(*pIosData),
                                  RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
                                  NIL_RTVFS,
                                  NIL_RTVFSLOCK,
                                  &hVfsIos,
                                  (void **)&pIosData);
            if (RT_FAILURE(rc))
                return pThis->rcFatal = rc;

            pIosData->BaseObj.offHdr    = offHdr;
            pIosData->BaseObj.pTarReader= &pThis->TarReader;
            pIosData->BaseObj.ObjInfo   = Info;
            pIosData->cbFile            = Info.cbObject;
            pIosData->offFile           = 0;
            pIosData->cbPadding         = (uint32_t)(Info.cbAllocated - Info.cbObject);
            pIosData->fEndOfStream      = false;
            pIosData->hVfsIos           = pThis->hVfsIos;
            RTVfsIoStrmRetain(pThis->hVfsIos);

            pThis->pCurIosData = pIosData;
            pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;

            enmType = RTVFSOBJTYPE_IO_STREAM;
            hVfsObj = RTVfsObjFromIoStream(hVfsIos);
            RTVfsIoStrmRelease(hVfsIos);
            break;
        }

        /*
         * We represent hard links using a symbolic link object.  This fits
         * best with the way TAR stores it and there is currently no better
         * fitting VFS type alternative.
         */
        case RTFS_TYPE_SYMLINK:
        {
            RTVFSSYMLINK        hVfsSym;
            PRTZIPTARBASEOBJ    pBaseObjData;
            rc = RTVfsNewSymlink(&g_rtZipTarFssSymOps,
                                 sizeof(*pBaseObjData),
                                 NIL_RTVFS,
                                 NIL_RTVFSLOCK,
                                 &hVfsSym,
                                 (void **)&pBaseObjData);
            if (RT_FAILURE(rc))
                return pThis->rcFatal = rc;

            pBaseObjData->offHdr    = offHdr;
            pBaseObjData->pTarReader= &pThis->TarReader;
            pBaseObjData->ObjInfo   = Info;

            enmType = RTVFSOBJTYPE_SYMLINK;
            hVfsObj = RTVfsObjFromSymlink(hVfsSym);
            RTVfsSymlinkRelease(hVfsSym);
            break;
        }

        /*
         * All other objects are repesented using a VFS base object since they
         * carry no data streams (unless some TAR extension implements extended
         * attributes / alternative streams).
         */
        case RTFS_TYPE_DEV_BLOCK:
        case RTFS_TYPE_DEV_CHAR:
        case RTFS_TYPE_DIRECTORY:
        case RTFS_TYPE_FIFO:
        {
            PRTZIPTARBASEOBJ pBaseObjData;
            rc = RTVfsNewBaseObj(&g_rtZipTarFssBaseObjOps,
                                 sizeof(*pBaseObjData),
                                 NIL_RTVFS,
                                 NIL_RTVFSLOCK,
                                 &hVfsObj,
                                 (void **)&pBaseObjData);
            if (RT_FAILURE(rc))
                return pThis->rcFatal = rc;

            pBaseObjData->offHdr    = offHdr;
            pBaseObjData->pTarReader= &pThis->TarReader;
            pBaseObjData->ObjInfo   = Info;

            enmType = RTVFSOBJTYPE_BASE;
            break;
        }

        default:
            AssertFailed();
            return pThis->rcFatal = VERR_INTERNAL_ERROR_5;
    }
    pThis->hVfsCurObj = hVfsObj;

    /*
     * Set the return data and we're done.
     */
    if (ppszName)
    {
        rc = RTStrDupEx(ppszName, pThis->TarReader.szName);
        if (RT_FAILURE(rc))
            return rc;
    }

    if (phVfsObj)
    {
        RTVfsObjRetain(hVfsObj);
        *phVfsObj = hVfsObj;
    }

    if (penmType)
        *penmType = enmType;

    return VINF_SUCCESS;
}
/**
 * Provide information about active users.
 */
static int vboxserviceVMInfoWriteUsers(void)
{
    int rc = VINF_SUCCESS;
    char *pszUserList = NULL;
    uint32_t cUsersInList = 0;

#ifdef RT_OS_WINDOWS
# ifndef TARGET_NT4
    rc = VBoxServiceVMInfoWinWriteUsers(&pszUserList, &cUsersInList);
# else
    rc = VERR_NOT_IMPLEMENTED;
# endif

#elif defined(RT_OS_FREEBSD)
    /** @todo FreeBSD: Port logged on user info retrieval.
     *                 However, FreeBSD 9 supports utmpx, so we could use the code
     *                 block below (?). */
    rc = VERR_NOT_IMPLEMENTED;

#elif defined(RT_OS_OS2)
    /** @todo OS/2: Port logged on (LAN/local/whatever) user info retrieval. */
    rc = VERR_NOT_IMPLEMENTED;

#else
    setutxent();
    utmpx *ut_user;
    uint32_t cListSize = 32;

    /* Allocate a first array to hold 32 users max. */
    char **papszUsers = (char **)RTMemAllocZ(cListSize * sizeof(char *));
    if (papszUsers == NULL)
        rc = VERR_NO_MEMORY;

    /* Process all entries in the utmp file. */
    while (   (ut_user = getutxent())
           && RT_SUCCESS(rc))
    {
        VBoxServiceVerbose(4, "Found logged in user \"%s\"\n",
                           ut_user->ut_user);
        if (cUsersInList > cListSize)
        {
            cListSize += 32;
            void *pvNew = RTMemRealloc(papszUsers, cListSize * sizeof(char*));
            AssertPtrBreakStmt(pvNew, cListSize -= 32);
            papszUsers = (char **)pvNew;
        }

        /* Make sure we don't add user names which are not
         * part of type USER_PROCESS. */
        if (ut_user->ut_type == USER_PROCESS)
        {
            bool fFound = false;
            for (uint32_t i = 0; i < cUsersInList && !fFound; i++)
                fFound = strcmp(papszUsers[i], ut_user->ut_user) == 0;

            if (!fFound)
            {
                rc = RTStrDupEx(&papszUsers[cUsersInList], (const char *)ut_user->ut_user);
                if (RT_FAILURE(rc))
                    break;
                cUsersInList++;
            }
        }
    }

    /* Calc the string length. */
    size_t cchUserList = 0;
    for (uint32_t i = 0; i < cUsersInList; i++)
        cchUserList += (i != 0) + strlen(papszUsers[i]);

    /* Build the user list. */
    rc = RTStrAllocEx(&pszUserList, cchUserList + 1);
    if (RT_SUCCESS(rc))
    {
        char *psz = pszUserList;
        for (uint32_t i = 0; i < cUsersInList; i++)
        {
            if (i != 0)
                *psz++ = ',';
            size_t cch = strlen(papszUsers[i]);
            memcpy(psz, papszUsers[i], cch);
            psz += cch;
        }
        *psz = '\0';
    }

    /* Cleanup. */
    for (uint32_t i = 0; i < cUsersInList; i++)
        RTStrFree(papszUsers[i]);
    RTMemFree(papszUsers);

    endutxent(); /* Close utmpx file. */
#endif
    Assert(RT_FAILURE(rc) || cUsersInList == 0 || (pszUserList && *pszUserList));

    /* If the user enumeration above failed, reset the user count to 0 except
     * we didn't have enough memory anymore. In that case we want to preserve
     * the previous user count in order to not confuse third party tools which
     * rely on that count. */
    if (RT_FAILURE(rc))
    {
        if (rc == VERR_NO_MEMORY)
        {
            static int s_iVMInfoBitchedOOM = 0;
            if (s_iVMInfoBitchedOOM++ < 3)
                VBoxServiceVerbose(0, "Warning: Not enough memory available to enumerate users! Keeping old value (%u)\n",
                                   g_cVMInfoLoggedInUsers);
            cUsersInList = g_cVMInfoLoggedInUsers;
        }
        else
            cUsersInList = 0;
    }

    VBoxServiceVerbose(4, "cUsersInList: %u, pszUserList: %s, rc=%Rrc\n",
                       cUsersInList, pszUserList ? pszUserList : "<NULL>", rc);

    if (pszUserList && cUsersInList > 0)
        VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", "%s", pszUserList);
    else
        VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL);
    VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%u", cUsersInList);
    if (g_cVMInfoLoggedInUsers != cUsersInList)
    {
        VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers",
                                   cUsersInList == 0 ? "true" : "false");
        g_cVMInfoLoggedInUsers = cUsersInList;
    }
    if (RT_SUCCESS(rc) && pszUserList)
        RTStrFree(pszUserList);
    return rc;
}
Esempio n. 15
0
/**
 * Queries the value of an SVN property.
 *
 * This will automatically adjust for scheduled changes.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_STATE if not a SVN WC file.
 * @retval  VERR_NOT_FOUND if the property wasn't found.
 * @param   pState              The rewrite state to work on.
 * @param   pszName             The property name.
 * @param   ppszValue           Where to return the property value.  Free this
 *                              using RTStrFree.  Optional.
 */
int ScmSvnQueryProperty(PSCMRWSTATE pState, const char *pszName, char **ppszValue)
{
    /*
     * Look it up in the scheduled changes.
     */
    size_t i = pState->cSvnPropChanges;
    while (i-- > 0)
        if (!strcmp(pState->paSvnPropChanges[i].pszName, pszName))
        {
            const char *pszValue = pState->paSvnPropChanges[i].pszValue;
            if (!pszValue)
                return VERR_NOT_FOUND;
            if (ppszValue)
                return RTStrDupEx(ppszValue, pszValue);
            return VINF_SUCCESS;
        }

#ifdef SCM_WITHOUT_LIBSVN
    int rc;
    scmSvnFindSvnBinary(pState);
    if (g_enmSvnVersion < kScmSvnVersion_1_7)
    {
        /*
         * Hack: Read the .svn/props/<file>.svn-work file exists.
         */
        char szPath[RTPATH_MAX];
        rc = scmSvnConstructName(pState, ".svn/props/", ".svn-work", szPath);
        if (RT_SUCCESS(rc) && !RTFileExists(szPath))
            rc = scmSvnConstructName(pState, ".svn/prop-base/", ".svn-base", szPath);
        if (RT_SUCCESS(rc))
        {
            SCMSTREAM Stream;
            rc = ScmStreamInitForReading(&Stream, szPath);
            if (RT_SUCCESS(rc))
            {
                /*
                 * The current format is K len\n<name>\nV len\n<value>\n" ... END.
                 */
                rc = VERR_NOT_FOUND;
                size_t const    cchName = strlen(pszName);
                SCMEOL          enmEol;
                size_t          cchLine;
                const char     *pchLine;
                while ((pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol)) != NULL)
                {
                    /*
                     * Parse the 'K num' / 'END' line.
                     */
                    if (   cchLine == 3
                        && !memcmp(pchLine, "END", 3))
                        break;
                    size_t cchKey;
                    if (   cchLine < 3
                        || pchLine[0] != 'K'
                        || pchLine[1] != ' '
                        || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchKey)
                        || cchKey == 0
                        || cchKey > 4096)
                    {
                        RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
                        rc = VERR_PARSE_ERROR;
                        break;
                    }

                    /*
                     * Match the key and skip to the value line.  Don't bother with
                     * names containing EOL markers.
                     */
                    size_t const offKey = ScmStreamTell(&Stream);
                    bool fMatch = cchName == cchKey;
                    if (fMatch)
                    {
                        pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol);
                        if (!pchLine)
                            break;
                        fMatch = cchLine == cchName
                              && !memcmp(pchLine, pszName, cchName);
                    }

                    if (RT_FAILURE(ScmStreamSeekAbsolute(&Stream, offKey + cchKey)))
                        break;
                    if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1)))
                        break;

                    /*
                     * Read and Parse the 'V num' line.
                     */
                    pchLine = ScmStreamGetLine(&Stream, &cchLine, &enmEol);
                    if (!pchLine)
                        break;
                    size_t cchValue;
                    if (   cchLine < 3
                        || pchLine[0] != 'V'
                        || pchLine[1] != ' '
                        || !scmSvnReadNumber(&pchLine[2], cchLine - 2, &cchValue)
                        || cchValue > _1M)
                    {
                        RTMsgError("%s:%u: Unexpected data '%.*s'\n", szPath, ScmStreamTellLine(&Stream), cchLine, pchLine);
                        rc = VERR_PARSE_ERROR;
                        break;
                    }

                    /*
                     * If we have a match, allocate a return buffer and read the
                     * value into it.  Otherwise skip this value and continue
                     * searching.
                     */
                    if (fMatch)
                    {
                        if (!ppszValue)
                            rc = VINF_SUCCESS;
                        else
                        {
                            char *pszValue;
                            rc = RTStrAllocEx(&pszValue, cchValue + 1);
                            if (RT_SUCCESS(rc))
                            {
                                rc = ScmStreamRead(&Stream, pszValue, cchValue);
                                if (RT_SUCCESS(rc))
                                    *ppszValue = pszValue;
                                else
                                    RTStrFree(pszValue);
                            }
                        }
                        break;
                    }

                    if (RT_FAILURE(ScmStreamSeekRelative(&Stream, cchValue)))
                        break;
                    if (RT_FAILURE(ScmStreamSeekByLine(&Stream, ScmStreamTellLine(&Stream) + 1)))
                        break;
                }

                if (RT_FAILURE(ScmStreamGetStatus(&Stream)))
                {
                    rc = ScmStreamGetStatus(&Stream);
                    RTMsgError("%s: stream error %Rrc\n", szPath, rc);
                }
                ScmStreamDelete(&Stream);
            }
        }

        if (rc == VERR_FILE_NOT_FOUND)
            rc = VERR_NOT_FOUND;
    }
    else
    {
        const char *apszArgs[] = { g_szSvnPath, "propget", "--strict", pszName, pState->pszFilename, NULL };
        char       *pszValue;
        rc = scmSvnRunAndGetOutput(pState, apszArgs, false, &pszValue);
        if (RT_SUCCESS(rc))
        {
            if (pszValue && *pszValue)
            {
                if (ppszValue)
                {
                    *ppszValue = pszValue;
                    pszValue = NULL;
                }
            }
            else
                rc = VERR_NOT_FOUND;
            RTStrFree(pszValue);
        }
    }
    return rc;

#else
    NOREF(pState);
#endif
    return VERR_NOT_FOUND;
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceAutoMountWorker(bool volatile *pfShutdown)
{
    /*
     * Tell the control thread that it can continue
     * spawning services.
     */
    RTThreadUserSignal(RTThreadSelf());

    uint32_t cMappings;
    PVBGLR3SHAREDFOLDERMAPPING paMappings;
    int rc = VbglR3SharedFolderGetMappings(g_SharedFoldersSvcClientID, true /* Only process auto-mounted folders */,
                                           &paMappings, &cMappings);
    if (   RT_SUCCESS(rc)
        && cMappings)
    {
        char *pszMountDir;
        rc = VbglR3SharedFolderGetMountDir(&pszMountDir);
        if (rc == VERR_NOT_FOUND)
            rc = RTStrDupEx(&pszMountDir, VBOXSERVICE_AUTOMOUNT_DEFAULT_DIR);
        if (RT_SUCCESS(rc))
        {
            VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount dir set to \"%s\"\n", pszMountDir);

            char *pszSharePrefix;
            rc = VbglR3SharedFolderGetMountPrefix(&pszSharePrefix);
            if (RT_SUCCESS(rc))
            {
                VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Shared folder mount prefix set to \"%s\"\n", pszSharePrefix);
#ifdef USE_VIRTUAL_SHARES
                /* Check for a fixed/virtual auto-mount share. */
                if (VbglR3SharedFolderExists(g_SharedFoldersSvcClientID, "vbsfAutoMount"))
                {
                    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Host supports auto-mount root\n");
                }
                else
                {
#endif
                    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Got %u shared folder mappings\n", cMappings);
                    rc = VBoxServiceAutoMountProcessMappings(paMappings, cMappings, pszMountDir, pszSharePrefix, g_SharedFoldersSvcClientID);
#ifdef USE_VIRTUAL_SHARES
                }
#endif
                RTStrFree(pszSharePrefix);
            } /* Mount share prefix. */
            else
                VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mount prefix, rc = %Rrc\n", rc);
            RTStrFree(pszMountDir);
        }
        else
            VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder directory, rc = %Rrc\n", rc);
        VbglR3SharedFolderFreeMappings(paMappings);
    }
    else if (RT_FAILURE(rc))
        VBoxServiceError("VBoxServiceAutoMountWorker: Error while getting the shared folder mappings, rc = %Rrc\n", rc);
    else
        VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: No shared folder mappings found\n");

    /*
     * Because this thread is a one-timer at the moment we don't want to break/change
     * the semantics of the main thread's start/stop sub-threads handling.
     *
     * This thread exits so fast while doing its own startup in VBoxServiceStartServices()
     * that this->fShutdown flag is set to true in VBoxServiceThread() before we have the
     * chance to check for a service failure in VBoxServiceStartServices() to indicate
     * a VBoxService startup error.
     *
     * Therefore *no* service threads are allowed to quit themselves and need to wait
     * for the pfShutdown flag to be set by the main thread.
     */
    for (;;)
    {
        /* Do we need to shutdown? */
        if (*pfShutdown)
            break;

        /* Let's sleep for a bit and let others run ... */
        RTThreadSleep(500);
    }

    RTSemEventMultiDestroy(g_AutoMountEvent);
    g_AutoMountEvent = NIL_RTSEMEVENTMULTI;

    VBoxServiceVerbose(3, "VBoxServiceAutoMountWorker: Finished with rc=%Rrc\n", rc);
    return VINF_SUCCESS;
}