Skip to content

Commit bb4eef8

Browse files
committed
use to Win32 file APIs and widePath for file ops to support long filenames
1 parent 5891ce0 commit bb4eef8

File tree

2 files changed

+146
-41
lines changed

2 files changed

+146
-41
lines changed

lib/Basic/PlatformUtility.cpp

Lines changed: 119 additions & 34 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 SetCurrentDirectoryW(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 CreateDirectoryW(wfilename.data(), NULL) != 0;
127134
#else
128135
return ::mkdir(fileName, S_IRWXU | S_IRWXG | S_IRWXO) == 0;
129136
#endif
@@ -164,15 +171,72 @@ 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+
if (RemoveDirectoryW(wpath.data())) {
180+
return 0;
181+
}
182+
int err = GetLastError();
183+
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
184+
errno = ENOENT;
185+
} else if (err == ERROR_ACCESS_DENIED) {
186+
errno = EACCES;
187+
} else if (err == ERROR_DIR_NOT_EMPTY) {
188+
errno = ENOTEMPTY;
189+
} else {
190+
errno = EINVAL;
191+
}
192+
return -1;
168193
#else
169194
return ::rmdir(path);
170195
#endif
171196
}
172197

173198
int sys::stat(const char *fileName, StatStruct *buf) {
174199
#if defined(_WIN32)
175-
return ::_stat(fileName, buf);
200+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
201+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
202+
errno = EINVAL;
203+
return -1;
204+
}
205+
206+
WIN32_FILE_ATTRIBUTE_DATA fileData;
207+
if (!GetFileAttributesExW(wfilename.data(), GetFileExInfoStandard, &fileData)) {
208+
int err = GetLastError();
209+
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
210+
errno = ENOENT;
211+
} else if (err == ERROR_ACCESS_DENIED) {
212+
errno = EACCES;
213+
} else {
214+
errno = EINVAL;
215+
}
216+
return -1;
217+
}
218+
219+
// Fill the stat structure
220+
buf->st_gid = 0;
221+
buf->st_atime = filetimeToTime_t(fileData.ftLastAccessTime);
222+
buf->st_ctime = filetimeToTime_t(fileData.ftCreationTime);
223+
buf->st_dev = 0;
224+
buf->st_ino = 0;
225+
buf->st_rdev = 0;
226+
buf->st_mode = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR : _S_IFREG;
227+
buf->st_mode |= (fileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _S_IREAD : _S_IREAD | _S_IWRITE;
228+
229+
llvm::StringRef extension = llvm::sys::path::extension(llvm::StringRef(fileName));
230+
if (extension == ".exe" || extension == ".cmd" || extension == ".bat" || extension == ".com") {
231+
buf->st_mode |= _S_IEXEC;
232+
}
233+
234+
buf->st_mtime = filetimeToTime_t(fileData.ftLastWriteTime);
235+
buf->st_nlink = 1;
236+
buf->st_size = ((long long)fileData.nFileSizeHigh << 32) | fileData.nFileSizeLow;
237+
buf->st_uid = 0;
238+
239+
return 0;
176240
#else
177241
return ::stat(fileName, buf);
178242
#endif
@@ -181,19 +245,21 @@ int sys::stat(const char *fileName, StatStruct *buf) {
181245
// Create a symlink named linkPath which contains the string pointsTo
182246
int sys::symlink(const char *pointsTo, const char *linkPath) {
183247
#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());
248+
llvm::SmallVector<wchar_t, MAX_PATH> wPointsTo;
249+
if (llvm::sys::path::widenPath(pointsTo, wPointsTo))
250+
return -1;
251+
llvm::SmallVector<wchar_t, MAX_PATH> wLinkPath;
252+
if (llvm::sys::path::widenPath(linkPath, wLinkPath))
253+
return -1;
254+
DWORD attributes = GetFileAttributesW(wPointsTo.data());
189255
DWORD directoryFlag = (attributes != INVALID_FILE_ATTRIBUTES &&
190256
attributes & FILE_ATTRIBUTE_DIRECTORY)
191257
? SYMBOLIC_LINK_FLAG_DIRECTORY
192258
: 0;
193259
// Note that CreateSymbolicLinkW takes its arguments in reverse order
194260
// compared to symlink/_symlink
195261
return !::CreateSymbolicLinkW(
196-
(LPCWSTR)wLinkPath.data(), (LPCWSTR)wPointsTo.data(),
262+
wLinkPath.data(), wPointsTo.data(),
197263
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | directoryFlag);
198264
#else
199265
return ::symlink(pointsTo, linkPath);
@@ -202,7 +268,23 @@ int sys::symlink(const char *pointsTo, const char *linkPath) {
202268

203269
int sys::unlink(const char *fileName) {
204270
#if defined(_WIN32)
205-
return ::_unlink(fileName);
271+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
272+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
273+
errno = EINVAL;
274+
return -1;
275+
}
276+
if (DeleteFileW(wfilename.data())) {
277+
return 0;
278+
}
279+
int err = GetLastError();
280+
if (err == ERROR_FILE_NOT_FOUND) {
281+
errno = ENOENT;
282+
} else if (err == ERROR_ACCESS_DENIED) {
283+
errno = EACCES;
284+
} else {
285+
errno = EINVAL;
286+
}
287+
return -1;
206288
#else
207289
return ::unlink(fileName);
208290
#endif
@@ -263,14 +345,15 @@ int sys::raiseOpenFileLimit(llbuild_rlim_t limit) {
263345
sys::MATCH_RESULT sys::filenameMatch(const std::string& pattern,
264346
const std::string& filename) {
265347
#if defined(_WIN32)
266-
llvm::SmallVector<llvm::UTF16, 20> wpattern;
267-
llvm::SmallVector<llvm::UTF16, 20> wfilename;
348+
llvm::SmallVector<wchar_t, MAX_PATH> wpattern;
349+
llvm::SmallVector<wchar_t, MAX_PATH> wfilename;
268350

269-
llvm::convertUTF8ToUTF16String(pattern, wpattern);
270-
llvm::convertUTF8ToUTF16String(filename, wfilename);
351+
if (llvm::sys::path::widenPath(pattern, wpattern) ||
352+
llvm::sys::path::widenPath(filename, wfilename))
353+
return sys::MATCH_ERROR;
271354

272355
bool result =
273-
PathMatchSpecW((LPCWSTR)wfilename.data(), (LPCWSTR)wpattern.data());
356+
PathMatchSpecW(wfilename.data(), wpattern.data());
274357
return result ? sys::MATCH : sys::NO_MATCH;
275358
#else
276359
int result = fnmatch(pattern.c_str(), filename.c_str(), 0);
@@ -342,9 +425,17 @@ std::string sys::makeTmpDir() {
342425
#if defined(_WIN32)
343426
char path[MAX_PATH];
344427
tmpnam_s(path, MAX_PATH);
345-
llvm::SmallVector<llvm::UTF16, 20> wPath;
346-
llvm::convertUTF8ToUTF16String(path, wPath);
347-
CreateDirectoryW((LPCWSTR)wPath.data(), NULL);
428+
llvm::SmallVector<wchar_t, MAX_PATH> wPath;
429+
if (llvm::sys::path::widenPath(path, wPath))
430+
return std::string();
431+
if (!CreateDirectoryW(wPath.data(), NULL)) {
432+
DWORD error = GetLastError();
433+
if (error != ERROR_ALREADY_EXISTS) {
434+
fprintf(stderr, "Failed to create temporary directory '%s': error code %lu\n",
435+
path, (unsigned long)error);
436+
return std::string();
437+
}
438+
}
348439
return std::string(path);
349440
#else
350441
if (const char *tmpDir = std::getenv("TMPDIR")) {
@@ -371,15 +462,10 @@ std::string sys::getPathSeparators() {
371462

372463
sys::ModuleTraits<>::Handle sys::OpenLibrary(const char *path) {
373464
#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()));
465+
llvm::SmallVector<wchar_t, MAX_PATH> wPath;
466+
if (llvm::sys::path::widenPath(path, wPath))
467+
return nullptr;
468+
return LoadLibraryW(wPath.data());
383469
#else
384470
return dlopen(path, RTLD_LAZY);
385471
#endif
@@ -401,4 +487,3 @@ void sys::CloseLibrary(sys::ModuleTraits<>::Handle handle) {
401487
dlclose(handle);
402488
#endif
403489
}
404-

src/llbuild3/LocalExecutor.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,27 +246,47 @@ 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, MAX_PATH> 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)
255-
struct ::_stat buf;
274+
WIN32_FILE_ATTRIBUTE_DATA fileData;
275+
if (!GetFileAttributesExW(wpath.data(), GetFileExInfoStandard, &fileData)) {
276+
return std::make_error_code(std::errc::permission_denied);
277+
}
278+
279+
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
280+
return std::make_error_code(std::errc::permission_denied);
256281
#else
257282
struct ::stat buf;
258-
#endif
259-
260-
#if defined(_WIN32)
261-
if (0 != ::_stat(path.c_str(), &buf)) {
262-
#else
263283
if (0 != ::stat(path.c_str(), &buf)) {
264-
#endif
265284
return std::make_error_code(std::errc::permission_denied);
266285
}
267286

268287
if (!S_ISREG(buf.st_mode))
269288
return std::make_error_code(std::errc::permission_denied);
289+
#endif
270290

271291
return std::error_code();
272292
}

0 commit comments

Comments
 (0)