/* static */ int DnDURIObject::RebaseURIPath(RTCString &strPathAbs, const RTCString &strBaseOld /* = "" */, const RTCString &strBaseNew /* = "" */) { char *pszPath = RTUriFilePath(strPathAbs.c_str()); if (!pszPath) /* No URI? */ pszPath = RTStrDup(strPathAbs.c_str()); int rc; if (pszPath) { const char *pszPathStart = pszPath; const char *pszBaseOld = strBaseOld.c_str(); if ( pszBaseOld && RTPathStartsWith(pszPath, pszBaseOld)) { pszPathStart += strlen(pszBaseOld); } rc = VINF_SUCCESS; if (RT_SUCCESS(rc)) { char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart); if (pszPathNew) { char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */, pszPathNew /* pszPath */, NULL /* pszQuery */, NULL /* pszFragment */); if (pszPathURI) { LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI)); strPathAbs = RTCString(pszPathURI) + "\r\n"; RTStrFree(pszPathURI); } else rc = VERR_INVALID_PARAMETER; RTStrFree(pszPathNew); } else rc = VERR_NO_MEMORY; } RTStrFree(pszPath); } else rc = VERR_NO_MEMORY; return rc; }
/** @todo Put this into an own class like DnDURIPath : public RTCString? */ int DnDURIObject::RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld, const RTCString &strBaseNew) { int rc; const char *pszPath = RTUriPath(strPath.c_str()); if (pszPath) { const char *pszPathStart = pszPath; const char *pszBaseOld = strBaseOld.c_str(); if ( pszBaseOld && RTPathStartsWith(pszPath, pszBaseOld)) { pszPathStart += strlen(pszBaseOld); } rc = VINF_SUCCESS; if (RT_SUCCESS(rc)) { char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart); if (pszPathNew) { char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */, pszPathNew /* pszPath */, NULL /* pszQuery */, NULL /* pszFragment */); if (pszPathURI) { #ifdef DEBUG_andy LogFlowFunc(("Rebasing \"%s\" to \"%s\"", strPath.c_str(), pszPathURI)); #endif strPath = RTCString(pszPathURI) + "\r\n"; RTStrFree(pszPathURI); rc = VINF_SUCCESS; } else rc = VERR_INVALID_PARAMETER; RTStrFree(pszPathNew); } else rc = VERR_NO_MEMORY; } } else rc = VERR_INVALID_PARAMETER; #ifdef DEBUG_andy LogFlowFuncLeaveRC(rc); #endif return rc; }
int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot, PCSHFLSTRING pGuestString, uint32_t cbGuestString, char **ppszHostPath, uint32_t *pcbHostPathRoot, uint32_t fu32Options, uint32_t *pfu32PathFlags) { #ifdef VBOX_STRICT /* * Check that the pGuestPath has correct size and encoding. */ if (ShflStringIsValidIn(pGuestString, cbGuestString, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)) == false) { LogFunc(("Invalid input string\n")); return VERR_INTERNAL_ERROR; } #else NOREF(cbGuestString); #endif /* * Resolve the root handle into a string. */ uint32_t cbRootLen = 0; const char *pszRoot = NULL; int rc = vbsfMappingsQueryHostRootEx(hRoot, &pszRoot, &cbRootLen); if (RT_FAILURE(rc)) { LogFunc(("invalid root\n")); return rc; } AssertReturn(cbRootLen > 0, VERR_INTERNAL_ERROR_2); /* vbsfMappingsQueryHostRootEx ensures this. */ /* * Get the UTF8 string with the relative path provided by the guest. * If guest uses UTF-16 then convert it to UTF-8. */ uint32_t cbGuestPath = 0; /* Shut up MSC */ const char *pchGuestPath = NULL; /* Ditto. */ char *pchGuestPathAllocated = NULL; /* Converted from UTF-16. */ if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8)) { /* UTF-8 */ cbGuestPath = pGuestString->u16Length; pchGuestPath = pGuestString->String.ach; } else { /* UTF-16 */ #ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */ uint32_t cwcSrc = 0; PRTUTF16 pwszSrc = NULL; rc = vbsfNormalizeStringDarwin(&pGuestString->String.ucs2[0], pGuestString->u16Length / sizeof(RTUTF16), &pwszSrc, &cwcSrc); #else uint32_t const cwcSrc = pGuestString->u16Length / sizeof(RTUTF16); PCRTUTF16 const pwszSrc = &pGuestString->String.ucs2[0]; #endif if (RT_SUCCESS(rc)) { size_t cbPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc); if (cbPathAsUtf8 >= cwcSrc) { /* Allocate buffer that will be able to contain the converted UTF-8 string. */ pchGuestPathAllocated = (char *)RTMemAlloc(cbPathAsUtf8 + 1); if (RT_LIKELY(pchGuestPathAllocated != NULL)) { if (RT_LIKELY(cbPathAsUtf8)) { size_t cchActual; char *pszDst = pchGuestPathAllocated; rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cbPathAsUtf8 + 1, &cchActual); AssertRC(rc); AssertStmt(RT_FAILURE(rc) || cchActual == cbPathAsUtf8, rc = VERR_INTERNAL_ERROR_4); Assert(strlen(pszDst) == cbPathAsUtf8); } if (RT_SUCCESS(rc)) { /* Terminate the string. */ pchGuestPathAllocated[cbPathAsUtf8] = '\0'; cbGuestPath = (uint32_t)cbPathAsUtf8; Assert(cbGuestPath == cbPathAsUtf8); pchGuestPath = pchGuestPathAllocated; } } else { rc = VERR_NO_MEMORY; } } else { AssertFailed(); rc = VERR_INTERNAL_ERROR_3; } #ifdef RT_OS_DARWIN RTMemFree(pwszSrc); #endif } } char *pszFullPath = NULL; if (RT_SUCCESS(rc)) { LogFlowFunc(("Root %s path %.*s\n", pszRoot, cbGuestPath, pchGuestPath)); /* * Allocate enough memory to build the host full path from the root and the relative path. */ const uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */ pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc); if (RT_LIKELY(pszFullPath != NULL)) { /* Buffer for the verified guest path. */ char *pchVerifiedPath = (char *)RTMemAlloc(cbGuestPath + 1); if (RT_LIKELY(pchVerifiedPath != NULL)) { /* Init the pointer for the guest relative path. */ uint32_t cbSrc = cbGuestPath; const char *pchSrc = pchGuestPath; /* Strip leading delimiters from the path the guest specified. */ while ( cbSrc > 0 && *pchSrc == pClient->PathDelimiter) { ++pchSrc; --cbSrc; } /* * Iterate the guest path components, verify each of them replacing delimiters with the host slash. */ char *pchDst = pchVerifiedPath; bool fLastComponentHasWildcard = false; for (; cbSrc > 0; --cbSrc, ++pchSrc) { if (RT_LIKELY(*pchSrc != pClient->PathDelimiter)) { if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc))) { if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc)) { fLastComponentHasWildcard = true; } *pchDst++ = *pchSrc; } else { rc = VERR_INVALID_NAME; break; } } else { /* Replace with the host slash. */ *pchDst++ = RTPATH_SLASH; if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1) { /* Processed component has a wildcard and there are more characters in the path. */ *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX; } fLastComponentHasWildcard = false; } } if (RT_SUCCESS(rc)) { *pchDst++ = 0; /* Construct the full host path removing '.' and '..'. */ rc = vbsfPathAbs(pszRoot, pchVerifiedPath, pszFullPath, cbFullPathAlloc); if (RT_SUCCESS(rc)) { if (pfu32PathFlags && fLastComponentHasWildcard) { *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST; } /* Check if the full path is still within the shared folder. */ if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE) { if (!RTPathStartsWith(pszFullPath, pszRoot)) { rc = VERR_INVALID_NAME; } } if (RT_SUCCESS(rc)) { /* * If the host file system is case sensitive and the guest expects * a case insensitive fs, then correct the path components casing. */ if ( vbsfIsHostMappingCaseSensitive(hRoot) && !vbsfIsGuestMappingCaseSensitive(hRoot)) { const bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD); const bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT); rc = vbsfCorrectPathCasing(pClient, pszFullPath, strlen(pszFullPath), fWildCard, fPreserveLastComponent); } if (RT_SUCCESS(rc)) { LogFlowFunc(("%s\n", pszFullPath)); /* Return the full host path. */ *ppszHostPath = pszFullPath; if (pcbHostPathRoot) { /* Return the length of the root path without the trailing slash. */ *pcbHostPathRoot = RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]) ? cbRootLen - 1 : /* pszRoot already had the trailing slash. */ cbRootLen; /* pszRoot did not have the trailing slash. */ } } } } else { LogFunc(("vbsfPathAbs %Rrc\n", rc)); } } RTMemFree(pchVerifiedPath); } else { rc = VERR_NO_MEMORY; } } else { rc = VERR_NO_MEMORY; } } /* * Cleanup. */ RTMemFree(pchGuestPathAllocated); if (RT_SUCCESS(rc)) { return rc; } /* * Cleanup on failure. */ RTMemFree(pszFullPath); LogFunc(("%Rrc\n", rc)); return rc; }