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;
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.
284
StringRef Path::getDirname() const {
285
return getDirnameCharSep(path, "/");
289
Path::getBasename() const {
290
// Find the last slash
291
size_t slash = path.rfind('/');
292
if (slash == std::string::npos)
297
size_t dot = path.rfind('.');
298
if (dot == std::string::npos || dot < slash)
299
return StringRef(path).substr(slash);
301
return StringRef(path).substr(slash, dot - slash);
305
Path::getSuffix() const {
306
// Find the last slash
307
size_t slash = path.rfind('/');
308
if (slash == std::string::npos)
313
size_t dot = path.rfind('.');
314
if (dot == std::string::npos || dot < slash)
315
return StringRef("");
317
return StringRef(path).substr(dot + 1);
321
Path::exists() const {
322
DWORD attr = GetFileAttributes(path.c_str());
323
return attr != INVALID_FILE_ATTRIBUTES;
327
Path::isDirectory() const {
328
DWORD attr = GetFileAttributes(path.c_str());
329
return (attr != INVALID_FILE_ATTRIBUTES) &&
330
(attr & FILE_ATTRIBUTE_DIRECTORY);
334
Path::canRead() const {
335
// FIXME: take security attributes into account.
336
DWORD attr = GetFileAttributes(path.c_str());
337
return attr != INVALID_FILE_ATTRIBUTES;
341
Path::canWrite() const {
342
// FIXME: take security attributes into account.
343
DWORD attr = GetFileAttributes(path.c_str());
344
return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
348
Path::canExecute() const {
349
// FIXME: take security attributes into account.
350
DWORD attr = GetFileAttributes(path.c_str());
351
return attr != INVALID_FILE_ATTRIBUTES;
355
Path::isRegularFile() const {
362
Path::getLast() const {
363
// Find the last slash
364
size_t pos = path.rfind('/');
366
// Handle the corner cases
367
if (pos == std::string::npos)
370
// If the last character is a slash, we have a root directory
371
if (pos == path.length()-1)
374
// Return everything after the last slash
375
return StringRef(path).substr(pos+1);
379
PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
380
if (!fsIsValid || update) {
381
WIN32_FILE_ATTRIBUTE_DATA fi;
382
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
383
MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
384
": Can't get status: ");
388
status.fileSize = fi.nFileSizeHigh;
389
status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
390
status.fileSize += fi.nFileSizeLow;
392
status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
393
status.user = 9999; // Not applicable to Windows, so...
394
status.group = 9999; // Not applicable to Windows, so...
396
// FIXME: this is only unique if the file is accessed by the same file path.
397
// How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
398
// numbers, but the concept doesn't exist in Windows.
400
for (unsigned i = 0; i < path.length(); ++i)
401
status.uniqueID += path[i];
404
ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
405
ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
406
status.modTime.fromWin32Time(ui.QuadPart);
408
status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
414
bool Path::makeReadableOnDisk(std::string* ErrMsg) {
415
// All files are readable on Windows (ignoring security attributes).
419
bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
420
DWORD attr = GetFileAttributes(path.c_str());
422
// If it doesn't exist, we're done.
423
if (attr == INVALID_FILE_ATTRIBUTES)
426
if (attr & FILE_ATTRIBUTE_READONLY) {
427
if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
428
MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
435
bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
436
// All files are executable on Windows (ignoring security attributes).
441
Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
442
WIN32_FILE_ATTRIBUTE_DATA fi;
443
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
444
MakeErrMsg(ErrMsg, path + ": can't get status of file");
448
if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
450
*ErrMsg = path + ": not a directory";
456
std::string searchpath = path;
457
if (path.size() == 0 || searchpath[path.size()-1] == '/')
462
HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
463
if (h == INVALID_HANDLE_VALUE) {
464
if (GetLastError() == ERROR_FILE_NOT_FOUND)
465
return true; // not really an error, now is it?
466
MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
471
if (fd.cFileName[0] == '.')
474
aPath.appendComponent(&fd.cFileName[0]);
475
result.insert(aPath);
476
} while (FindNextFile(h, &fd));
478
DWORD err = GetLastError();
480
if (err != ERROR_NO_MORE_FILES) {
482
MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
489
Path::set(StringRef a_path) {
492
std::string save(path);
494
FlipBackSlashes(path);
503
Path::appendComponent(StringRef name) {
506
std::string save(path);
508
size_t last = path.size() - 1;
509
if (path[last] != '/')
521
Path::eraseComponent() {
522
size_t slashpos = path.rfind('/',path.size());
523
if (slashpos == path.size() - 1 || slashpos == std::string::npos)
525
std::string save(path);
526
path.erase(slashpos);
535
Path::appendSuffix(StringRef suffix) {
536
std::string save(path);
547
Path::eraseSuffix() {
548
size_t dotpos = path.rfind('.',path.size());
549
size_t slashpos = path.rfind('/',path.size());
550
if (dotpos != std::string::npos) {
551
if (slashpos == std::string::npos || dotpos > slashpos+1) {
552
std::string save(path);
553
path.erase(dotpos, path.size()-dotpos);
564
inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
566
*ErrMsg = std::string(pathname) + ": " + std::string(msg);
571
Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
572
// Get a writeable copy of the path name
573
size_t len = path.length();
574
char *pathname = reinterpret_cast<char *>(_alloca(len+2));
575
path.copy(pathname, len);
578
// Make sure it ends with a slash.
579
if (len == 0 || pathname[len - 1] != '/') {
584
// Determine starting point for initial / search.
585
char *next = pathname;
586
if (pathname[0] == '/' && pathname[1] == '/') {
588
next = strchr(pathname+2, '/');
590
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
593
next = strchr(next+1, '/');
595
return PathMsg(ErrMsg, pathname,"badly formed remote directory");
599
return PathMsg(ErrMsg, pathname, "badly formed remote directory");
602
if (pathname[1] == ':')
603
next += 2; // skip drive letter
605
next++; // skip root directory
608
// If we're supposed to create intermediate directories
609
if (create_parents) {
610
// Loop through the directory components until we're done
612
next = strchr(next, '/');
614
if (!CreateDirectory(pathname, NULL) &&
615
GetLastError() != ERROR_ALREADY_EXISTS)
616
return MakeErrMsg(ErrMsg,
617
std::string(pathname) + ": Can't create directory: ");
621
// Drop trailing slash.
623
if (!CreateDirectory(pathname, NULL) &&
624
GetLastError() != ERROR_ALREADY_EXISTS) {
625
return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: ");
632
Path::createFileOnDisk(std::string* ErrMsg) {
634
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
635
FILE_ATTRIBUTE_NORMAL, NULL);
636
if (h == INVALID_HANDLE_VALUE)
637
return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
644
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
645
WIN32_FILE_ATTRIBUTE_DATA fi;
646
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
649
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
650
// If it doesn't exist, we're done.
654
char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
655
int lastchar = path.length() - 1 ;
656
path.copy(pathname, lastchar+1);
658
// Make path end with '/*'.
659
if (pathname[lastchar] != '/')
660
pathname[++lastchar] = '/';
661
pathname[lastchar+1] = '*';
662
pathname[lastchar+2] = 0;
664
if (remove_contents) {
666
HANDLE h = FindFirstFile(pathname, &fd);
668
// It's a bad idea to alter the contents of a directory while enumerating
669
// its contents. So build a list of its contents first, then destroy them.
671
if (h != INVALID_HANDLE_VALUE) {
672
std::vector<Path> list;
675
if (strcmp(fd.cFileName, ".") == 0)
677
if (strcmp(fd.cFileName, "..") == 0)
681
aPath.appendComponent(&fd.cFileName[0]);
682
list.push_back(aPath);
683
} while (FindNextFile(h, &fd));
685
DWORD err = GetLastError();
687
if (err != ERROR_NO_MORE_FILES) {
689
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
692
for (std::vector<Path>::iterator I = list.begin(); I != list.end();
695
aPath.eraseFromDisk(true);
698
if (GetLastError() != ERROR_FILE_NOT_FOUND)
699
return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
703
pathname[lastchar] = 0;
704
if (!RemoveDirectory(pathname))
705
return MakeErrMsg(ErrStr,
706
std::string(pathname) + ": Can't destroy directory: ");
709
// Read-only files cannot be deleted on Windows. Must remove the read-only
711
if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
712
if (!SetFileAttributes(path.c_str(),
713
fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
714
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
717
if (!DeleteFile(path.c_str()))
718
return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
723
bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
724
assert(len < 1024 && "Request for magic string too long");
725
char* buf = reinterpret_cast<char*>(alloca(len));
727
HANDLE h = CreateFile(path.c_str(),
732
FILE_ATTRIBUTE_NORMAL,
734
if (h == INVALID_HANDLE_VALUE)
738
BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
741
if (!ret || nRead != len)
744
Magic = std::string(buf, len);
749
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
750
if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
751
return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
757
Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
758
// FIXME: should work on directories also.
763
HANDLE h = CreateFile(path.c_str(),
764
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
765
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
768
FILE_ATTRIBUTE_NORMAL,
770
if (h == INVALID_HANDLE_VALUE)
773
BY_HANDLE_FILE_INFORMATION bhfi;
774
if (!GetFileInformationByHandle(h, &bhfi)) {
775
DWORD err = GetLastError();
778
return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
782
ui.QuadPart = si.modTime.toWin32Time();
784
ft.dwLowDateTime = ui.LowPart;
785
ft.dwHighDateTime = ui.HighPart;
786
BOOL ret = SetFileTime(h, NULL, &ft, &ft);
787
DWORD err = GetLastError();
791
return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
794
// Best we can do with Unix permission bits is to interpret the owner
796
if (si.mode & 0200) {
797
if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
798
if (!SetFileAttributes(path.c_str(),
799
bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
800
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
803
if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
804
if (!SetFileAttributes(path.c_str(),
805
bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
806
return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
814
CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
815
// Can't use CopyFile macro defined in Windows.h because it would mess up the
816
// above line. We use the expansion it would have in a non-UNICODE build.
817
if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
818
return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
819
"' to '" + Dest.str() + "': ");
824
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
825
if (reuse_current && !exists())
826
return false; // File doesn't exist already, just use it!
828
// Reserve space for -XXXXXX at the end.
829
char *FNBuffer = (char*) alloca(path.size()+8);
830
unsigned offset = path.size();
831
path.copy(FNBuffer, offset);
833
// Find a numeric suffix that isn't used by an existing file. Assume there
834
// won't be more than 1 million files with the same prefix. Probably a safe
836
static unsigned FCounter = 0;
838
sprintf(FNBuffer+offset, "-%06u", FCounter);
839
if (++FCounter > 999999)
847
Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
848
// Make this into a unique file name
849
makeUnique(reuse_current, ErrMsg);
851
// Now go and create it
852
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
853
FILE_ATTRIBUTE_NORMAL, NULL);
854
if (h == INVALID_HANDLE_VALUE)
855
return MakeErrMsg(ErrMsg, path + ": can't create file");
861
/// MapInFilePages - Not yet implemented on win32.
862
const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
866
/// MapInFilePages - Not yet implemented on win32.
867
void Path::UnMapFilePages(const char *Base, uint64_t FileSize) {
868
assert(0 && "NOT IMPLEMENTED");