RTDECL(int) RTEnvGetUtf8(const char *pszVar, char *pszValue, size_t cbValue, size_t *pcchActual) { AssertPtrReturn(pszVar, VERR_INVALID_POINTER); AssertPtrNullReturn(pszValue, VERR_INVALID_POINTER); AssertReturn(pszValue || !cbValue, VERR_INVALID_PARAMETER); AssertPtrNullReturn(pcchActual, VERR_INVALID_POINTER); AssertReturn(pcchActual || (pszValue && cbValue), VERR_INVALID_PARAMETER); AssertReturn(strchr(pszVar, '=') == NULL, VERR_ENV_INVALID_VAR_NAME); if (pcchActual) *pcchActual = 0; PRTUTF16 pwszVar; int rc = RTStrToUtf16(pszVar, &pwszVar); AssertRCReturn(rc, rc); /** @todo Consider _wgetenv_s or GetEnvironmentVariableW here to avoid the * potential race with a concurrent _wputenv/_putenv. */ PCRTUTF16 pwszValue = _wgetenv(pwszVar); RTUtf16Free(pwszVar); if (pwszValue) { if (cbValue) rc = RTUtf16ToUtf8Ex(pwszValue, RTSTR_MAX, &pszValue, cbValue, pcchActual); else rc = RTUtf16CalcUtf8LenEx(pwszValue, RTSTR_MAX, pcchActual); } else rc = VERR_ENV_VAR_NOT_FOUND; return rc; }
RTDECL(int) RTPathUserDocuments(char *pszPath, size_t cchPath) { /* * Validate input */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cchPath, VERR_INVALID_PARAMETER); RTLDRMOD hShell32; int rc = RTLdrLoad("Shell32.dll", &hShell32); if (RT_SUCCESS(rc)) { PFNSHGETFOLDERPATHW pfnSHGetFolderPathW; rc = RTLdrGetSymbol(hShell32, "SHGetFolderPathW", (void**)&pfnSHGetFolderPathW); if (RT_SUCCESS(rc)) { RTUTF16 wszPath[RTPATH_MAX]; HRESULT hrc = pfnSHGetFolderPathW(0, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, wszPath); if ( hrc == S_OK /* Found */ || hrc == S_FALSE) /* Found, but doesn't exist */ { /* * Convert and return. */ RTLdrClose(hShell32); return RTUtf16ToUtf8Ex(&wszPath[0], RTSTR_MAX, &pszPath, cchPath, NULL); } } RTLdrClose(hShell32); } return VERR_PATH_NOT_FOUND; }
int rtldrNativeLoadSystem(const char *pszFilename, const char *pszExt, uint32_t fFlags, PRTLDRMOD phLdrMod) { /* * We only try the System32 directory. */ WCHAR wszSysDir[MAX_PATH]; UINT cwcSysDir = GetSystemDirectoryW(wszSysDir, MAX_PATH); if (cwcSysDir >= MAX_PATH) return VERR_FILENAME_TOO_LONG; char szPath[RTPATH_MAX]; char *pszPath = szPath; int rc = RTUtf16ToUtf8Ex(wszSysDir, RTSTR_MAX, &pszPath, sizeof(szPath), NULL); if (RT_SUCCESS(rc)) { rc = RTPathAppend(szPath, sizeof(szPath), pszFilename); if (pszExt && RT_SUCCESS(rc)) rc = RTStrCat(szPath, sizeof(szPath), pszExt); if (RT_SUCCESS(rc)) { if (RTFileExists(szPath)) rc = RTLdrLoadEx(szPath, phLdrMod, fFlags, NULL); else rc = VERR_MODULE_NOT_FOUND; } } return rc; }
/** * Get the real (no symlinks, no . or .. components) path, must exist. * * @returns iprt status code. * @param pszPath The path to resolve. * @param pszRealPath Where to store the real path. * @param cchRealPath Size of the buffer. */ RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath) { /* * Convert to UTF-16, call Win32 APIs, convert back. */ PRTUTF16 pwszPath; int rc = RTStrToUtf16(pszPath, &pwszPath); if (!RT_SUCCESS(rc)) return (rc); LPWSTR lpFile; WCHAR wsz[RTPATH_MAX]; rc = GetFullPathNameW((LPCWSTR)pwszPath, RT_ELEMENTS(wsz), &wsz[0], &lpFile); if (rc > 0 && rc < RT_ELEMENTS(wsz)) { /* Check that it exists. (Use RTPathAbs() to just resolve the name.) */ DWORD dwAttr = GetFileAttributesW(wsz); if (dwAttr != INVALID_FILE_ATTRIBUTES) rc = RTUtf16ToUtf8Ex((PRTUTF16)&wsz[0], RTSTR_MAX, &pszRealPath, cchRealPath, NULL); else rc = RTErrConvertFromWin32(GetLastError()); } else if (rc <= 0) rc = RTErrConvertFromWin32(GetLastError()); else rc = VERR_FILENAME_TOO_LONG; RTUtf16Free(pwszPath); return rc; }
VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetStringDescriptor(PDEVICE_OBJECT pDevObj, char *pszResult, ULONG cbResult, int iIndex, int LangId, ULONG dwTimeoutMs) { char aBuf[MAXIMUM_USB_STRING_LENGTH]; AssertCompile(sizeof (aBuf) <= UINT8_MAX); UCHAR cbBuf = (UCHAR)sizeof (aBuf); PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)&aBuf; Assert(pszResult); *pszResult = 0; memset(pDr, 0, cbBuf); pDr->bLength = cbBuf; pDr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE; NTSTATUS Status = VBoxUsbToolGetDescriptor(pDevObj, pDr, cbBuf, USB_STRING_DESCRIPTOR_TYPE, iIndex, LangId, dwTimeoutMs); if (NT_SUCCESS(Status)) { if (pDr->bLength >= sizeof (USB_STRING_DESCRIPTOR)) { int rc = RTUtf16ToUtf8Ex(pDr->bString, (pDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString)) / sizeof(RTUTF16), &pszResult, cbResult, NULL /*pcch*/); if (RT_SUCCESS(rc)) { USBLibPurgeEncoding(pszResult); Status = STATUS_SUCCESS; } else Status = STATUS_UNSUCCESSFUL; } else Status = STATUS_INVALID_PARAMETER; } return Status; }
/** * Gets the user home directory. * * @returns iprt status code. * @param pszPath Buffer where to store the path. * @param cchPath Buffer size in bytes. */ RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath) { RTUTF16 wszPath[RTPATH_MAX]; DWORD dwAttr; /* * There are multiple definitions for what WE think of as user home... */ if ( !GetEnvironmentVariableW(L"HOME", &wszPath[0], RTPATH_MAX) || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { if ( !GetEnvironmentVariableW(L"USERPROFILE", &wszPath[0], RTPATH_MAX) || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { /* %HOMEDRIVE%%HOMEPATH% */ if (!GetEnvironmentVariableW(L"HOMEDRIVE", &wszPath[0], RTPATH_MAX)) return VERR_PATH_NOT_FOUND; size_t const cwc = RTUtf16Len(&wszPath[0]); if ( !GetEnvironmentVariableW(L"HOMEPATH", &wszPath[cwc], RTPATH_MAX - (DWORD)cwc) || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) return VERR_PATH_NOT_FOUND; } } /* * Convert and return. */ return RTUtf16ToUtf8Ex(&wszPath[0], RTSTR_MAX, &pszPath, cchPath, NULL); }
/** * A variant of Utf8Str::copyFrom that does not throw any exceptions but returns * E_OUTOFMEMORY instead. * * @param a_pbstr The source string. * @returns S_OK or E_OUTOFMEMORY. */ HRESULT Utf8Str::copyFromEx(CBSTR a_pbstr) { if (a_pbstr && *a_pbstr) { int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr, RTSTR_MAX, // size_t cwcString: translate entire string &m_psz, // char **ppsz: output buffer 0, // size_t cch: if 0, func allocates buffer in *ppsz &m_cch); // size_t *pcch: receives the size of the output string, excluding the terminator. if (RT_SUCCESS(vrc)) m_cbAllocated = m_cch + 1; else { if ( vrc != VERR_NO_STR_MEMORY && vrc != VERR_NO_MEMORY) { /* ASSUME: input is valid Utf-16. Fake out of memory error. */ AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len((PCRTUTF16)a_pbstr) * sizeof(RTUTF16), a_pbstr)); } m_cch = 0; m_cbAllocated = 0; m_psz = NULL; return E_OUTOFMEMORY; } } else { m_cch = 0; m_cbAllocated = 0; m_psz = NULL; } return S_OK; }
/** * Gets the user home directory. * * @returns iprt status code. * @param pszPath Buffer where to store the path. * @param cchPath Buffer size in bytes. */ RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath) { /* * Validate input */ AssertPtrReturn(pszPath, VERR_INVALID_POINTER); AssertReturn(cchPath, VERR_INVALID_PARAMETER); RTUTF16 wszPath[RTPATH_MAX]; bool fValidFolderPath = false; /* * Try with Windows XP+ functionality first. */ RTLDRMOD hShell32; int rc = RTLdrLoadSystem("Shell32.dll", true /*fNoUnload*/, &hShell32); if (RT_SUCCESS(rc)) { PFNSHGETFOLDERPATHW pfnSHGetFolderPathW; rc = RTLdrGetSymbol(hShell32, "SHGetFolderPathW", (void**)&pfnSHGetFolderPathW); if (RT_SUCCESS(rc)) { HRESULT hrc = pfnSHGetFolderPathW(0, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, wszPath); fValidFolderPath = (hrc == S_OK); } RTLdrClose(hShell32); } DWORD dwAttr; if ( !fValidFolderPath || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { /* * Fall back to Windows specific environment variables. HOME is not used. */ if ( !GetEnvironmentVariableW(L"USERPROFILE", &wszPath[0], RTPATH_MAX) || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) { /* %HOMEDRIVE%%HOMEPATH% */ if (!GetEnvironmentVariableW(L"HOMEDRIVE", &wszPath[0], RTPATH_MAX)) return VERR_PATH_NOT_FOUND; size_t const cwc = RTUtf16Len(&wszPath[0]); if ( !GetEnvironmentVariableW(L"HOMEPATH", &wszPath[cwc], RTPATH_MAX - (DWORD)cwc) || (dwAttr = GetFileAttributesW(&wszPath[0])) == INVALID_FILE_ATTRIBUTES || !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) return VERR_PATH_NOT_FOUND; } } /* * Convert and return. */ return RTUtf16ToUtf8Ex(&wszPath[0], RTSTR_MAX, &pszPath, cchPath, NULL); }
/** * Converts the name from UTF-16 to UTF-8. * * Fortunately, the names are relative to the directory, so we won't have to do * any sweaty path style coversion. :-) * * @returns IPRT status code * @param pThis The directory instance data. * @param cbName The file name length in bytes. * @param pwsName The file name, not terminated. */ static int rtDirNtConvertName(PRTDIR pThis, uint32_t cbName, PCRTUTF16 pwsName) { int rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName); if (RT_SUCCESS(rc)) { if (!pThis->cbNameAlloc) pThis->cbNameAlloc = pThis->cchName + 1; } else if (rc == VERR_BUFFER_OVERFLOW) { RTStrFree(pThis->pszName); pThis->pszName = NULL; pThis->cbNameAlloc = 0; rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName); if (RT_SUCCESS(rc)) pThis->cbNameAlloc = pThis->cchName + 1; } Assert(RT_SUCCESS(rc) ? pThis->pszName != NULL : pThis->pszName == NULL); return rc; }
RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath) { WCHAR wszInput[4]; wszInput[0] = chDrive; wszInput[1] = ':'; wszInput[2] = '\0'; int rc; RTUTF16 wszFullPath[RTPATH_MAX]; if (GetFullPathNameW(wszInput, RTPATH_MAX, wszFullPath, NULL)) rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL); else rc = RTErrConvertFromWin32(GetLastError()); return rc; }
/** * 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; }
DECLHIDDEN(int) rtProcInitExePath(char *pszPath, size_t cchPath) { /* * Query the image name from the dynamic linker, convert and return it. */ WCHAR wsz[RTPATH_MAX]; HMODULE hExe = GetModuleHandle(NULL); if (GetModuleFileNameW(hExe, wsz, RTPATH_MAX)) { int rc = RTUtf16ToUtf8Ex(wsz, RTSTR_MAX, &pszPath, cchPath, NULL); AssertRCReturn(rc, rc); return VINF_SUCCESS; } DWORD err = GetLastError(); int rc = RTErrConvertFromWin32(err); AssertMsgFailed(("%Rrc %d\n", rc, err)); return rc; }
RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath) { int rc; /* * GetCurrentDirectory may in some cases omit the drive letter, according * to MSDN, thus the GetFullPathName call. */ RTUTF16 wszCurPath[RTPATH_MAX]; if (GetCurrentDirectoryW(RTPATH_MAX, wszCurPath)) { RTUTF16 wszFullPath[RTPATH_MAX]; if (GetFullPathNameW(wszCurPath, RTPATH_MAX, wszFullPath, NULL)) rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cchPath, NULL); else rc = RTErrConvertFromWin32(GetLastError()); } else rc = RTErrConvertFromWin32(GetLastError()); return rc; }
HRESULT HostDnsServiceWin::updateInfo() { HostDnsInformation info; LONG lrc; int rc; std::string strDomain; std::string strSearchList; /* NB: comma separated, no spaces */ /* * We ignore "DhcpDomain" key here since it's not stable. If * there are two active interfaces that use DHCP (in particular * when host uses OpenVPN) then DHCP ACKs will take turns updating * that key. Instead we call GetAdaptersAddresses() below (which * is what ipconfig.exe seems to do). */ for (DWORD regIndex = 0; /**/; ++regIndex) { char keyName[256]; DWORD cbKeyName = sizeof(keyName); DWORD keyType = 0; char keyData[1024]; DWORD cbKeyData = sizeof(keyData); lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex, keyName, &cbKeyName, 0, &keyType, (LPBYTE)keyData, &cbKeyData); if (lrc == ERROR_NO_MORE_ITEMS) break; if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */ continue; if (lrc != ERROR_SUCCESS) { LogRel2(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc)); return E_FAIL; } if (keyType != REG_SZ) continue; if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0') --cbKeyData; /* don't count trailing NUL if present */ if (RTStrICmp("Domain", keyName) == 0) { strDomain.assign(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: Domain=\"%s\"\n", strDomain.c_str())); } else if (RTStrICmp("DhcpDomain", keyName) == 0) { std::string strDhcpDomain(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: DhcpDomain=\"%s\"\n", strDhcpDomain.c_str())); } else if (RTStrICmp("SearchList", keyName) == 0) { strSearchList.assign(keyData, cbKeyData); LogRel2(("HostDnsServiceWin: SearchList=\"%s\"\n", strSearchList.c_str())); } } /* statically configured domain name */ if (!strDomain.empty()) { info.domain = strDomain; info.searchList.push_back(strDomain); } /* statically configured search list */ if (!strSearchList.empty()) { vappend(info.searchList, strSearchList, ','); } /* * When name servers are configured statically it seems that the * value of Tcpip\Parameters\NameServer is NOT set, inly interface * specific NameServer value is (which triggers notification for * us to pick up the change). Fortunately, DnsApi seems to do the * right thing there. */ DNS_STATUS status; PIP4_ARRAY pIp4Array = NULL; // NB: must be set on input it seems, despite docs' claim to the contrary. DWORD cbBuffer = sizeof(&pIp4Array); status = DnsQueryConfig(DnsConfigDnsServerList, DNS_CONFIG_FLAG_ALLOC, NULL, NULL, &pIp4Array, &cbBuffer); if (status == NO_ERROR && pIp4Array != NULL) { for (DWORD i = 0; i < pIp4Array->AddrCount; ++i) { char szAddrStr[16] = ""; RTStrPrintf(szAddrStr, sizeof(szAddrStr), "%RTnaipv4", pIp4Array->AddrArray[i]); LogRel2(("HostDnsServiceWin: server %d: %s\n", i+1, szAddrStr)); info.servers.push_back(szAddrStr); } LocalFree(pIp4Array); } /** * DnsQueryConfig(DnsConfigSearchList, ...) is not implemented. * Call GetAdaptersAddresses() that orders the returned list * appropriately and collect IP_ADAPTER_ADDRESSES::DnsSuffix. */ do { PIP_ADAPTER_ADDRESSES pAddrBuf = NULL; ULONG cbAddrBuf = 8 * 1024; bool fReallocated = false; ULONG err; pAddrBuf = (PIP_ADAPTER_ADDRESSES) malloc(cbAddrBuf); if (pAddrBuf == NULL) { LogRel2(("HostDnsServiceWin: failed to allocate %zu bytes" " of GetAdaptersAddresses buffer\n", (size_t)cbAddrBuf)); break; } while (pAddrBuf != NULL) { ULONG cbAddrBufProvided = cbAddrBuf; err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, pAddrBuf, &cbAddrBuf); if (err == NO_ERROR) { break; } else if (err == ERROR_BUFFER_OVERFLOW) { LogRel2(("HostDnsServiceWin: provided GetAdaptersAddresses with %zu" " but asked again for %zu bytes\n", (size_t)cbAddrBufProvided, (size_t)cbAddrBuf)); if (RT_UNLIKELY(fReallocated)) /* what? again?! */ { LogRel2(("HostDnsServiceWin: ... not going to realloc again\n")); free(pAddrBuf); pAddrBuf = NULL; break; } PIP_ADAPTER_ADDRESSES pNewBuf = (PIP_ADAPTER_ADDRESSES) realloc(pAddrBuf, cbAddrBuf); if (pNewBuf == NULL) { LogRel2(("HostDnsServiceWin: failed to reallocate %zu bytes\n", (size_t)cbAddrBuf)); free(pAddrBuf); pAddrBuf = NULL; break; } /* try again */ pAddrBuf = pNewBuf; /* cbAddrBuf already updated */ fReallocated = true; } else { LogRel2(("HostDnsServiceWin: GetAdaptersAddresses error %d\n", err)); free(pAddrBuf); pAddrBuf = NULL; break; } } if (pAddrBuf == NULL) break; for (PIP_ADAPTER_ADDRESSES pAdp = pAddrBuf; pAdp != NULL; pAdp = pAdp->Next) { LogRel2(("HostDnsServiceWin: %ls (status %u) ...\n", pAdp->FriendlyName ? pAdp->FriendlyName : L"(null)", pAdp->OperStatus)); if (pAdp->OperStatus != IfOperStatusUp) continue; if (pAdp->DnsSuffix == NULL || *pAdp->DnsSuffix == L'\0') continue; char *pszDnsSuffix = NULL; rc = RTUtf16ToUtf8Ex(pAdp->DnsSuffix, RTSTR_MAX, &pszDnsSuffix, 0, /* allocate */ NULL); if (RT_FAILURE(rc)) { LogRel2(("HostDnsServiceWin: failed to convert DNS suffix \"%ls\": %Rrc\n", pAdp->DnsSuffix, rc)); continue; } AssertContinue(pszDnsSuffix != NULL); AssertContinue(*pszDnsSuffix != '\0'); LogRel2(("HostDnsServiceWin: ... suffix = \"%s\"\n", pszDnsSuffix)); vappend(info.searchList, pszDnsSuffix); RTStrFree(pszDnsSuffix); } free(pAddrBuf); } while (0); if (info.domain.empty() && !info.searchList.empty()) info.domain = info.searchList[0]; if (info.searchList.size() == 1) info.searchList.clear(); HostDnsMonitor::setInfo(info); return S_OK; }
/** * Services the RTSYSOSINFO_PRODUCT, RTSYSOSINFO_RELEASE * and RTSYSOSINFO_SERVICE_PACK requests. * * @returns See RTSystemQueryOSInfo. * @param enmInfo See RTSystemQueryOSInfo. * @param pszInfo See RTSystemQueryOSInfo. * @param cchInfo See RTSystemQueryOSInfo. */ static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo) { /* * Make sure it's terminated correctly in case of error. */ *pszInfo = '\0'; /* * Check that we got the windows version at init time. */ AssertReturn(g_WinOsInfoEx.dwOSVersionInfoSize, VERR_WRONG_ORDER); /* * Service the request. */ char szTmp[512]; szTmp[0] = '\0'; switch (enmInfo) { /* * The product name. */ case RTSYSOSINFO_PRODUCT: { switch (g_enmWinVer) { case kRTWinOSType_95: strcpy(szTmp, "Windows 95"); break; case kRTWinOSType_95SP1: strcpy(szTmp, "Windows 95 (Service Pack 1)"); break; case kRTWinOSType_95OSR2: strcpy(szTmp, "Windows 95 (OSR 2)"); break; case kRTWinOSType_98: strcpy(szTmp, "Windows 98"); break; case kRTWinOSType_98SP1: strcpy(szTmp, "Windows 98 (Service Pack 1)"); break; case kRTWinOSType_98SE: strcpy(szTmp, "Windows 98 (Second Edition)"); break; case kRTWinOSType_ME: strcpy(szTmp, "Windows Me"); break; case kRTWinOSType_NT351: strcpy(szTmp, "Windows NT 3.51"); break; case kRTWinOSType_NT4: strcpy(szTmp, "Windows NT 4.0"); break; case kRTWinOSType_2K: strcpy(szTmp, "Windows 2000"); break; case kRTWinOSType_XP: strcpy(szTmp, "Windows XP"); if (g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL) strcat(szTmp, " Home"); if ( g_WinOsInfoEx.wProductType == VER_NT_WORKSTATION && !(g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL)) strcat(szTmp, " Professional"); #if 0 /** @todo fixme */ if (GetSystemMetrics(SM_MEDIACENTER)) strcat(szTmp, " Media Center"); #endif break; case kRTWinOSType_2003: strcpy(szTmp, "Windows 2003"); break; case kRTWinOSType_VISTA: { strcpy(szTmp, "Windows Vista"); rtSystemWinAppendProductType(szTmp); break; } case kRTWinOSType_2008: strcpy(szTmp, "Windows 2008"); break; case kRTWinOSType_7: strcpy(szTmp, "Windows 7"); break; case kRTWinOSType_2008R2: strcpy(szTmp, "Windows 2008 R2"); break; case kRTWinOSType_8: strcpy(szTmp, "Windows 8"); break; case kRTWinOSType_2012: strcpy(szTmp, "Windows 2012"); break; case kRTWinOSType_81: strcpy(szTmp, "Windows 8.1"); break; case kRTWinOSType_2012R2: strcpy(szTmp, "Windows 2012 R2"); break; case kRTWinOSType_10: strcpy(szTmp, "Windows 10"); break; case kRTWinOSType_2016: strcpy(szTmp, "Windows 2016"); break; case kRTWinOSType_NT_UNKNOWN: RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u", g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion); break; default: AssertFailed(); case kRTWinOSType_UNKNOWN: RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u", g_WinOsInfoEx.dwPlatformId, g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion); break; } break; } /* * The release. */ case RTSYSOSINFO_RELEASE: { RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u", g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion, g_WinOsInfoEx.dwBuildNumber); break; } /* * Get the service pack. */ case RTSYSOSINFO_SERVICE_PACK: { if (g_WinOsInfoEx.wServicePackMajor) { if (g_WinOsInfoEx.wServicePackMinor) RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u", (unsigned)g_WinOsInfoEx.wServicePackMajor, (unsigned)g_WinOsInfoEx.wServicePackMinor); else RTStrPrintf(szTmp, sizeof(szTmp), "%u", (unsigned)g_WinOsInfoEx.wServicePackMajor); } else if (g_WinOsInfoEx.szCSDVersion[0]) { /* just copy the entire string. */ char *pszTmp = szTmp; int rc = RTUtf16ToUtf8Ex(g_WinOsInfoEx.szCSDVersion, RT_ELEMENTS(g_WinOsInfoEx.szCSDVersion), &pszTmp, sizeof(szTmp), NULL); if (RT_SUCCESS(rc)) RTStrStripR(szTmp); else szTmp[0] = '\0'; AssertCompile(sizeof(szTmp) > sizeof(g_WinOsInfoEx.szCSDVersion)); } else { switch (g_enmWinVer) { case kRTWinOSType_95SP1: strcpy(szTmp, "1"); break; case kRTWinOSType_98SP1: strcpy(szTmp, "1"); break; default: break; } } break; } default: AssertFatalFailed(); } /* * Copy the result to the return buffer. */ size_t cchTmp = strlen(szTmp); Assert(cchTmp < sizeof(szTmp)); if (cchTmp < cchInfo) { memcpy(pszInfo, szTmp, cchTmp + 1); return VINF_SUCCESS; } memcpy(pszInfo, szTmp, cchInfo - 1); pszInfo[cchInfo - 1] = '\0'; return VERR_BUFFER_OVERFLOW; }
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; }