[llvm] r222671 - More long path name support on Windows, this time in program execution.

Paul Robinson paul_robinson at playstation.sony.com
Mon Nov 24 10:05:29 PST 2014


Author: probinson
Date: Mon Nov 24 12:05:29 2014
New Revision: 222671

URL: http://llvm.org/viewvc/llvm-project?rev=222671&view=rev
Log:
More long path name support on Windows, this time in program execution.
Allows long paths for the executable and redirected stdin/stdout/stderr.
Addresses PR21563.

Modified:
    llvm/trunk/lib/Support/Windows/Path.inc
    llvm/trunk/lib/Support/Windows/Program.inc
    llvm/trunk/lib/Support/Windows/WindowsSupport.h
    llvm/trunk/unittests/Support/ProgramTest.cpp

Modified: llvm/trunk/lib/Support/Windows/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=222671&r1=222670&r2=222671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Path.inc (original)
+++ llvm/trunk/lib/Support/Windows/Path.inc Mon Nov 24 12:05:29 2014
@@ -44,6 +44,7 @@ using namespace llvm;
 
 using llvm::sys::windows::UTF8ToUTF16;
 using llvm::sys::windows::UTF16ToUTF8;
+using llvm::sys::path::widenPath;
 
 static std::error_code windows_error(DWORD E) {
   return mapWindowsError(E);
@@ -59,11 +60,15 @@ static bool is_separator(const wchar_t v
   }
 }
 
+namespace llvm {
+namespace sys  {
+namespace path {
+
 // Convert a UTF-8 path to UTF-16.  Also, if the absolute equivalent of the
 // path is longer than CreateDirectory can tolerate, make it absolute and
 // prefixed by '\\?\'.
-static std::error_code widenPath(const Twine &Path8,
-                                 SmallVectorImpl<wchar_t> &Path16) {
+std::error_code widenPath(const Twine &Path8,
+                          SmallVectorImpl<wchar_t> &Path16) {
   const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename.
 
   // Several operations would convert Path8 to SmallString; more efficient to
@@ -111,9 +116,8 @@ static std::error_code widenPath(const T
   // Just use the caller's original path.
   return UTF8ToUTF16(Path8Str, Path16);
 }
+} // end namespace path
 
-namespace llvm {
-namespace sys  {
 namespace fs {
 
 std::string getMainExecutable(const char *argv0, void *MainExecAddr) {

Modified: llvm/trunk/lib/Support/Windows/Program.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Program.inc?rev=222671&r1=222670&r2=222671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Program.inc (original)
+++ llvm/trunk/lib/Support/Windows/Program.inc Mon Nov 24 12:05:29 2014
@@ -117,14 +117,19 @@ static HANDLE RedirectIO(const StringRef
   sa.bInheritHandle = TRUE;
 
   SmallVector<wchar_t, 128> fnameUnicode;
-  if (windows::UTF8ToUTF16(fname, fnameUnicode))
-    return INVALID_HANDLE_VALUE;
-
+  if (path->empty()) {
+    // Don't play long-path tricks on "NUL".
+    if (windows::UTF8ToUTF16(fname, fnameUnicode))
+      return INVALID_HANDLE_VALUE;
+  } else {
+    if (path::widenPath(fname, fnameUnicode))
+      return INVALID_HANDLE_VALUE;
+  }
   h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
                   FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
                   FILE_ATTRIBUTE_NORMAL, NULL);
   if (h == INVALID_HANDLE_VALUE) {
-    MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
+    MakeErrMsg(ErrMsg, fname + ": Can't open file for " +
         (fd ? "input: " : "output: "));
   }
 
@@ -322,7 +327,7 @@ static bool Execute(ProcessInfo &PI, Str
   fflush(stderr);
 
   SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
-  if (std::error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) {
+  if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) {
     SetLastError(ec.value());
     MakeErrMsg(ErrMsg,
                std::string("Unable to convert application name to UTF-16"));

Modified: llvm/trunk/lib/Support/Windows/WindowsSupport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/WindowsSupport.h?rev=222671&r1=222670&r2=222671&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/WindowsSupport.h (original)
+++ llvm/trunk/lib/Support/Windows/WindowsSupport.h Mon Nov 24 12:05:29 2014
@@ -30,6 +30,7 @@
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/Config/config.h" // Get build system configuration settings
 #include "llvm/Support/Compiler.h"
 #include <system_error>
@@ -162,6 +163,11 @@ c_str(SmallVectorImpl<T> &str) {
 }
 
 namespace sys {
+namespace path {
+std::error_code widenPath(const Twine &Path8,
+                          SmallVectorImpl<wchar_t> &Path16);
+} // end namespace path
+
 namespace windows {
 std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
 std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,

Modified: llvm/trunk/unittests/Support/ProgramTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ProgramTest.cpp?rev=222671&r1=222670&r2=222671&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ProgramTest.cpp (original)
+++ llvm/trunk/unittests/Support/ProgramTest.cpp Mon Nov 24 12:05:29 2014
@@ -70,6 +70,56 @@ static void CopyEnvironment(std::vector<
   }
 }
 
+#ifdef LLVM_ON_WIN32
+TEST(ProgramTest, CreateProcessLongPath) {
+  if (getenv("LLVM_PROGRAM_TEST_LONG_PATH"))
+    exit(0);
+
+  // getMainExecutable returns an absolute path; prepend the long-path prefix.
+  std::string MyAbsExe =
+      sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+  std::string MyExe;
+  if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
+    MyExe.append("\\\\?\\");
+  MyExe.append(MyAbsExe);
+
+  const char *ArgV[] = {
+    MyExe.c_str(),
+    "--gtest_filter=ProgramTest.CreateProcessLongPath",
+    nullptr
+  };
+
+  // Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child.
+  std::vector<const char *> EnvP;
+  CopyEnvironment(EnvP);
+  EnvP.push_back("LLVM_PROGRAM_TEST_LONG_PATH=1");
+  EnvP.push_back(nullptr);
+
+  // Redirect stdout to a long path.
+  SmallString<128> TestDirectory;
+  ASSERT_NO_ERROR(
+    fs::createUniqueDirectory("program-redirect-test", TestDirectory));
+  SmallString<256> LongPath(TestDirectory);
+  LongPath.push_back('\\');
+  // MAX_PATH = 260
+  LongPath.append(260 - TestDirectory.size(), 'a');
+  StringRef LongPathRef(LongPath);
+
+  std::string Error;
+  bool ExecutionFailed;
+  const StringRef *Redirects[] = { nullptr, &LongPathRef, nullptr };
+  int RC = ExecuteAndWait(MyExe, ArgV, &EnvP[0], Redirects,
+    /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
+    &ExecutionFailed);
+  EXPECT_FALSE(ExecutionFailed) << Error;
+  EXPECT_EQ(0, RC);
+
+  // Remove the long stdout.
+  ASSERT_NO_ERROR(fs::remove(Twine(LongPath)));
+  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory)));
+}
+#endif
+
 TEST(ProgramTest, CreateProcessTrailingSlash) {
   if (getenv("LLVM_PROGRAM_TEST_CHILD")) {
     if (ProgramTestStringArg1 == "has\\\\ trailing\\" &&





More information about the llvm-commits mailing list