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; }
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; } }