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