/** Check that the string is an absolute path to a file or print an error. */ bool checkAbsoluteFilePath(const char *pcszName, const char *pcszValue) { if (RTPathFilename(pcszValue) && RTPathStartsWithRoot(pcszValue)) return true; RTStrmPrintf(g_pStdErr, "%s: %s must be an absolute path of a file.\n", pcszName, pcszValue); return false; }
/** * Validates a name in an extension pack. * * We restrict the charset to try make sure the extension pack can be unpacked * on all file systems. * * @returns VBox status code, failures with message. * @param pszName The name to validate. * @param pszError Where to store an error message on failure. * @param cbError The size of the buffer @a pszError points to. */ static int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError) { if (RTPathStartsWithRoot(pszName)) return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName); const char *pszErr = NULL; const char *psz = pszName; int ch; while ((ch = *psz) != '\0') { /* Character set restrictions. */ if (ch < 0 || ch >= 128) { pszErr = "Only 7-bit ASCII allowed"; break; } if (ch <= 31 || ch == 127) { pszErr = "No control characters are not allowed"; break; } if (ch == '\\') { pszErr = "Only backward slashes are not allowed"; break; } if (strchr("'\":;*?|[]<>(){}", ch)) { pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed"; break; } /* Take the simple way out and ban all ".." sequences. */ if ( ch == '.' && psz[1] == '.') { pszErr = "Double dot sequence are not allowed"; break; } /* Keep the tree shallow or the hardening checks will fail. */ if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH) { pszErr = "Too long"; break; } /* advance */ psz++; } if (pszErr) return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError, "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr); return RTEXITCODE_SUCCESS; }
HRESULT SystemProperties::i_setDefaultAdditionsISO(const com::Utf8Str &aPath) { com::Utf8Str path(aPath); if (path.isEmpty()) { char strTemp[RTPATH_MAX]; int vrc = RTPathAppPrivateNoArch(strTemp, sizeof(strTemp)); AssertRC(vrc); Utf8Str strSrc1 = Utf8Str(strTemp).append("/VBoxGuestAdditions.iso"); vrc = RTPathExecDir(strTemp, sizeof(strTemp)); AssertRC(vrc); Utf8Str strSrc2 = Utf8Str(strTemp).append("/additions/VBoxGuestAdditions.iso"); vrc = RTPathUserHome(strTemp, sizeof(strTemp)); AssertRC(vrc); Utf8Str strSrc3 = Utf8StrFmt("%s/VBoxGuestAdditions_%s.iso", strTemp, VirtualBox::i_getVersionNormalized().c_str()); /* Check the standard image locations */ if (RTFileExists(strSrc1.c_str())) path = strSrc1; else if (RTFileExists(strSrc2.c_str())) path = strSrc2; else if (RTFileExists(strSrc3.c_str())) path = strSrc3; else return setError(E_FAIL, tr("Cannot determine default Guest Additions ISO location. Most likely they are not available")); } if (!RTPathStartsWithRoot(path.c_str())) return setError(E_INVALIDARG, tr("Given default machine Guest Additions ISO file '%s' is not fully qualified"), path.c_str()); if (!RTFileExists(path.c_str())) return setError(E_INVALIDARG, tr("Given default machine Guest Additions ISO file '%s' does not exist"), path.c_str()); m->strDefaultAdditionsISO = path; return S_OK; }
/** * Internal implementation to set the default machine folder. Gets called * from the public attribute setter as well as loadSettings(). With 4.0, * the "default default" machine folder has changed, and we now require * a full path always. * @param aPath * @return */ HRESULT SystemProperties::setDefaultMachineFolder(const Utf8Str &strPath) { Utf8Str path(strPath); // make modifiable if ( path.isEmpty() // used by API calls to reset the default || path == "Machines" // this value (exactly like this, without path) is stored // in VirtualBox.xml if user upgrades from before 4.0 and // has not changed the default machine folder ) { // new default with VirtualBox 4.0: "$HOME/VirtualBox VMs" HRESULT rc = getUserHomeDirectory(path); if (FAILED(rc)) return rc; path += RTPATH_SLASH_STR "VirtualBox VMs"; } if (!RTPathStartsWithRoot(path.c_str())) return setError(E_INVALIDARG, tr("Given default machine folder '%s' is not fully qualified"), path.c_str()); m->strDefaultMachineFolder = path; return S_OK; }
RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst, const char *pszPathFrom, const char *pszPathTo) { int rc = VINF_SUCCESS; AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER); AssertReturn(cbPathDst, VERR_INVALID_PARAMETER); AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER); AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER); AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER); AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER); AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER); /* * Check for different root specifiers (drive letters), creating a relative path doesn't work here. * @todo: How to handle case insensitive root specifiers correctly? */ size_t offRootFrom = rtPathRootSpecLen(pszPathFrom); size_t offRootTo = rtPathRootSpecLen(pszPathTo); if ( offRootFrom != offRootTo || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom)) return VERR_NOT_SUPPORTED; /* Filter out the parent path which is equal to both paths. */ while ( *pszPathFrom == *pszPathTo && *pszPathFrom != '\0' && *pszPathTo != '\0') { pszPathFrom++; pszPathTo++; } /* * Because path components can start with an equal string but differ afterwards we * need to go back to the beginning of the current component. */ while (!RTPATH_IS_SEP(*pszPathFrom)) pszPathFrom--; pszPathFrom++; /* Skip path separator. */ while (!RTPATH_IS_SEP(*pszPathTo)) pszPathTo--; pszPathTo++; /* Skip path separator. */ /* Paths point to the first non equal component now. */ char aszPathTmp[RTPATH_MAX + 1]; unsigned offPathTmp = 0; /* Create the part to go up from pszPathFrom. */ while (*pszPathFrom != '\0') { while ( !RTPATH_IS_SEP(*pszPathFrom) && *pszPathFrom != '\0') pszPathFrom++; if (RTPATH_IS_SEP(*pszPathFrom)) { if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1) return VERR_FILENAME_TOO_LONG; aszPathTmp[offPathTmp++] = '.'; aszPathTmp[offPathTmp++] = '.'; aszPathTmp[offPathTmp++] = RTPATH_SLASH; pszPathFrom++; } } aszPathTmp[offPathTmp] = '\0'; /* Now append the rest of pszPathTo to the final path. */ char *pszPathTmp = &aszPathTmp[offPathTmp]; size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1; rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo); if (RT_SUCCESS(rc)) { *pszPathTmp = '\0'; size_t cchPathTmp = strlen(aszPathTmp); if (cchPathTmp >= cbPathDst) return VERR_BUFFER_OVERFLOW; memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1); } else rc = VERR_FILENAME_TOO_LONG; return rc; }
int rtldrNativeLoad(const char *pszFilename, uintptr_t *phHandle, uint32_t fFlags, PRTERRINFO pErrInfo) { Assert(sizeof(*phHandle) >= sizeof(HMODULE)); AssertReturn(!(fFlags & RTLDRLOAD_FLAGS_GLOBAL), VERR_INVALID_FLAGS); AssertLogRelMsgReturn(RTPathStartsWithRoot(pszFilename), /* Relative names will still be applied to the search path. */ ("pszFilename='%s'\n", pszFilename), VERR_INTERNAL_ERROR_2); /* * Convert to UTF-16 and make sure it got a .DLL suffix. */ int rc; RTUTF16 *pwszNative = NULL; if (RTPathHasSuffix(pszFilename)) rc = RTStrToUtf16(pszFilename, &pwszNative); else { size_t cwcAlloc; rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcAlloc); if (RT_SUCCESS(rc)) { cwcAlloc += sizeof(".DLL"); pwszNative = RTUtf16Alloc(cwcAlloc * sizeof(RTUTF16)); if (pwszNative) { size_t cwcNative; rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwszNative, cwcAlloc, &cwcNative); if (RT_SUCCESS(rc)) rc = RTUtf16CopyAscii(&pwszNative[cwcNative], cwcAlloc - cwcNative, ".DLL"); } else rc = VERR_NO_UTF16_MEMORY; } } if (RT_SUCCESS(rc)) { /* * Attempt load. */ HMODULE hmod; static int s_iSearchDllLoadDirSupported = 0; if ( !(fFlags & RTLDRLOAD_FLAGS_NT_SEARCH_DLL_LOAD_DIR) || s_iSearchDllLoadDirSupported < 0) hmod = LoadLibraryExW(pwszNative, NULL, 0); else { hmod = LoadLibraryExW(pwszNative, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR); if (s_iSearchDllLoadDirSupported == 0) { if (hmod != NULL || GetLastError() != ERROR_INVALID_PARAMETER) s_iSearchDllLoadDirSupported = 1; else { s_iSearchDllLoadDirSupported = -1; hmod = LoadLibraryExW(pwszNative, NULL, 0); } } } if (hmod) { *phHandle = (uintptr_t)hmod; RTUtf16Free(pwszNative); return VINF_SUCCESS; } /* * Try figure why it failed to load. */ DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); rc = RTErrInfoSetF(pErrInfo, rc, "GetLastError=%u", dwErr); } else rc = RTErrInfoSetF(pErrInfo, rc, "Error converting UTF-8 to UTF-16 string."); RTUtf16Free(pwszNative); return rc; }
/** * Create one directory and any missing parent directories. * * @returns exit code * @param pOpts The mkdir option. * @param pszDir The path to the new directory. */ static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir) { /* We need a copy we can work with here. */ char *pszCopy = RTStrDup(pszDir); if (!pszCopy) return RTMsgErrorExitFailure("Out of string memory!"); int rc; if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) ) { size_t cchCopy = strlen(pszCopy); do { rc = RTDirRemove(pszCopy); if (RT_SUCCESS(rc)) { if (pOpts->fVerbose) RTPrintf("%s\n", pszCopy); } else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting) rc = VINF_SUCCESS; else { if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty) rc = VINF_SUCCESS; else RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc); break; } /* Strip off a component. */ while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1])) cchCopy--; pszCopy[cchCopy] = '\0'; } while (cchCopy > 0); } else { /* * Strip the final path element from the pszDir spec. */ char *pszFinalPath; char *pszSpec; uint32_t offError; rc = RTVfsChainSplitOffFinalPath(pszCopy, &pszSpec, &pszFinalPath, &offError); if (RT_SUCCESS(rc)) { /* * Open the root director/whatever. */ RTERRINFOSTATIC ErrInfo; RTVFSDIR hVfsBaseDir; if (pszSpec) { rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo)); if (RT_FAILURE(rc)) RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core); else if (!pszFinalPath) pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX); } else if (!RTPathStartsWithRoot(pszFinalPath)) { rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir); if (RT_FAILURE(rc)) RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath); } else { char *pszRoot = pszFinalPath; pszFinalPath = RTPathSkipRootSpec(pszFinalPath); char const chSaved = *pszFinalPath; *pszFinalPath = '\0'; rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir); *pszFinalPath = chSaved; if (RT_FAILURE(rc)) RTMsgError("Failed to open root dir for '%s': %Rrc", rc, pszRoot); } /* * Walk the path component by component, starting at the end. */ if (RT_SUCCESS(rc)) { size_t cchFinalPath = strlen(pszFinalPath); while (RT_SUCCESS(rc) && cchFinalPath > 0) { rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { if (pOpts->fVerbose) RTPrintf("%s\n", pszCopy); } else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting) rc = VINF_SUCCESS; else { if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty) rc = VINF_SUCCESS; else if (pszSpec) RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc); else RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc); break; } /* Strip off a component. */ while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1])) cchFinalPath--; pszFinalPath[cchFinalPath] = '\0'; } RTVfsDirRelease(hVfsBaseDir); } } else RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL); } RTStrFree(pszCopy); return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; }