Skip to content

Commit d6e52be

Browse files
committed
use to _w variants for Windows of the file APIs and widePath for file ops to support long filenames
1 parent cbac2d9 commit d6e52be

File tree

2 files changed

+81
-34
lines changed

2 files changed

+81
-34
lines changed

lib/Basic/PlatformUtility.cpp

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ using namespace llbuild::basic;
3838

3939
bool sys::chdir(const char *fileName) {
4040
#if defined(_WIN32)
41-
llvm::SmallVector<llvm::UTF16, 20> wFileName;
42-
llvm::convertUTF8ToUTF16String(fileName, wFileName);
43-
return SetCurrentDirectoryW((LPCWSTR)wFileName.data());
41+
llvm::SmallVector<wchar_t, MAX_PATH> wFileName;
42+
if (llvm::sys::path::widenPath(fileName, wFileName))
43+
return false;
44+
return ::_wchdir(wFileName.data());
4445
#else
4546
return ::chdir(fileName) == 0;
4647
#endif
@@ -63,10 +64,13 @@ time_t filetimeToTime_t(FILETIME ft) {
6364

6465
int sys::lstat(const char *fileName, sys::StatStruct *buf) {
6566
#if defined(_WIN32)
66-
llvm::SmallVector<llvm::UTF16, 20> wfilename;
67-
llvm::convertUTF8ToUTF16String(fileName, wfilename);
67+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
68+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
69+
errno = EINVAL;
70+
return -1;
71+
}
6872
HANDLE h = CreateFileW(
69-
/*lpFileName=*/(LPCWSTR)wfilename.data(),
73+
/*lpFileName=*/wfilename.data(),
7074
/*dwDesiredAccess=*/0,
7175
/*dwShareMode=*/FILE_SHARE_READ,
7276
/*lpSecurityAttributes=*/NULL,
@@ -123,7 +127,10 @@ int sys::lstat(const char *fileName, sys::StatStruct *buf) {
123127

124128
bool sys::mkdir(const char* fileName) {
125129
#if defined(_WIN32)
126-
return _mkdir(fileName) == 0;
130+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
131+
if (llvm::sys::path::widenPath(fileName, wfilename))
132+
return false;
133+
return ::_wmkdir(wfilename.data()) != 0;
127134
#else
128135
return ::mkdir(fileName, S_IRWXU | S_IRWXG | S_IRWXO) == 0;
129136
#endif
@@ -164,15 +171,25 @@ int sys::read(int fileHandle, void *destinationBuffer,
164171

165172
int sys::rmdir(const char *path) {
166173
#if defined(_WIN32)
167-
return ::_rmdir(path);
174+
llvm::SmallVector<wchar_t, MAX_PATH> wpath;
175+
if (llvm::sys::path::widenPath(path, wpath)) {
176+
errno = EINVAL;
177+
return -1;
178+
}
179+
return ::_wrmdir(wpath.data());
168180
#else
169181
return ::rmdir(path);
170182
#endif
171183
}
172184

173185
int sys::stat(const char *fileName, StatStruct *buf) {
174186
#if defined(_WIN32)
175-
return ::_stat(fileName, buf);
187+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
188+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
189+
errno = EINVAL;
190+
return -1;
191+
}
192+
return ::_wstat(wfilename.data(), buf);
176193
#else
177194
return ::stat(fileName, buf);
178195
#endif
@@ -181,19 +198,21 @@ int sys::stat(const char *fileName, StatStruct *buf) {
181198
// Create a symlink named linkPath which contains the string pointsTo
182199
int sys::symlink(const char *pointsTo, const char *linkPath) {
183200
#if defined(_WIN32)
184-
llvm::SmallVector<llvm::UTF16, 20> wPointsTo;
185-
llvm::convertUTF8ToUTF16String(pointsTo, wPointsTo);
186-
llvm::SmallVector<llvm::UTF16, 20> wLinkPath;
187-
llvm::convertUTF8ToUTF16String(linkPath, wLinkPath);
188-
DWORD attributes = GetFileAttributesW((LPCWSTR)wPointsTo.data());
201+
llvm::SmallVector<wchar_t, MAX_PATH> wPointsTo;
202+
if (llvm::sys::path::widenPath(pointsTo, wPointsTo))
203+
return -1;
204+
llvm::SmallVector<wchar_t, MAX_PATH> wLinkPath;
205+
if (llvm::sys::path::widenPath(linkPath, wLinkPath))
206+
return -1;
207+
DWORD attributes = GetFileAttributesW(wPointsTo.data());
189208
DWORD directoryFlag = (attributes != INVALID_FILE_ATTRIBUTES &&
190209
attributes & FILE_ATTRIBUTE_DIRECTORY)
191210
? SYMBOLIC_LINK_FLAG_DIRECTORY
192211
: 0;
193212
// Note that CreateSymbolicLinkW takes its arguments in reverse order
194213
// compared to symlink/_symlink
195214
return !::CreateSymbolicLinkW(
196-
(LPCWSTR)wLinkPath.data(), (LPCWSTR)wPointsTo.data(),
215+
wLinkPath.data(), wPointsTo.data(),
197216
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | directoryFlag);
198217
#else
199218
return ::symlink(pointsTo, linkPath);
@@ -202,7 +221,12 @@ int sys::symlink(const char *pointsTo, const char *linkPath) {
202221

203222
int sys::unlink(const char *fileName) {
204223
#if defined(_WIN32)
205-
return ::_unlink(fileName);
224+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
225+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
226+
errno = EINVAL;
227+
return -1;
228+
}
229+
return ::_wunlink(wfilename.data());
206230
#else
207231
return ::unlink(fileName);
208232
#endif
@@ -263,14 +287,15 @@ int sys::raiseOpenFileLimit(llbuild_rlim_t limit) {
263287
sys::MATCH_RESULT sys::filenameMatch(const std::string& pattern,
264288
const std::string& filename) {
265289
#if defined(_WIN32)
266-
llvm::SmallVector<llvm::UTF16, 20> wpattern;
267-
llvm::SmallVector<llvm::UTF16, 20> wfilename;
290+
llvm::SmallVector<wchar_t, MAX_PATH> wpattern;
291+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
268292

269-
llvm::convertUTF8ToUTF16String(pattern, wpattern);
270-
llvm::convertUTF8ToUTF16String(filename, wfilename);
293+
if (llvm::sys::path::widenPath(pattern, wpattern) ||
294+
llvm::sys::path::widenPath(filename, wfilename))
295+
return sys::MATCH_ERROR;
271296

272297
bool result =
273-
PathMatchSpecW((LPCWSTR)wfilename.data(), (LPCWSTR)wpattern.data());
298+
PathMatchSpecW(wfilename.data(), wpattern.data());
274299
return result ? sys::MATCH : sys::NO_MATCH;
275300
#else
276301
int result = fnmatch(pattern.c_str(), filename.c_str(), 0);
@@ -342,9 +367,17 @@ std::string sys::makeTmpDir() {
342367
#if defined(_WIN32)
343368
char path[MAX_PATH];
344369
tmpnam_s(path, MAX_PATH);
345-
llvm::SmallVector<llvm::UTF16, 20> wPath;
346-
llvm::convertUTF8ToUTF16String(path, wPath);
347-
CreateDirectoryW((LPCWSTR)wPath.data(), NULL);
370+
llvm::SmallVector<wchar_t, MAX_PATH> wPath;
371+
if (llvm::sys::path::widenPath(path, wPath))
372+
return std::string();
373+
if (!CreateDirectoryW(wPath.data(), NULL)) {
374+
DWORD error = GetLastError();
375+
if (error != ERROR_ALREADY_EXISTS) {
376+
fprintf(stderr, "Failed to create temporary directory '%s': error code %lu\n",
377+
path, (unsigned long)error);
378+
return std::string();
379+
}
380+
}
348381
return std::string(path);
349382
#else
350383
if (const char *tmpDir = std::getenv("TMPDIR")) {
@@ -371,15 +404,10 @@ std::string sys::getPathSeparators() {
371404

372405
sys::ModuleTraits<>::Handle sys::OpenLibrary(const char *path) {
373406
#if defined(_WIN32)
374-
int cchLength =
375-
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, strlen(path),
376-
nullptr, 0);
377-
std::u16string buffer(cchLength + 1, 0);
378-
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, strlen(path),
379-
const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(buffer.data())),
380-
buffer.size());
381-
382-
return LoadLibraryW(reinterpret_cast<LPCWSTR>(buffer.data()));
407+
llvm::SmallVector<wchar_t, MAX_PATH> wPath;
408+
if (llvm::sys::path::widenPath(path, wPath))
409+
return nullptr;
410+
return LoadLibraryW(wPath.data());
383411
#else
384412
return dlopen(path, RTLD_LAZY);
385413
#endif

src/llbuild3/LocalExecutor.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,28 @@ std::string formatWindowsCommandString(std::vector<std::string> args) {
246246

247247
std::error_code checkExecutable(const std::filesystem::path& path) {
248248

249+
#if defined(_WIN32)
250+
llvm::SmallVector<wchar_t, 128> wpath;
251+
if (llvm::sys::path::widenPath(path.c_str(), wpath)) {
252+
return std::make_error_code(std::errc::invalid_argument);
253+
}
254+
255+
DWORD attributes = GetFileAttributesW(wpath.data());
256+
if (attributes == INVALID_FILE_ATTRIBUTES) {
257+
DWORD err = GetLastError();
258+
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
259+
return std::make_error_code(std::errc::no_such_file_or_directory);
260+
} else if (err == ERROR_ACCESS_DENIED) {
261+
return std::make_error_code(std::errc::permission_denied);
262+
} else {
263+
return std::error_code(err, std::system_category());
264+
}
265+
}
266+
#else
249267
if (::access(path.c_str(), R_OK | X_OK) == -1) {
250268
return std::error_code(errno, std::generic_category());
251269
}
270+
#endif
252271

253272
// Don't say that directories are executable.
254273
#if defined(_WIN32)
@@ -258,7 +277,7 @@ std::error_code checkExecutable(const std::filesystem::path& path) {
258277
#endif
259278

260279
#if defined(_WIN32)
261-
if (0 != ::_stat(path.c_str(), &buf)) {
280+
if (0 != ::_wstat(wpath.data(), &buf)) {
262281
#else
263282
if (0 != ::stat(path.c_str(), &buf)) {
264283
#endif

0 commit comments

Comments
 (0)