1
//===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
3
// The LLVM Compiler Infrastructure
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
8
// Modified by Henrik Bach to comply with at least MinGW.
9
// Ported to Win32 by Jeff Cohen.
11
//===----------------------------------------------------------------------===//
13
// This file provides the Win32 specific implementation of the Path class.
15
//===----------------------------------------------------------------------===//
17
//===----------------------------------------------------------------------===//
18
//=== WARNING: Implementation here must contain only generic Win32 code that
19
//=== is guaranteed to work on *all* Win32 variants.
20
//===----------------------------------------------------------------------===//
26
// We need to undo a macro defined in Windows.h, otherwise we won't compile:
28
#undef GetCurrentDirectory
30
// Windows happily accepts either forward or backward slashes, though any path
31
// returned by a Win32 API will have backward slashes. As LLVM code basically
32
// assumes forward slashes are used, backward slashs are converted where they
33
// can be introduced into a path.
35
// Another invariant is that a path ends with a slash if and only if the path
36
// is a root directory. Any other use of a trailing slash is stripped. Unlike
37
// in Unix, Windows has a rather complicated notion of a root path and this
38
// invariant helps simply the code.
40
static void FlipBackSlashes(std::string& s) {
41
for (size_t i = 0; i < s.size(); i++)
48
const char PathSeparator = ';';
50
Path::Path(llvm::StringRef p)
52
FlipBackSlashes(path);
55
Path::Path(const char *StrStart, unsigned StrLen)
56
: path(StrStart, StrLen) {
57
FlipBackSlashes(path);
61
Path::operator=(StringRef that) {
62
path.assign(that.data(), that.size());
63
FlipBackSlashes(path);
68
Path::isValid() const {
72
// If there is a colon, it must be the second character, preceded by a letter
73
// and followed by something.
74
size_t len = path.size();
75
size_t pos = path.rfind(':',len);
77
if (pos != std::string::npos) {
78
if (pos != 1 || !isalpha(path[0]) || len < 3)
83
// Look for a UNC path, and if found adjust our notion of the root slash.
84
if (len > 3 && path[0] == '/' && path[1] == '/') {
85
rootslash = path.find('/', 2);
86
if (rootslash == std::string::npos)
90
// Check for illegal characters.
91
if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
92
"\013\014\015\016\017\020\021\022\023\024\025\026"
93
"\027\030\031\032\033\034\035\036\037")
97
// Remove trailing slash, unless it's a root slash.
98
if (len > rootslash+1 && path[len-1] == '/')
101
// Check each component for legality.
102
for (pos = 0; pos < len; ++pos) {
103
// A component may not end in a space.
104
if (path[pos] == ' ') {
105
if (path[pos+1] == '/' || path[pos+1] == '\0')
109
// A component may not end in a period.
110
if (path[pos] == '.') {
111
if (path[pos+1] == '/' || path[pos+1] == '\0') {
112
// Unless it is the pseudo-directory "."...
113
if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
116
if (pos > 0 && path[pos-1] == '.') {
117
if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
128
void Path::makeAbsolute() {
129
TCHAR FullPath[MAX_PATH + 1] = {0};
130
LPTSTR FilePart = NULL;
132
DWORD RetLength = ::GetFullPathNameA(path.c_str(),
133
sizeof(FullPath)/sizeof(FullPath[0]),
134
FullPath, &FilePart);
136
if (0 == RetLength) {
137
// FIXME: Report the error GetLastError()
138
assert(0 && "Unable to make absolute path!");
139
} else if (RetLength > MAX_PATH) {
140
// FIXME: Report too small buffer (needed RetLength bytes).
141
assert(0 && "Unable to make absolute path!");
148
Path::isAbsolute(const char *NameStart, unsigned NameLen) {
150
// FIXME: This does not handle correctly an absolute path starting from
151
// a drive letter or in UNC format.
157
return NameStart[0] == '/';
159
return (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) ||
160
(NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\'));
165
Path::isAbsolute() const {
166
// FIXME: This does not handle correctly an absolute path starting from
167
// a drive letter or in UNC format.
168
switch (path.length()) {
173
return path[0] == '/';
175
return path[0] == '/' || (path[1] == ':' && path[2] == '/');
179
static Path *TempDirectory = NULL;
182
Path::GetTemporaryDirectory(std::string* ErrMsg) {
184
return *TempDirectory;
186
char pathname[MAX_PATH];
187
if (!GetTempPath(MAX_PATH, pathname)) {
189
*ErrMsg = "Can't determine temporary directory";
194
result.set(pathname);
196
// Append a subdirectory passed on our process id so multiple LLVMs don't
197
// step on each other's toes.
199
// Mingw's Win32 header files are broken.
200
sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
202
sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
204
result.appendComponent(pathname);
206
// If there's a directory left over from a previous LLVM execution that
207
// happened to have the same process id, get rid of it.
208
result.eraseFromDisk(true);
210
// And finally (re-)create the empty directory.
211
result.createDirectoryOnDisk(false);
212
TempDirectory = new Path(result);
213
return *TempDirectory;
216
// FIXME: the following set of functions don't map to Windows very well.
218
Path::GetRootDirectory() {
225
Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
226
Paths.push_back(sys::Path("C:/WINDOWS/SYSTEM32"));
227
Paths.push_back(sys::Path("C:/WINDOWS"));
231
Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
232
char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
234
getPathList(env_var,Paths);
239
if (tmpPath.set(LLVM_LIBDIR))
240
if (tmpPath.canRead())
241
Paths.push_back(tmpPath);
244
GetSystemLibraryPaths(Paths);
248
Path::GetLLVMDefaultConfigDir() {
249
// TODO: this isn't going to fly on Windows
250
return Path("/etc/llvm");
254
Path::GetUserHomeDirectory() {
255
// TODO: Typical Windows setup doesn't define HOME.
256
const char* home = getenv("HOME");
259
if (result.set(home))
262
return GetRootDirectory();
266
Path::GetCurrentDirectory() {
267
char pathname[MAX_PATH];
268
::GetCurrentDirectoryA(MAX_PATH,pathname);
269
return Path(pathname);
272
/// GetMainExecutable - Return the path to the main executable, given the
273
/// value of argv[0] from program startup.
274
Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
275
char pathname[MAX_PATH];
276
DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
277
return ret != MAX_PATH ? Path(pathname) : Path();
281
// FIXME: the above set of functions don't map to Windows very well.
285
Path::isRootDirectory() const {
286
size_t len = path.size();
287
return len > 0 && path[len-1] == '/';
290
StringRef Path::getDirname() const {
291
return getDirnameCharSep(path, "/");
295
Path::getBasename() const {
296
// Find the last slash
297
size_t slash = path.rfind('/');
298
if (slash == std::string::npos)
303
size_t dot = path.rfind('.');
304
if (dot == std::string::npos || dot < slash)
305
return StringRef(path).substr(slash);
307
return StringRef(path).substr(slash, dot - slash);
311
Path::getSuffix() const {
312
// Find the last slash
313
size_t slash = path.rfind('/');
314
if (slash == std::string::npos)
319
size_t dot = path.rfind('.');
320
if (dot == std::string::npos || dot < slash)
321
return StringRef("");
323
return StringRef(path).substr(dot + 1);
327
Path::exists() const {
328
DWORD attr = GetFileAttributes(path.c_str());
329
return attr != INVALID_FILE_ATTRIBUTES;
333
Path::isDirectory() const {
334
DWORD attr = GetFileAttributes(path.c_str());
335
return (attr != INVALID_FILE_ATTRIBUTES) &&
336
(attr & FILE_ATTRIBUTE_DIRECTORY);
340
Path::canRead() const {
341
// FIXME: take security attributes into account.
342
DWORD attr = GetFileAttributes(path.c_str());
343
return attr != INVALID_FILE_ATTRIBUTES;
347
Path::canWrite() const {
348
// FIXME: take security attributes into account.
349
DWORD attr = GetFileAttributes(path.c_str());
350
return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
354
Path::canExecute() const {
355
// FIXME: take security attributes into account.
356
DWORD attr = GetFileAttributes(path.c_str());
357
return attr != INVALID_FILE_ATTRIBUTES;
361
Path::isRegularFile() const {
368
Path::getLast() const {
369
// Find the last slash
370
size_t pos = path.rfind('/');
372
// Handle the corner cases
373
if (pos == std::string::npos)
376
// If the last character is a slash, we have a root directory
377
if (pos == path.length()-1)
380
// Return everything after the last slash
381
return StringRef(path).substr(pos+1);
385
PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
386
if (!fsIsValid || update) {
387
WIN32_FILE_ATTRIBUTE_DATA fi;
388
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
389
MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
390
": Can't get status: ");
394
status.fileSize = fi.nFileSizeHigh;
395
status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
396
status.fileSize += fi.nFileSizeLow;
398
status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
399
status.user = 9999; // Not applicable to Windows, so...
400
status.group = 9999; // Not applicable to Windows, so...
402
// FIXME: this is only unique if the file is accessed by the same file path.
403
// How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
404
// numbers, but the concept doesn't exist in Windows.
406
for (unsigned i = 0; i < path.length(); ++i)
407
status.uniqueID += path[i];
409
__int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
410
status.modTime.fromWin32Time(ft);
412
status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
418
bool Path::makeReadableOnDisk(std::string* ErrMsg) {
419
// All files are readable on Windows (ignoring security attributes).
423
bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
424
DWORD attr = GetFileAttributes(path.c_str());
426
// If it doesn't exist, we're done.
427
if (attr == INVALID_FILE_ATTRIBUTES)
430
if (attr & FILE_ATTRIBUTE_READONLY) {
431
if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
432
MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
439
bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
440
// All files are executable on Windows (ignoring security attributes).
445
Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
446
WIN32_FILE_ATTRIBUTE_DATA fi;
447
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
448
MakeErrMsg(ErrMsg, path + ": can't get status of file");
452
if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
454
*ErrMsg = path + ": not a directory";
460
std::string searchpath = path;
461
if (path.size() == 0 || searchpath[path.size()-1] == '/')
466
HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
467
if (h == INVALID_HANDLE_VALUE) {
468
if (GetLastError() == ERROR_FILE_NOT_FOUND)
469
return true; // not really an error, now is it?
470
MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
475
if (fd.cFileName[0] == '.')
478
aPath.appendComponent(&fd.cFileName[0]);
479
result.insert(aPath);
480
} while (FindNextFile(h, &fd));
482
DWORD err = GetLastError();
484
if (err != ERROR_NO_MORE_FILES) {
486
MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
493
Path::set(StringRef a_path) {
496
std::string save(path);
498
FlipBackSlashes(path);
507
Path::appendComponent(StringRef name) {
510
std::string save(path);
512
size_t last = path.size() - 1;
513
if (path[last] != '/')
525
Path::eraseComponent() {
526
size_t slashpos = path.rfind('/',path.size());
527
if (slashpos == path.size() - 1 || slashpos == std::string::npos)
529
std::string save(path);
530
path.erase(slashpos);
539
Path::appendSuffix(StringRef suffix) {
540
std::string save(path);
551
Path::eraseSuffix() {
552
size_t dotpos = path.rfind('.',path.size());
553
size_t slashpos = path.rfind('/',path.size());
554
if (dotpos != std::string::npos) {
555
if (slashpos == std::string::npos || dotpos > slashpos+1) {
556
std::string save(path);
557
path.erase(dotpos, path.size()-dotpos);
568
inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
570
*ErrMsg = std::string(pathname) + ": " + std::string(msg);
575
Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
576
// Get a writeable copy of the path name
577
size_t len = path.length();
578
char *pathname = reinterpret_cast<char *>(_alloca(len+2));
579
path.copy(pathname, len);
582
// Make sure it ends with a slash.
583
if (len == 0 || pathname[len - 1] != '/') {
588
// Determine starting point for initial / search.
589
char *next = pathname;
590
if (pathname[0] == '/' && pathname[1] == '/') {
592
next = strchr(pathname+2, '/');
594
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
597
next = strchr(next+1, '/');
599
return PathMsg(ErrMsg, pathname,"badly formed remote directory");
603
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
606
if (pathname[1] == ':')
607
next += 2; // skip drive letter
609
next++; // skip root directory
612
// If we're supposed to create intermediate directories
613
if (create_parents) {
614
// Loop through the directory components until we're done
616
next = strchr(next, '/');
618
if (!CreateDirectory(pathname, NULL) &&
619
GetLastError() != ERROR_ALREADY_EXISTS)
620
return MakeErrMsg(ErrMsg,
621
std::string(pathname) + ": Can't create directory: ");
625
// Drop trailing slash.
627
if (!CreateDirectory(pathname, NULL) &&
628
GetLastError() != ERROR_ALREADY_EXISTS) {
629
return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: ");
636
Path::createFileOnDisk(std::string* ErrMsg) {
638
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
639
FILE_ATTRIBUTE_NORMAL, NULL);
640
if (h == INVALID_HANDLE_VALUE)
641
return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
648
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
649
WIN32_FILE_ATTRIBUTE_DATA fi;
650
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
653
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
654
// If it doesn't exist, we're done.
658
char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
659
int lastchar = path.length() - 1 ;
660
path.copy(pathname, lastchar+1);
662
// Make path end with '/*'.
663
if (pathname[lastchar] != '/')
664
pathname[++lastchar] = '/';
665
pathname[lastchar+1] = '*';
666
pathname[lastchar+2] = 0;
668
if (remove_contents) {
670
HANDLE h = FindFirstFile(pathname, &fd);
672
// It's a bad idea to alter the contents of a directory while enumerating
673
// its contents. So build a list of its contents first, then destroy them.
675
if (h != INVALID_HANDLE_VALUE) {
676
std::vector<Path> list;
679
if (strcmp(fd.cFileName, ".") == 0)
681
if (strcmp(fd.cFileName, "..") == 0)
685
aPath.appendComponent(&fd.cFileName[0]);
686
list.push_back(aPath);
687
} while (FindNextFile(h, &fd));
689
DWORD err = GetLastError();
691
if (err != ERROR_NO_MORE_FILES) {
693
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
696
for (std::vector<Path>::iterator I = list.begin(); I != list.end();
699
aPath.eraseFromDisk(true);
702
if (GetLastError() != ERROR_FILE_NOT_FOUND)
703
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
707
pathname[lastchar] = 0;
708
if (!RemoveDirectory(pathname))
709
return MakeErrMsg(ErrStr,
710
std::string(pathname) + ": Can't destroy directory: ");
713
// Read-only files cannot be deleted on Windows. Must remove the read-only
715
if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
716
if (!SetFileAttributes(path.c_str(),
717
fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
718
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
721
if (!DeleteFile(path.c_str()))
722
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
727
bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
728
assert(len < 1024 && "Request for magic string too long");
729
char* buf = (char*) alloca(1 + len);
731
HANDLE h = CreateFile(path.c_str(),
736
FILE_ATTRIBUTE_NORMAL,
738
if (h == INVALID_HANDLE_VALUE)
742
BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
745
if (!ret || nRead != len)
754
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
755
if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
756
return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
762
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
763
// FIXME: should work on directories also.
768
HANDLE h = CreateFile(path.c_str(),
769
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
770
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
773
FILE_ATTRIBUTE_NORMAL,
775
if (h == INVALID_HANDLE_VALUE)
778
BY_HANDLE_FILE_INFORMATION bhfi;
779
if (!GetFileInformationByHandle(h, &bhfi)) {
780
DWORD err = GetLastError();
783
return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
787
(uint64_t&)ft = si.modTime.toWin32Time();
788
BOOL ret = SetFileTime(h, NULL, &ft, &ft);
789
DWORD err = GetLastError();
793
return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
796
// Best we can do with Unix permission bits is to interpret the owner
798
if (si.mode & 0200) {
799
if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
800
if (!SetFileAttributes(path.c_str(),
801
bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
802
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
805
if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
806
if (!SetFileAttributes(path.c_str(),
807
bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
808
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
816
CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
817
// Can't use CopyFile macro defined in Windows.h because it would mess up the
818
// above line. We use the expansion it would have in a non-UNICODE build.
819
if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
820
return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
821
"' to '" + Dest.str() + "': ");
826
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
827
if (reuse_current && !exists())
828
return false; // File doesn't exist already, just use it!
830
// Reserve space for -XXXXXX at the end.
831
char *FNBuffer = (char*) alloca(path.size()+8);
832
unsigned offset = path.size();
833
path.copy(FNBuffer, offset);
835
// Find a numeric suffix that isn't used by an existing file. Assume there
836
// won't be more than 1 million files with the same prefix. Probably a safe
838
static unsigned FCounter = 0;
840
sprintf(FNBuffer+offset, "-%06u", FCounter);
841
if (++FCounter > 999999)
849
Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
850
// Make this into a unique file name
851
makeUnique(reuse_current, ErrMsg);
853
// Now go and create it
854
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
855
FILE_ATTRIBUTE_NORMAL, NULL);
856
if (h == INVALID_HANDLE_VALUE)
857
return MakeErrMsg(ErrMsg, path + ": can't create file");
863
/// MapInFilePages - Not yet implemented on win32.
864
const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
868
/// MapInFilePages - Not yet implemented on win32.
869
void Path::UnMapFilePages(const char *Base, uint64_t FileSize) {
870
assert(0 && "NOT IMPLEMENTED");