[llvm] r252366 - [Support] Use GetTempDir to get the temporary dir path on Windows.

Pawel Bylica via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 6 15:21:49 PST 2015


Author: chfast
Date: Fri Nov  6 17:21:49 2015
New Revision: 252366

URL: http://llvm.org/viewvc/llvm-project?rev=252366&view=rev
Log:
[Support] Use GetTempDir to get the temporary dir path on Windows.

Summary:
In general GetTempDir follows the same logic as the replaced code: checks env variables TMP, TEMP, USERPROFILE in order. However, it also perform other checks like making separators native (\), making the path absolute, etc.

This change fixes FileSystemTest.CreateDir unittest that had been failing when run from Unix-like shell on Windows (Unix-like path separator (/) used in env variables).

Reviewers: chapuni, rafael, aaron.ballman

Subscribers: rafael, llvm-commits

Differential Revision: http://reviews.llvm.org/D14231

Modified:
    llvm/trunk/lib/Support/Windows/Path.inc
    llvm/trunk/unittests/Support/Path.cpp

Modified: llvm/trunk/lib/Support/Windows/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=252366&r1=252365&r2=252366&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Path.inc (original)
+++ llvm/trunk/lib/Support/Windows/Path.inc Fri Nov  6 17:21:49 2015
@@ -773,49 +773,22 @@ bool home_directory(SmallVectorImpl<char
   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

Modified: llvm/trunk/unittests/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Path.cpp?rev=252366&r1=252365&r2=252366&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Path.cpp (original)
+++ llvm/trunk/unittests/Support/Path.cpp Fri Nov  6 17:21:49 2015
@@ -351,6 +351,76 @@ TEST(Support, UserCacheDirectory) {
   }
 }
 
+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




More information about the llvm-commits mailing list