Example #1
0
static char *rtPathSkipRootSpec(char *pszCur)
{
#ifdef HAVE_DRIVE
    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == RTPATH_SLASH)
        pszCur += 3;
# ifdef HAVE_UNC
    else if (pszCur[0] == RTPATH_SLASH && pszCur[1] == RTPATH_SLASH)
    {
        pszCur += 2;
        while (*pszCur == RTPATH_SLASH)
            pszCur++;
        if (*pszCur)
        {
            while (*pszCur != RTPATH_SLASH && *pszCur)
                pszCur++;
            if (*pszCur == RTPATH_SLASH)
            {
                pszCur++;
                while (*pszCur != RTPATH_SLASH && *pszCur)
                    pszCur++;
                if (*pszCur == RTPATH_SLASH)
                    pszCur++;
            }
        }
    }
# endif
#else
    if (pszCur[0] == RTPATH_SLASH)
        pszCur += 1;
#endif
    return pszCur;
}
Example #2
0
/**
 * Cleans up a path specifier a little bit.
 * This includes removing duplicate slashes, unnecessary single dots, and
 * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
 *
 * @returns Number of bytes in the clean path.
 * @param   pszPath     The path to cleanup.
 */
static int fsCleanPath(char *pszPath)
{
    /*
     * Change to '/' and remove duplicates.
     */
    char   *pszSrc = pszPath;
    char   *pszTrg = pszPath;
#ifdef HAVE_UNC
    int     fUnc = 0;
    if (    RTPATH_IS_SLASH(pszPath[0])
        &&  RTPATH_IS_SLASH(pszPath[1]))
    {   /* Skip first slash in a unc path. */
        pszSrc++;
        *pszTrg++ = '/';
        fUnc = 1;
    }
#endif

    for (;;)
    {
        char ch = *pszSrc++;
        if (RTPATH_IS_SLASH(ch))
        {
            *pszTrg++ = '/';
            for (;;)
            {
                do  ch = *pszSrc++;
                while (RTPATH_IS_SLASH(ch));

                /* Remove '/./' and '/.'. */
                if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
                    break;
            }
        }
        *pszTrg = ch;
        if (!ch)
            break;
        pszTrg++;
    }

    /*
     * Remove trailing slash if the path may be pointing to a directory.
     */
    int cch = pszTrg - pszPath;
    if (    cch > 1
        &&  RTPATH_IS_SLASH(pszTrg[-1])
#ifdef HAVE_DRIVE
        &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
#endif
        &&  !RTPATH_IS_SLASH(pszTrg[-2]))
        pszPath[--cch] = '\0';

    return cch;
}
/**
 * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
 *
 * @returns iprt status code.
 * @param   pszPath         The path to resolve.
 * @param   pszAbsPath      Where to store the absolute path.
 * @param   cchAbsPath      Size of the buffer.
 */
RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
{
    /*
     * Validation.
     */
    AssertPtr(pszAbsPath);
    AssertPtr(pszPath);
    if (RT_UNLIKELY(!*pszPath))
        return VERR_INVALID_PARAMETER;

    /*
     * Convert to UTF-16, call Win32 API, convert back.
     */
    LPWSTR pwszPath;
    int rc = RTStrToUtf16(pszPath, &pwszPath);
    if (!RT_SUCCESS(rc))
        return (rc);

    LPWSTR pwszFile; /* Ignored */
    RTUTF16 wsz[RTPATH_MAX];
    rc = GetFullPathNameW(pwszPath, RT_ELEMENTS(wsz), &wsz[0], &pwszFile);
    if (rc > 0 && rc < RT_ELEMENTS(wsz))
    {
        size_t cch;
        rc = RTUtf16ToUtf8Ex(&wsz[0], RTSTR_MAX, &pszAbsPath, cchAbsPath, &cch);
        if (RT_SUCCESS(rc))
        {
# if 1 /** @todo This code is completely bonkers. */
            /*
             * Remove trailing slash if the path may be pointing to a directory.
             * (See posix variant.)
             */
            if (    cch > 1
                &&  RTPATH_IS_SLASH(pszAbsPath[cch - 1])
                &&  !RTPATH_IS_VOLSEP(pszAbsPath[cch - 2])
                &&  !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
                pszAbsPath[cch - 1] = '\0';
# endif
        }
    }
    else if (rc <= 0)
        rc = RTErrConvertFromWin32(GetLastError());
    else
        rc = VERR_FILENAME_TOO_LONG;

    RTUtf16Free(pwszPath);
    return rc;
}
RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
{
#ifdef HAVE_DRIVE
    /*
     * Check if it's the same drive as the current directory.
     */
    int rc = RTPathGetCurrent(pszPath, cbPath);
    if (RT_SUCCESS(rc))
    {
        if (   (   chDrive == *pszPath
                   || RT_C_TO_LOWER(chDrive) == RT_C_TO_LOWER(*pszPath))
                && RTPATH_IS_VOLSEP(pszPath[1]))
            return rc;

        /*
         * Different drive, indicate root.
         */
        if (cbPath >= 4)
        {
            pszPath[0] = RT_C_TO_UPPER(chDrive);
            pszPath[1] = ':';
            pszPath[2] = RTPATH_SLASH;
            pszPath[3] = '\0';
            return VINF_SUCCESS;
        }
    }
    return rc;

#else
    /*
     * No driver letters, just return root slash on whatever we're asked.
     */
    NOREF(chDrive);
    if (cbPath >= 2)
    {
        pszPath[0] = RTPATH_SLASH;
        pszPath[1] = '\0';
        return VINF_SUCCESS;
    }
    return VERR_BUFFER_OVERFLOW;
#endif
}
Example #5
0
RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
{
    int rc;

    /*
     * Validation.
     */
    AssertPtr(pszAbsPath);
    AssertPtr(pszPath);
    if (RT_UNLIKELY(!*pszPath))
        return VERR_INVALID_PARAMETER;

    /*
     * Make a clean working copy of the input.
     */
    size_t cchPath = strlen(pszPath);
    if (cchPath > PATH_MAX)
    {
        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
        return VERR_FILENAME_TOO_LONG;
    }

    char szTmpPath[PATH_MAX + 1];
    memcpy(szTmpPath, pszPath, cchPath + 1);
    size_t cchTmpPath = fsCleanPath(szTmpPath);

    /*
     * Handle "." specially (fsCleanPath does).
     */
    if (szTmpPath[0] == '.' && !szTmpPath[1])
        return RTPathGetCurrent(pszAbsPath, cchAbsPath);

    /*
     * Do we have a root slash?
     */
    char *pszCur = szTmpPath;
#ifdef HAVE_DRIVE
    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
        pszCur += 3;
# ifdef HAVE_UNC
    else if (pszCur[0] == '/' && pszCur[1] == '/')
        pszCur += 2;
# endif
#else  /* !HAVE_DRIVE */
    if (pszCur[0] == '/')
        pszCur += 1;
#endif /* !HAVE_DRIVE */
    else
    {
        /*
         * No, prepend the current directory to the relative path.
         */
        char szCurDir[RTPATH_MAX];
        rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
        AssertRCReturn(rc, rc);

        size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
        if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
        {
            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
            return VERR_FILENAME_TOO_LONG;
        }

        memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
        memcpy(szTmpPath, szCurDir, cchCurDir);
        szTmpPath[cchCurDir] = '/';


#ifdef HAVE_DRIVE
        if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
            pszCur += 3;
# ifdef HAVE_UNC
        else if (pszCur[0] == '/' && pszCur[1] == '/')
            pszCur += 2;
# endif
#else
        if (pszCur[0] == '/')
            pszCur += 1;
#endif
        else
            AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
    }

    char *pszTop = pszCur;

    /*
     * Get rid of double dot path components by evaluating them.
     */
    for (;;)
    {
        if (   pszCur[0] == '.'
            && pszCur[1] == '.'
            && (!pszCur[2] || pszCur[2] == '/'))
        {
            /* rewind to the previous component if any */
            char *pszPrev = pszCur - 1;
            if (pszPrev > pszTop)
                while (*--pszPrev != '/')
                    ;

            AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
            memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);

            pszCur = pszPrev;
        }
        else
        {
            /* advance to end of component. */
            while (*pszCur && *pszCur != '/')
                pszCur++;
        }

        if (!*pszCur)
            break;

        /* skip the slash */
        ++pszCur;
    }

    if (pszCur < pszTop)
    {
        /*
         * We overwrote the root slash with '\0', restore it.
         */
        *pszCur++ = '/';
        *pszCur = '\0';
    }
    else if (pszCur > pszTop && pszCur[-1] == '/')
    {
        /*
         * Extra trailing slash in a non-root path, remove it.
         * (A bit questionable...)
         */
        *--pszCur = '\0';
    }

    /*
     * Copy the result to the user buffer.
     */
    cchTmpPath = pszCur - szTmpPath;
    if (cchTmpPath < cchAbsPath)
    {
        memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
        rc = VINF_SUCCESS;
    }
    else
        rc = VERR_BUFFER_OVERFLOW;

    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
    return rc;
}
Example #6
0
RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
{
    int rc;

    /*
     * Validation.
     */
    AssertPtr(pszAbsPath);
    AssertPtr(pszPath);
    if (RT_UNLIKELY(!*pszPath))
        return VERR_INVALID_PARAMETER; //VERR_INVALID_NAME;

    /*
     * Make a clean working copy of the input.
     */
    size_t cchPath = strlen(pszPath);
    if (cchPath >= RTPATH_MAX)
    {
        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
        return VERR_FILENAME_TOO_LONG;
    }

    char szTmpPath[RTPATH_MAX];
    memcpy(szTmpPath, pszPath, cchPath + 1);
    size_t cchTmpPath = fsCleanPath(szTmpPath);

    /*
     * Handle "." specially (fsCleanPath does).
     */
    if (szTmpPath[0] == '.')
    {
        if (   cchTmpPath == 1
            || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
        {
            rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
            if (RT_SUCCESS(rc))
            {
                size_t cch = fsCleanPath(pszAbsPath);
                char  *pszTop = rtPathSkipRootSpec(pszAbsPath);
#if 1
                if ((uintptr_t)&pszAbsPath[cch] > (uintptr_t)pszTop && pszAbsPath[cch - 1] == RTPATH_SLASH)
                    pszAbsPath[cch - 1] = '\0';
#else
                if (   cchTmpPath == 2
                    && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
                {
                    if (cch + 1 < cchAbsPath)
                    {
                        pszAbsPath[cch++] = RTPATH_SLASH;
                        pszAbsPath[cch] = '\0';
                    }
                    else
                        rc = VERR_BUFFER_OVERFLOW;
                }
#endif
            }
            return rc;
        }
    }

    /*
     * Do we have an incomplete root spec?  Supply the missing bits.
     */
#ifdef HAVE_DRIVE
    if (   !(szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] == RTPATH_SLASH)
# ifdef HAVE_UNC
        && !(szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] == RTPATH_SLASH)
# endif
        )
#else
    if (szTmpPath[0] != RTPATH_SLASH)
#endif
    {
        char    szCurDir[RTPATH_MAX];
        size_t  cchCurDir;
        int     offApplyAt;
        bool    fNeedSlash;
#ifdef HAVE_DRIVE
        if (szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] != RTPATH_SLASH)
        {
            /*
             * Relative to drive specific current directory.
             */
            rc = RTPathGetCurrentOnDrive(szTmpPath[0], szCurDir, sizeof(szCurDir));
            fNeedSlash = true;
            offApplyAt = 2;
        }
# ifdef HAVE_UNC
        else if (szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] != RTPATH_SLASH)
# else
        else if (szTmpPath[0] == RTPATH_SLASH)
# endif
        {
            /*
             * Root of current drive.  This may return a UNC root if we're not
             * standing on a drive but on a UNC share.
             */
            rc = RTPathGetCurrentDrive(szCurDir, sizeof(szCurDir));
            fNeedSlash = false;
            offApplyAt = 0;
        }
        else
#endif
        {
            /*
             * Relative to current directory.
             */
            rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
            fNeedSlash = true;
            offApplyAt = 0;
        }
        if (RT_SUCCESS(rc))
        {
            cchCurDir = fsCleanPath(szCurDir);
            if (fNeedSlash && cchCurDir > 0 && szCurDir[cchCurDir - 1] == RTPATH_SLASH)
                fNeedSlash = false;

            if (cchCurDir + fNeedSlash + cchTmpPath - offApplyAt <= RTPATH_MAX)
            {
                memmove(szTmpPath + cchCurDir + fNeedSlash, szTmpPath + offApplyAt, cchTmpPath + 1 - offApplyAt);
                memcpy(szTmpPath, szCurDir, cchCurDir);
                if (fNeedSlash)
                    szTmpPath[cchCurDir] = RTPATH_SLASH;
            }
            else
                rc = VERR_FILENAME_TOO_LONG;
        }
        if (RT_FAILURE(rc))
        {
            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
            return rc;
        }
    }
RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath)
{
#ifdef HAVE_DRIVE
    /*
     * Query the current directroy and extract the wanted information from it.
     */
    int rc = RTPathGetCurrent(pszPath, cbPath);
    if (RT_SUCCESS(rc))
    {
        /*
         * Drive letter? Chop off at root slash.
         */
        if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
        {
            pszPath[2] = '\0';
            return rc;
        }

        /*
         * UNC? Chop off after share.
         */
        if (   RTPATH_IS_SLASH(pszPath[0])
            && RTPATH_IS_SLASH(pszPath[1])
            && !RTPATH_IS_SLASH(pszPath[2])
            && pszPath[2])
        {
            /* Work thru the server name. */
            size_t off = 3;
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
            size_t offServerSlash = off;

            /* Is there a share name? */
            if (RTPATH_IS_SLASH(pszPath[off]))
            {
                while (RTPATH_IS_SLASH(pszPath[off]))
                    off++;
                if (pszPath[off])
                {
                    /* Work thru the share name. */
                    while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                        off++;
                }
                /* No share name, chop at server name. */
                else
                    off = offServerSlash;
            }
        }
        return VERR_INTERNAL_ERROR_4;
    }
    return rc;

#else  /* !HAVE_DRIVE */
    /*
     * No drive letters on this system, return empty string.
     */
    if (cbPath > 0)
    {
        *pszPath = '\0';
        return VINF_SUCCESS;
    }
    return VERR_BUFFER_OVERFLOW;
#endif /* !HAVE_DRIVE */
}
/**
 *  Shared initialization code. Called from the other constructors.
 *
 *  @note
 *      Must be called from under the object's lock!
 */
HRESULT SharedFolder::protectedInit(VirtualBoxBase *aParent,
                                    const Utf8Str &aName,
                                    const Utf8Str &aHostPath,
                                    bool aWritable,
                                    bool aAutoMount,
                                    bool fFailOnError)
{
    LogFlowThisFunc(("aName={%s}, aHostPath={%s}, aWritable={%d}, aAutoMount={%d}\n",
                      aName.c_str(), aHostPath.c_str(), aWritable, aAutoMount));

    ComAssertRet(aParent && aName.isNotEmpty() && aHostPath.isNotEmpty(), E_INVALIDARG);

    Utf8Str hostPath = aHostPath;
    size_t hostPathLen = hostPath.length();

    /* Remove the trailing slash unless it's a root directory
     * (otherwise the comparison with the RTPathAbs() result will fail at least
     * on Linux). Note that this isn't really necessary for the shared folder
     * itself, since adding a mapping eventually results into a
     * RTDirOpenFiltered() call (see HostServices/SharedFolders) that seems to
     * accept both the slashified paths and not. */
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
    if (hostPathLen > 2 &&
        RTPATH_IS_SEP (hostPath.c_str()[hostPathLen - 1]) &&
        RTPATH_IS_VOLSEP (hostPath.c_str()[hostPathLen - 2]))
        ;
#else
    if (hostPathLen == 1 && RTPATH_IS_SEP(hostPath[0]))
        ;
#endif
    else
        hostPath.stripTrailingSlash();

    if (fFailOnError)
    {
        /* Check whether the path is full (absolute) */
        char hostPathFull[RTPATH_MAX];
        int vrc = RTPathAbsEx(NULL,
                              hostPath.c_str(),
                              hostPathFull,
                              sizeof (hostPathFull));
        if (RT_FAILURE(vrc))
            return setError(E_INVALIDARG,
                            tr("Invalid shared folder path: '%s' (%Rrc)"),
                            hostPath.c_str(), vrc);

        if (RTPathCompare(hostPath.c_str(), hostPathFull) != 0)
            return setError(E_INVALIDARG,
                            tr("Shared folder path '%s' is not absolute"),
                            hostPath.c_str());
    }

    unconst(mParent) = aParent;

    unconst(m->strName) = aName;
    unconst(m->strHostPath) = hostPath;
    m->fWritable = aWritable;
    m->fAutoMount = aAutoMount;

    return S_OK;
}