11
11
#include " llbuild/Basic/Stat.h"
12
12
#include " llvm/ADT/SmallVector.h"
13
13
#include " llvm/Support/ConvertUTF.h"
14
+ #include " llvm/Support/Path.h"
14
15
15
16
#if defined(_WIN32)
16
17
#include " LeanWindows.h"
17
18
#include < Shlwapi.h>
18
19
#include < direct.h>
19
20
#include < io.h>
21
+ #include < time.h>
20
22
#else
21
23
#include < fnmatch.h>
22
24
#include < unistd.h>
@@ -28,7 +30,9 @@ using namespace llbuild::basic;
28
30
29
31
bool sys::chdir (const char *fileName) {
30
32
#if defined(_WIN32)
31
- return SetCurrentDirectoryA (fileName);
33
+ llvm::SmallVector<UTF16, 20 > wFileName;
34
+ llvm::convertUTF8ToUTF16String (fileName, wFileName);
35
+ return SetCurrentDirectoryW ((LPCWSTR)wFileName.data ());
32
36
#else
33
37
return ::chdir (fileName) == 0 ;
34
38
#endif
@@ -42,11 +46,68 @@ int sys::close(int fileHandle) {
42
46
#endif
43
47
}
44
48
49
+ #if defined(_WIN32)
50
+ time_t filetimeToTime_t (FILETIME ft) {
51
+ long long ltime = ft.dwLowDateTime | ((long long )ft.dwHighDateTime << 32 );
52
+ return (time_t )((ltime - 116444736000000000 ) / 10000000 );
53
+ }
54
+ #endif
55
+
45
56
int sys::lstat (const char *fileName, sys::StatStruct *buf) {
46
57
#if defined(_WIN32)
47
- // We deliberately ignore lstat on Windows, and delegate
48
- // to stat.
49
- return ::_stat (fileName, buf);
58
+ llvm::SmallVector<UTF16, 20 > wfilename;
59
+ llvm::convertUTF8ToUTF16String (fileName, wfilename);
60
+ HANDLE h = CreateFileW (
61
+ /* lpFileName=*/ (LPCWSTR)wfilename.data (),
62
+ /* dwDesiredAccess=*/ 0 ,
63
+ /* dwShareMode=*/ FILE_SHARE_READ,
64
+ /* lpSecurityAttributes=*/ NULL ,
65
+ /* dwCreationDisposition=*/ OPEN_EXISTING,
66
+ /* dwFlagsAndAttributes=*/ FILE_FLAG_OPEN_REPARSE_POINT |
67
+ FILE_FLAG_BACKUP_SEMANTICS,
68
+ /* hTemplateFile=*/ NULL );
69
+ if (h == INVALID_HANDLE_VALUE) {
70
+ int err = GetLastError ();
71
+ if (err == ERROR_FILE_NOT_FOUND) {
72
+ errno = ENOENT;
73
+ }
74
+ return -1 ;
75
+ }
76
+ BY_HANDLE_FILE_INFORMATION info;
77
+ GetFileInformationByHandle (h, &info);
78
+ // Group id is always 0 on Windows
79
+ buf->st_gid = 0 ;
80
+ buf->st_atime = filetimeToTime_t (info.ftLastAccessTime );
81
+ buf->st_ctime = filetimeToTime_t (info.ftCreationTime );
82
+ buf->st_dev = info.dwVolumeSerialNumber ;
83
+ // inodes have meaning on FAT/HPFS/NTFS
84
+ buf->st_ino = 0 ;
85
+ buf->st_rdev = info.dwVolumeSerialNumber ;
86
+ buf->st_mode =
87
+ // On a symlink to a directory, Windows sets both the REPARSE_POINT and
88
+ // DIRECTORY attributes. Since Windows doesn't provide S_IFLNK and we
89
+ // want unix style "symlinks to directories are not directories
90
+ // themselves, we say symlinks are regular files
91
+ (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
92
+ ? _S_IFREG
93
+ : (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR
94
+ : _S_IFREG;
95
+ buf->st_mode |= (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
96
+ ? _S_IREAD
97
+ : _S_IREAD | _S_IWRITE;
98
+ llvm::StringRef extension =
99
+ llvm::sys::path::extension (llvm::StringRef (fileName));
100
+ if (extension == " .exe" || extension == " .cmd" || extension == " .bat" ||
101
+ extension == " .com" ) {
102
+ buf->st_mode |= _S_IEXEC;
103
+ }
104
+ buf->st_mtime = filetimeToTime_t (info.ftLastWriteTime );
105
+ buf->st_nlink = info.nNumberOfLinks ;
106
+ buf->st_size = ((long long )info.nFileSizeHigh << 32 ) | info.nFileSizeLow ;
107
+ // Uid is always 0 on Windows systems
108
+ buf->st_uid = 0 ;
109
+ CloseHandle (h);
110
+ return 0 ;
50
111
#else
51
112
return ::lstat (fileName, buf);
52
113
#endif
@@ -109,17 +170,25 @@ int sys::stat(const char *fileName, StatStruct *buf) {
109
170
#endif
110
171
}
111
172
112
- int sys::symlink (const char *source, const char *target) {
173
+ // Create a symlink named linkPath which contains the string pointsTo
174
+ int sys::symlink (const char *pointsTo, const char *linkPath) {
113
175
#if defined(_WIN32)
114
- DWORD attributes = GetFileAttributesA (source);
115
- if (attributes != INVALID_FILE_ATTRIBUTES &&
116
- (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ) {
117
- return ::CreateSymbolicLinkA (source, target, SYMBOLIC_LINK_FLAG_DIRECTORY);
118
- }
119
-
120
- return ::CreateSymbolicLinkA (source, target, 0 );
176
+ llvm::SmallVector<UTF16, 20 > wPointsTo;
177
+ llvm::convertUTF8ToUTF16String (pointsTo, wPointsTo);
178
+ llvm::SmallVector<UTF16, 20 > wLinkPath;
179
+ llvm::convertUTF8ToUTF16String (linkPath, wLinkPath);
180
+ DWORD attributes = GetFileAttributesW ((LPCWSTR)wPointsTo.data ());
181
+ DWORD directoryFlag = (attributes != INVALID_FILE_ATTRIBUTES &&
182
+ attributes & FILE_ATTRIBUTE_DIRECTORY)
183
+ ? SYMBOLIC_LINK_FLAG_DIRECTORY
184
+ : 0 ;
185
+ // Note that CreateSymbolicLinkW takes its arguments in reverse order
186
+ // compared to symlink/_symlink
187
+ return !::CreateSymbolicLinkW (
188
+ (LPCWSTR)wLinkPath.data (), (LPCWSTR)wPointsTo.data (),
189
+ SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | directoryFlag);
121
190
#else
122
- return ::symlink (source, target );
191
+ return ::symlink (pointsTo, linkPath );
123
192
#endif
124
193
}
125
194
@@ -217,23 +286,29 @@ std::string sys::strerror(int error) {
217
286
218
287
char *sys::strsep (char **stringp, const char *delim) {
219
288
#if defined(_WIN32)
220
- char *begin, *end = *stringp;
289
+ // If *stringp is NULL, the strsep() function returns NULL and does nothing
290
+ // else.
221
291
if (*stringp == NULL ) {
222
292
return NULL ;
223
293
}
224
- int delimLen = strlen (delim);
225
- bool found = false ;
226
- while (*end) {
227
- for (int i = 0 ; i < delimLen; i++) {
294
+ char *begin = *stringp;
295
+ char *end = *stringp;
296
+ do {
297
+ // Otherwise, this function finds the first token in the string *stringp,
298
+ // that is delimited by one of the bytes in the string delim.
299
+ for (int i = 0 ; delim[i] != ' \0 ' ; i++) {
228
300
if (*end == delim[i]) {
229
- found = true ;
301
+ // This token is terminated by overwriting the delimiter with a null
302
+ // byte ('\0'), and *stringp is updated to point past the token.
303
+ *end = ' \0 ' ;
304
+ *stringp = end + 1 ;
305
+ return begin;
230
306
}
231
307
}
232
- if (found) {
233
- *stringp = end + 1 ;
234
- }
235
- }
236
- *end = ' \0 ' ;
308
+ } while (*(++end));
309
+ // In case no delimiter was found, the token is taken to be the entire string
310
+ // *stringp, and *stringp is made NULL.
311
+ *stringp = NULL ;
237
312
return begin;
238
313
#else
239
314
return ::strsep (stringp, delim);
@@ -244,9 +319,20 @@ std::string sys::makeTmpDir() {
244
319
#if defined(_WIN32)
245
320
char path[MAX_PATH];
246
321
tmpnam_s (path, MAX_PATH);
322
+ llvm::SmallVector<UTF16, 20 > wPath;
323
+ llvm::convertUTF8ToUTF16String (path, wPath);
324
+ CreateDirectoryW ((LPCWSTR)wPath.data (), NULL );
247
325
return std::string (path);
248
326
#else
249
327
char tmpDirPathBuf[] = " /tmp/fileXXXXXX" ;
250
328
return std::string (mkdtemp (tmpDirPathBuf));
251
329
#endif
252
330
}
331
+
332
+ std::string sys::getPathSeparators () {
333
+ #if defined(_WIN32)
334
+ return " /\\ " ;
335
+ #else
336
+ return " /" ;
337
+ #endif
338
+ }
0 commit comments