@@ -38,9 +38,10 @@ using namespace llbuild::basic;
3838
3939bool 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
6465int 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
124128bool 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
165172int 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
173198int 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
182246int 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
203269int 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) {
263345sys::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
372463sys::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-
0 commit comments