return getKnownFolderPath(FOLDERID_Profile, result);
}
-static bool getTempDirEnvVar(const char *Var, SmallVectorImpl<char> &Res) {
- SmallVector<wchar_t, 128> NameUTF16;
- if (windows::UTF8ToUTF16(Var, NameUTF16))
- return false;
-
- SmallVector<wchar_t, 1024> Buf;
- size_t Size = 1024;
- do {
- Buf.reserve(Size);
- Size =
- GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
- if (Size == 0)
- return false;
-
- // Try again with larger buffer.
- } while (Size > Buf.capacity());
- Buf.set_size(Size);
-
- if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
- return false;
- return true;
-}
-
-static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) {
- const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"};
- for (const char *Env : EnvironmentVariables) {
- if (getTempDirEnvVar(Env, Res))
- return true;
- }
- return false;
-}
-
void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
(void)ErasedOnReboot;
- Result.clear();
- // Check whether the temporary directory is specified by an environment
- // variable.
- if (getTempDirEnvVar(Result))
- return;
+ wchar_t Path[MAX_PATH + 2]; // GetTempPath can return MAX_PATH + 1 + null
+ if (auto PathLength = ::GetTempPathW(sizeof(Path) / sizeof(wchar_t), Path)) {
+ assert(PathLength > 0 && PathLength <= (MAX_PATH + 1) &&
+ "GetTempPath returned undocumented result");
+ if (Path[PathLength - 1] == L'\\')
+ --PathLength; // skip trailing "\" added by GetTempPath
+ if (!UTF16ToUTF8(Path, PathLength, Result))
+ return;
+ }
// Fall back to a system default.
const char *DefaultResult = "C:\\TEMP";
+ Result.clear();
Result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
}
} // end namespace path
}
}
+TEST(Support, TempDirectory) {
+ SmallString<32> TempDir;
+ path::system_temp_directory(false, TempDir);
+ EXPECT_TRUE(!TempDir.empty());
+ TempDir.clear();
+ path::system_temp_directory(true, TempDir);
+ EXPECT_TRUE(!TempDir.empty());
+}
+
+static std::string path2regex(std::string Path) {
+ size_t Pos = 0;
+ while ((Pos = Path.find('\\', Pos)) != std::string::npos) {
+ Path.replace(Pos, 1, "\\\\");
+ Pos += 2;
+ }
+ return Path;
+}
+
+/// Helper for running temp dir test in separated process. See below.
+#define EXPECT_TEMP_DIR(prepare, expected) \
+ EXPECT_EXIT( \
+ { \
+ prepare; \
+ SmallString<300> TempDir; \
+ path::system_temp_directory(true, TempDir); \
+ raw_os_ostream(std::cerr) << TempDir; \
+ std::exit(0); \
+ }, \
+ ::testing::ExitedWithCode(0), path2regex(expected))
+
+#ifdef LLVM_ON_WIN32
+TEST(SupportDeathTest, TempDirectoryOnWindows) {
+ // In this test we want to check how system_temp_directory responds to
+ // different values of specific env vars. To prevent corrupting env vars of
+ // the current process all checks are done in separated processes.
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:\\OtherFolder"), "C:\\OtherFolder");
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:/Unix/Path/Seperators"),
+ "C:\\Unix\\Path\\Seperators");
+ EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"Local Path"), ".+\\Local Path$");
+ EXPECT_TEMP_DIR(
+ _wputenv_s(L"TMP", L"C:\\2\x03C0r-\x00B5\x00B3\\\x2135\x2080"),
+ "C:\\2\xCF\x80r-\xC2\xB5\xC2\xB3\\\xE2\x84\xB5\xE2\x82\x80");
+
+ // Test $TMP empty, $TEMP set.
+ EXPECT_TEMP_DIR(
+ {
+ _wputenv_s(L"TMP", L"");
+ _wputenv_s(L"TEMP", L"C:\\Valid\\Path");
+ },
+ "C:\\Valid\\Path");
+
+ // Test evn var / path with 260 chars.
+ SmallString<270> Expected{"C:\\Temp\\AB\\123456789"};
+ while (Expected.size() < 260)
+ Expected.append("\\DirNameWith19Charss");
+ ASSERT_EQ(260, Expected.size());
+ EXPECT_TEMP_DIR(_putenv_s("TMP", Expected.c_str()), Expected.c_str());
+
+ // Test evn var 261 chars.
+ Expected.append("X");
+ ASSERT_EQ(261, Expected.size());
+ EXPECT_TEMP_DIR(
+ {
+ _putenv_s("TMP", Expected.c_str());
+ _wputenv_s(L"TEMP", L"C:\\Short\\Path");
+ },
+ "C:\\Short\\Path");
+}
+#endif
+
class FileSystemTest : public testing::Test {
protected:
/// Unique temporary directory in which all created filesystem entities must