Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -775,49 +775,22 @@ return getKnownFolderPath(FOLDERID_Profile, result); } -static bool getTempDirEnvVar(const char *Var, SmallVectorImpl &Res) { - SmallVector NameUTF16; - if (windows::UTF8ToUTF16(Var, NameUTF16)) - return false; - - SmallVector 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 &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 &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 Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -351,6 +351,63 @@ } } +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()); + +#ifdef LLVM_ON_WIN32 + const wchar_t *OrigTmp = _wgetenv(L"TMP"); + const wchar_t *OrigTemp = _wgetenv(L"TEMP"); + + _wputenv_s(L"TMP", L"C:\\OtherFolder"); + path::system_temp_directory(true, TempDir); + EXPECT_EQ("C:\\OtherFolder", TempDir); + + _wputenv_s(L"TMP", L"C:/Unix/Path/Seperators"); + path::system_temp_directory(true, TempDir); + EXPECT_EQ("C:\\Unix\\Path\\Seperators", TempDir); + + _wputenv_s(L"TMP", L"Local Path"); + path::system_temp_directory(true, TempDir); + EXPECT_NE("Local Path", TempDir); + EXPECT_TRUE(path::is_absolute(TempDir)); + EXPECT_EQ("Local Path", path::filename(TempDir)); + + SmallString<270> Expected{"C:\\Temp\\AB\\123456789"}; + while (Expected.size() < 260) + Expected.append("\\DirNameWith19Charss"); + ASSERT_EQ(260, Expected.size()); + + _putenv_s("TMP", Expected.c_str()); + path::system_temp_directory(true, TempDir); + EXPECT_EQ(Expected, TempDir); + + // Path longer than 260 is invalid + Expected.append("X"); + ASSERT_EQ(261, Expected.size()); + path::system_temp_directory(true, TempDir); + EXPECT_NE(Expected, TempDir); + + _wputenv_s(L"TMP", L""); + _wputenv_s(L"TEMP", L"C:\\Valid\\Path"); + path::system_temp_directory(true, TempDir); + EXPECT_EQ("C:\\Valid\\Path", TempDir); + + // Test Unicode paths + _wputenv_s(L"TMP", L"C:\\2\x03C0r-\x00B5\x00B3\\\x2135\x2080"); + path::system_temp_directory(true, TempDir); + EXPECT_EQ("C:\\2\xCF\x80r-\xC2\xB5\xC2\xB3\\\xE2\x84\xB5\xE2\x82\x80", + TempDir); + + _wputenv_s(L"TEMP", OrigTemp); + _wputenv_s(L"TMP", OrigTmp); +#endif +} + class FileSystemTest : public testing::Test { protected: /// Unique temporary directory in which all created filesystem entities must