Skip to content

Commit 2a26b43

Browse files
committed
use to Win32 file APIs and widePath for file ops to support long filenames
1 parent f3b9649 commit 2a26b43

File tree

2 files changed

+141
-40
lines changed

2 files changed

+141
-40
lines changed

lib/Basic/PlatformUtility.cpp

Lines changed: 114 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, 128> 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, 128> 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, 128> 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,73 @@ 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, 128> 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+
} else {
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;
193+
}
168194
#else
169195
return ::rmdir(path);
170196
#endif
171197
}
172198

173199
int sys::stat(const char *fileName, StatStruct *buf) {
174200
#if defined(_WIN32)
175-
return ::_stat(fileName, buf);
201+
llvm::SmallVector<wchar_t, 128> wfilename;
202+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
203+
errno = EINVAL;
204+
return -1;
205+
}
206+
207+
WIN32_FILE_ATTRIBUTE_DATA fileData;
208+
if (!GetFileAttributesExW(wfilename.data(), GetFileExInfoStandard, &fileData)) {
209+
int err = GetLastError();
210+
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
211+
errno = ENOENT;
212+
} else if (err == ERROR_ACCESS_DENIED) {
213+
errno = EACCES;
214+
} else {
215+
errno = EINVAL;
216+
}
217+
return -1;
218+
}
219+
220+
// Fill the stat structure
221+
buf->st_gid = 0;
222+
buf->st_atime = filetimeToTime_t(fileData.ftLastAccessTime);
223+
buf->st_ctime = filetimeToTime_t(fileData.ftCreationTime);
224+
buf->st_dev = 0;
225+
buf->st_ino = 0;
226+
buf->st_rdev = 0;
227+
buf->st_mode = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR : _S_IFREG;
228+
buf->st_mode |= (fileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? _S_IREAD : _S_IREAD | _S_IWRITE;
229+
230+
llvm::StringRef extension = llvm::sys::path::extension(llvm::StringRef(fileName));
231+
if (extension == ".exe" || extension == ".cmd" || extension == ".bat" || extension == ".com") {
232+
buf->st_mode |= _S_IEXEC;
233+
}
234+
235+
buf->st_mtime = filetimeToTime_t(fileData.ftLastWriteTime);
236+
buf->st_nlink = 1;
237+
buf->st_size = ((long long)fileData.nFileSizeHigh << 32) | fileData.nFileSizeLow;
238+
buf->st_uid = 0;
239+
240+
return 0;
176241
#else
177242
return ::stat(fileName, buf);
178243
#endif
@@ -181,19 +246,21 @@ int sys::stat(const char *fileName, StatStruct *buf) {
181246
// Create a symlink named linkPath which contains the string pointsTo
182247
int sys::symlink(const char *pointsTo, const char *linkPath) {
183248
#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());
249+
llvm::SmallVector<wchar_t, 128> wPointsTo;
250+
if (llvm::sys::path::widenPath(pointsTo, wPointsTo))
251+
return -1;
252+
llvm::SmallVector<wchar_t, 128> wLinkPath;
253+
if (llvm::sys::path::widenPath(linkPath, wLinkPath))
254+
return -1;
255+
DWORD attributes = GetFileAttributesW(wPointsTo.data());
189256
DWORD directoryFlag = (attributes != INVALID_FILE_ATTRIBUTES &&
190257
attributes & FILE_ATTRIBUTE_DIRECTORY)
191258
? SYMBOLIC_LINK_FLAG_DIRECTORY
192259
: 0;
193260
// Note that CreateSymbolicLinkW takes its arguments in reverse order
194261
// compared to symlink/_symlink
195262
return !::CreateSymbolicLinkW(
196-
(LPCWSTR)wLinkPath.data(), (LPCWSTR)wPointsTo.data(),
263+
wLinkPath.data(), wPointsTo.data(),
197264
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | directoryFlag);
198265
#else
199266
return ::symlink(pointsTo, linkPath);
@@ -202,7 +269,24 @@ int sys::symlink(const char *pointsTo, const char *linkPath) {
202269

203270
int sys::unlink(const char *fileName) {
204271
#if defined(_WIN32)
205-
return ::_unlink(fileName);
272+
llvm::SmallVector<wchar_t, 128> wfilename;
273+
if (llvm::sys::path::widenPath(fileName, wfilename)) {
274+
errno = EINVAL;
275+
return -1;
276+
}
277+
if (DeleteFileW(wfilename.data())) {
278+
return 0;
279+
} else {
280+
int err = GetLastError();
281+
if (err == ERROR_FILE_NOT_FOUND) {
282+
errno = ENOENT;
283+
} else if (err == ERROR_ACCESS_DENIED) {
284+
errno = EACCES;
285+
} else {
286+
errno = EINVAL;
287+
}
288+
return -1;
289+
}
206290
#else
207291
return ::unlink(fileName);
208292
#endif
@@ -263,14 +347,15 @@ int sys::raiseOpenFileLimit(llbuild_rlim_t limit) {
263347
sys::MATCH_RESULT sys::filenameMatch(const std::string& pattern,
264348
const std::string& filename) {
265349
#if defined(_WIN32)
266-
llvm::SmallVector<llvm::UTF16, 20> wpattern;
267-
llvm::SmallVector<llvm::UTF16, 20> wfilename;
350+
llvm::SmallVector<wchar_t, 128> wpattern;
351+
llvm::SmallVector<wchar_t, 128> wfilename;
268352

269-
llvm::convertUTF8ToUTF16String(pattern, wpattern);
270-
llvm::convertUTF8ToUTF16String(filename, wfilename);
353+
if (llvm::sys::path::widenPath(pattern, wpattern) ||
354+
llvm::sys::path::widenPath(filename, wfilename))
355+
return sys::MATCH_ERROR;
271356

272357
bool result =
273-
PathMatchSpecW((LPCWSTR)wfilename.data(), (LPCWSTR)wpattern.data());
358+
PathMatchSpecW(wfilename.data(), wpattern.data());
274359
return result ? sys::MATCH : sys::NO_MATCH;
275360
#else
276361
int result = fnmatch(pattern.c_str(), filename.c_str(), 0);
@@ -342,9 +427,10 @@ std::string sys::makeTmpDir() {
342427
#if defined(_WIN32)
343428
char path[MAX_PATH];
344429
tmpnam_s(path, MAX_PATH);
345-
llvm::SmallVector<llvm::UTF16, 20> wPath;
346-
llvm::convertUTF8ToUTF16String(path, wPath);
347-
CreateDirectoryW((LPCWSTR)wPath.data(), NULL);
430+
llvm::SmallVector<wchar_t, 128> wPath;
431+
if (llvm::sys::path::widenPath(path, wPath))
432+
return std::string();
433+
CreateDirectoryW(wPath.data(), NULL);
348434
return std::string(path);
349435
#else
350436
if (const char *tmpDir = std::getenv("TMPDIR")) {
@@ -371,15 +457,10 @@ std::string sys::getPathSeparators() {
371457

372458
sys::ModuleTraits<>::Handle sys::OpenLibrary(const char *path) {
373459
#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()));
460+
llvm::SmallVector<wchar_t, 128> wPath;
461+
if (llvm::sys::path::widenPath(path, wPath))
462+
return nullptr;
463+
return LoadLibraryW(wPath.data());
383464
#else
384465
return dlopen(path, RTLD_LAZY);
385466
#endif

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, 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)
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)