diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2017-03-14 14:02:22 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2017-03-14 14:02:22 +0000 |
commit | cde9c1692e1f439258dc769597e6413641f622cc (patch) | |
tree | f22f09c74ffda6bb3bd03075c28c3a154d2fda80 /src/VBox/HostServices | |
parent | 5f59d0893905a3146843a995a3331706914d4974 (diff) | |
download | VirtualBox-svn-cde9c1692e1f439258dc769597e6413641f622cc.tar.gz |
SharedFolders: helper function for Windows extended-length paths.
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@66090 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/HostServices')
-rw-r--r-- | src/VBox/HostServices/SharedFolders/vbsfpathabs.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedFolders/vbsfpathabs.cpp b/src/VBox/HostServices/SharedFolders/vbsfpathabs.cpp new file mode 100644 index 00000000000..cb7fa72cafc --- /dev/null +++ b/src/VBox/HostServices/SharedFolders/vbsfpathabs.cpp @@ -0,0 +1,178 @@ +/* $Id$ */ +/** @file + * Shared Folders - guest/host path convertion and verification. + */ + +/* + * Copyright (C) 2017 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <iprt/path.h> +#include <iprt/string.h> + +#if defined(RT_OS_WINDOWS) +static void vbsfPathResolveRelative(char *pszPathBegin) +{ + char *pszCur = pszPathBegin; + char * const pszTop = pszCur; + + /* + * Get rid of double dot path components by evaluating them. + */ + for (;;) + { + char const chFirst = pszCur[0]; + if ( chFirst == '.' + && pszCur[1] == '.' + && (!pszCur[2] || pszCur[2] == RTPATH_SLASH)) + { + /* rewind to the previous component if any */ + char *pszPrev = pszCur; + if ((uintptr_t)pszPrev > (uintptr_t)pszTop) + { + pszPrev--; + while ( (uintptr_t)pszPrev > (uintptr_t)pszTop + && pszPrev[-1] != RTPATH_SLASH) + pszPrev--; + } + if (!pszCur[2]) + { + if (pszPrev != pszTop) + pszPrev[-1] = '\0'; + else + *pszPrev = '\0'; + break; + } + Assert(pszPrev[-1] == RTPATH_SLASH); + memmove(pszPrev, pszCur + 3, strlen(pszCur + 3) + 1); + pszCur = pszPrev - 1; + } + else if ( chFirst == '.' + && (!pszCur[1] || pszCur[1] == RTPATH_SLASH)) + { + /* remove unnecessary '.' */ + if (!pszCur[1]) + { + if (pszCur != pszTop) + pszCur[-1] = '\0'; + else + *pszCur = '\0'; + break; + } + memmove(pszCur, pszCur + 2, strlen(pszCur + 2) + 1); + continue; + } + else + { + /* advance to end of component. */ + while (*pszCur && *pszCur != RTPATH_SLASH) + pszCur++; + } + + if (!*pszCur) + break; + + /* skip the slash */ + ++pszCur; + } +} +#endif /* RT_OS_WINDOWS */ + +int vbsfPathAbs(const char *pszRoot, const char *pszPath, char *pszAbsPath, size_t cbAbsPath) +{ +#if defined(RT_OS_WINDOWS) + const char *pszPathStart = pszRoot? pszRoot: pszPath; + + /* Windows extended-length paths. */ + if ( RTPATH_IS_SLASH(pszPathStart[0]) + && RTPATH_IS_SLASH(pszPathStart[1]) + && pszPathStart[2] == '?' + && RTPATH_IS_SLASH(pszPathStart[3]) + ) + { + /* Maximum total path length of 32,767 characters. */ + if (cbAbsPath > _32K) + cbAbsPath = _32K; + + /* Copy the root to pszAbsPath buffer. */ + size_t cchRoot = pszRoot? strlen(pszRoot): 0; + if (cchRoot >= cbAbsPath) + return VERR_FILENAME_TOO_LONG; + + if (pszRoot) + { + /* Caller must ensure that the path is relative, without the leading path separator. */ + if (RTPATH_IS_SLASH(pszPath[0])) + return VERR_INVALID_PARAMETER; + + if (cchRoot) + memcpy(pszAbsPath, pszRoot, cchRoot); + + if (cchRoot == 0 || !RTPATH_IS_SLASH(pszAbsPath[cchRoot - 1])) + { + /* Append path separator after the root. */ + ++cchRoot; + if (cchRoot >= cbAbsPath) + return VERR_FILENAME_TOO_LONG; + + pszAbsPath[cchRoot - 1] = RTPATH_SLASH; + } + } + + /* Append the path to the pszAbsPath buffer. */ + const size_t cchPath = strlen(pszPath); + if (cchRoot + cchPath >= cbAbsPath) + return VERR_FILENAME_TOO_LONG; + + memcpy(&pszAbsPath[cchRoot], pszPath, cchPath + 1); /* Including trailing 0. */ + + /* Find out where the actual path begins, i.e. skip the root spec. */ + char *pszPathBegin = &pszAbsPath[4]; /* Skip the extended-length path prefix "\\?\" */ + if ( pszPathBegin[0] + && RTPATH_IS_VOLSEP(pszPathBegin[1]) + && pszPathBegin[2] == RTPATH_SLASH) + { + /* "\\?\C:\" */ + pszPathBegin += 3; + } + else if ( pszPathBegin[0] == 'U' + && pszPathBegin[1] == 'N' + && pszPathBegin[2] == 'C' + && pszPathBegin[3] == RTPATH_SLASH) + { + /* "\\?\UNC\server\share" */ + pszPathBegin += 4; + + /* Skip "server\share" too. */ + while (*pszPathBegin != RTPATH_SLASH && *pszPathBegin) + ++pszPathBegin; + if (*pszPathBegin == RTPATH_SLASH) + { + ++pszPathBegin; + while (*pszPathBegin != RTPATH_SLASH && *pszPathBegin) + ++pszPathBegin; + if (*pszPathBegin == RTPATH_SLASH) + ++pszPathBegin; + } + } + else + return VERR_INVALID_NAME; + + /* Process pszAbsPath in place. */ + vbsfPathResolveRelative(pszPathBegin); + + return VINF_SUCCESS; + } +#endif /* RT_OS_WINDOWS */ + + /* Fallback for the common paths. */ + return RTPathAbsEx(pszRoot, pszPath, pszAbsPath, cbAbsPath); +} |