Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
        }
    }