llvm.org GIT mirror llvm / 2dc4746
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222671 91177308-0d34-0410-b5e6-96231b3b80d8 Paul Robinson 4 years ago
4 changed file(s) with 75 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
4343
4444 using llvm::sys::windows::UTF8ToUTF16;
4545 using llvm::sys::windows::UTF16ToUTF8;
46 using llvm::sys::path::widenPath;
4647
4748 static std::error_code windows_error(DWORD E) {
4849 return mapWindowsError(E);
5859 }
5960 }
6061
62 namespace llvm {
63 namespace sys {
64 namespace path {
65
6166 // Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the
6267 // path is longer than CreateDirectory can tolerate, make it absolute and
6368 // prefixed by '\\?\'.
64 static std::error_code widenPath(const Twine &Path8,
65 SmallVectorImpl &Path16) {
69 std::error_code widenPath(const Twine &Path8,
70 SmallVectorImpl &Path16) {
6671 const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename.
6772
6873 // Several operations would convert Path8 to SmallString; more efficient to
110115 // Just use the caller's original path.
111116 return UTF8ToUTF16(Path8Str, Path16);
112117 }
113
114 namespace llvm {
115 namespace sys {
118 } // end namespace path
119
116120 namespace fs {
117121
118122 std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
116116 sa.bInheritHandle = TRUE;
117117
118118 SmallVector fnameUnicode;
119 if (windows::UTF8ToUTF16(fname, fnameUnicode))
120 return INVALID_HANDLE_VALUE;
121
119 if (path->empty()) {
120 // Don't play long-path tricks on "NUL".
121 if (windows::UTF8ToUTF16(fname, fnameUnicode))
122 return INVALID_HANDLE_VALUE;
123 } else {
124 if (path::widenPath(fname, fnameUnicode))
125 return INVALID_HANDLE_VALUE;
126 }
122127 h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
123128 FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
124129 FILE_ATTRIBUTE_NORMAL, NULL);
125130 if (h == INVALID_HANDLE_VALUE) {
126 MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
131 MakeErrMsg(ErrMsg, fname + ": Can't open file for " +
127132 (fd ? "input: " : "output: "));
128133 }
129134
321326 fflush(stderr);
322327
323328 SmallVector ProgramUtf16;
324 if (std::error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) {
329 if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) {
325330 SetLastError(ec.value());
326331 MakeErrMsg(ErrMsg,
327332 std::string("Unable to convert application name to UTF-16"));
2929
3030 #include "llvm/ADT/SmallVector.h"
3131 #include "llvm/ADT/StringRef.h"
32 #include "llvm/ADT/Twine.h"
3233 #include "llvm/Config/config.h" // Get build system configuration settings
3334 #include "llvm/Support/Compiler.h"
3435 #include
161162 }
162163
163164 namespace sys {
165 namespace path {
166 std::error_code widenPath(const Twine &Path8,
167 SmallVectorImpl &Path16);
168 } // end namespace path
169
164170 namespace windows {
165171 std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl &utf16);
166172 std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
6868 ++envp;
6969 }
7070 }
71
72 #ifdef LLVM_ON_WIN32
73 TEST(ProgramTest, CreateProcessLongPath) {
74 if (getenv("LLVM_PROGRAM_TEST_LONG_PATH"))
75 exit(0);
76
77 // getMainExecutable returns an absolute path; prepend the long-path prefix.
78 std::string MyAbsExe =
79 sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
80 std::string MyExe;
81 if (!StringRef(MyAbsExe).startswith("\\\\?\\"))
82 MyExe.append("\\\\?\\");
83 MyExe.append(MyAbsExe);
84
85 const char *ArgV[] = {
86 MyExe.c_str(),
87 "--gtest_filter=ProgramTest.CreateProcessLongPath",
88 nullptr
89 };
90
91 // Add LLVM_PROGRAM_TEST_LONG_PATH to the environment of the child.
92 std::vector EnvP;
93 CopyEnvironment(EnvP);
94 EnvP.push_back("LLVM_PROGRAM_TEST_LONG_PATH=1");
95 EnvP.push_back(nullptr);
96
97 // Redirect stdout to a long path.
98 SmallString<128> TestDirectory;
99 ASSERT_NO_ERROR(
100 fs::createUniqueDirectory("program-redirect-test", TestDirectory));
101 SmallString<256> LongPath(TestDirectory);
102 LongPath.push_back('\\');
103 // MAX_PATH = 260
104 LongPath.append(260 - TestDirectory.size(), 'a');
105 StringRef LongPathRef(LongPath);
106
107 std::string Error;
108 bool ExecutionFailed;
109 const StringRef *Redirects[] = { nullptr, &LongPathRef, nullptr };
110 int RC = ExecuteAndWait(MyExe, ArgV, &EnvP[0], Redirects,
111 /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error,
112 &ExecutionFailed);
113 EXPECT_FALSE(ExecutionFailed) << Error;
114 EXPECT_EQ(0, RC);
115
116 // Remove the long stdout.
117 ASSERT_NO_ERROR(fs::remove(Twine(LongPath)));
118 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory)));
119 }
120 #endif
71121
72122 TEST(ProgramTest, CreateProcessTrailingSlash) {
73123 if (getenv("LLVM_PROGRAM_TEST_CHILD")) {