1 //===- llvm/System/Linux/Path.cpp - Linux Path Implementation ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source 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 //===----------------------------------------------------------------------===//
25 // We need to undo a macro defined in Windows.h, otherwise we won't compile:
28 static void FlipBackSlashes(std::string& s) {
29 for (size_t i = 0; i < s.size(); i++)
38 Path::isValid() const {
42 // If there is a colon, it must be the second character, preceded by a letter
43 // and followed by something.
44 size_t len = path.size();
45 size_t pos = path.rfind(':',len);
47 if (pos != std::string::npos) {
48 if (pos != 1 || !isalpha(path[0]) || len < 3)
53 // Look for a UNC path, and if found adjust our notion of the root slash.
54 if (len > 3 && path[0] == '/' && path[1] == '/') {
55 rootslash = path.find('/', 2);
56 if (rootslash == std::string::npos)
60 // Check for illegal characters.
61 if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
62 "\013\014\015\016\017\020\021\022\023\024\025\026"
63 "\027\030\031\032\033\034\035\036\037")
67 // Remove trailing slash, unless it's a root slash.
68 if (len > rootslash+1 && path[len-1] == '/')
71 // Check each component for legality.
72 for (pos = 0; pos < len; ++pos) {
73 // A component may not end in a space.
74 if (path[pos] == ' ') {
75 if (path[pos+1] == '/' || path[pos+1] == '\0')
79 // A component may not end in a period.
80 if (path[pos] == '.') {
81 if (path[pos+1] == '/' || path[pos+1] == '\0') {
82 // Unless it is the pseudo-directory "."...
83 if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
86 if (pos > 0 && path[pos-1] == '.') {
87 if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
98 static Path *TempDirectory = NULL;
101 Path::GetTemporaryDirectory() {
103 return *TempDirectory;
105 char pathname[MAX_PATH];
106 if (!GetTempPath(MAX_PATH, pathname))
107 throw std::string("Can't determine temporary directory");
110 result.set(pathname);
112 // Append a subdirectory passed on our process id so multiple LLVMs don't
113 // step on each other's toes.
114 sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
115 result.appendComponent(pathname);
117 // If there's a directory left over from a previous LLVM execution that
118 // happened to have the same process id, get rid of it.
119 result.eraseFromDisk(true);
121 // And finally (re-)create the empty directory.
122 result.createDirectoryOnDisk(false);
123 TempDirectory = new Path(result);
124 return *TempDirectory;
127 Path::Path(const std::string& unverified_path)
128 : path(unverified_path)
130 FlipBackSlashes(path);
131 if (unverified_path.empty())
137 throw std::string(unverified_path + ": path is not valid");
140 // FIXME: the following set of functions don't map to Windows very well.
142 Path::GetRootDirectory() {
148 static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
149 const char* at = path;
150 const char* delim = strchr(at, ';');
153 std::string tmp(at, size_t(delim-at));
154 if (tmpPath.set(tmp))
155 if (tmpPath.canRead())
156 Paths.push_back(tmpPath);
158 delim = strchr(at, ';');
162 if (tmpPath.set(std::string(at)))
163 if (tmpPath.canRead())
164 Paths.push_back(tmpPath);
168 Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
169 Paths.push_back(sys::Path("C:\\WINDOWS\\SYSTEM32"));
170 Paths.push_back(sys::Path("C:\\WINDOWS"));
174 Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
175 char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
177 getPathList(env_var,Paths);
182 if (tmpPath.set(LLVM_LIBDIR))
183 if (tmpPath.canRead())
184 Paths.push_back(tmpPath);
187 GetSystemLibraryPaths(Paths);
191 Path::GetLLVMDefaultConfigDir() {
192 // TODO: this isn't going to fly on Windows
193 return Path("/etc/llvm");
197 Path::GetUserHomeDirectory() {
198 // TODO: Typical Windows setup doesn't define HOME.
199 const char* home = getenv("HOME");
202 if (result.set(home))
205 return GetRootDirectory();
207 // FIXME: the above set of functions don't map to Windows very well.
210 Path::isFile() const {
211 return !isDirectory();
215 Path::isDirectory() const {
216 WIN32_FILE_ATTRIBUTE_DATA fi;
217 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
218 ThrowError(std::string(path) + ": Can't get status: ");
219 return fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
223 Path::isHidden() const {
224 WIN32_FILE_ATTRIBUTE_DATA fi;
225 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
226 ThrowError(std::string(path) + ": Can't get status: ");
227 return fi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN;
231 Path::getBasename() const {
232 // Find the last slash
233 size_t slash = path.rfind('/');
234 if (slash == std::string::npos)
239 return path.substr(slash, path.rfind('.'));
242 bool Path::hasMagicNumber(const std::string &Magic) const {
243 std::string actualMagic;
244 if (getMagicNumber(actualMagic, Magic.size()))
245 return Magic == actualMagic;
250 Path::isBytecodeFile() const {
251 std::string actualMagic;
252 if (!getMagicNumber(actualMagic, 4))
254 return actualMagic == "llvc" || actualMagic == "llvm";
258 Path::exists() const {
259 DWORD attr = GetFileAttributes(path.c_str());
260 return attr != INVALID_FILE_ATTRIBUTES;
264 Path::canRead() const {
265 // FIXME: take security attributes into account.
266 DWORD attr = GetFileAttributes(path.c_str());
267 return attr != INVALID_FILE_ATTRIBUTES;
271 Path::canWrite() const {
272 // FIXME: take security attributes into account.
273 DWORD attr = GetFileAttributes(path.c_str());
274 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
278 Path::canExecute() const {
279 // FIXME: take security attributes into account.
280 DWORD attr = GetFileAttributes(path.c_str());
281 return attr != INVALID_FILE_ATTRIBUTES;
285 Path::getLast() const {
286 // Find the last slash
287 size_t pos = path.rfind('/');
289 // Handle the corner cases
290 if (pos == std::string::npos)
293 // If the last character is a slash, we have a root directory
294 if (pos == path.length()-1)
297 // Return everything after the last slash
298 return path.substr(pos+1);
302 Path::getStatusInfo(StatusInfo& info) const {
303 WIN32_FILE_ATTRIBUTE_DATA fi;
304 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
305 ThrowError(std::string(path) + ": Can't get status: ");
307 info.fileSize = fi.nFileSizeHigh;
308 info.fileSize <<= 32;
309 info.fileSize += fi.nFileSizeLow;
311 info.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
312 info.user = 9999; // Not applicable to Windows, so...
313 info.group = 9999; // Not applicable to Windows, so...
315 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
316 info.modTime.fromWin32Time(ft);
318 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
321 static bool AddPermissionBits(const std::string& Filename, int bits) {
322 DWORD attr = GetFileAttributes(Filename.c_str());
324 // If it doesn't exist, we're done.
325 if (attr == INVALID_FILE_ATTRIBUTES)
328 // The best we can do to interpret Unix permission bits is to use
329 // the owner writable bit.
330 if ((attr & FILE_ATTRIBUTE_READONLY) && (bits & 0200)) {
331 if (!SetFileAttributes(Filename.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
332 ThrowError(Filename + ": SetFileAttributes: ");
337 void Path::makeReadableOnDisk() {
338 // All files are readable on Windows (ignoring security attributes).
341 void Path::makeWriteableOnDisk() {
342 DWORD attr = GetFileAttributes(path.c_str());
344 // If it doesn't exist, we're done.
345 if (attr == INVALID_FILE_ATTRIBUTES)
348 if (attr & FILE_ATTRIBUTE_READONLY) {
349 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
350 ThrowError(std::string(path) + ": Can't make file writable: ");
354 void Path::makeExecutableOnDisk() {
355 // All files are executable on Windows (ignoring security attributes).
359 Path::getDirectoryContents(std::set<Path>& result) const {
365 std::string searchpath = path;
366 if (path.size() == 0 || searchpath[path.size()-1] == '/')
372 HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
373 if (h == INVALID_HANDLE_VALUE) {
374 if (GetLastError() == ERROR_FILE_NOT_FOUND)
375 return true; // not really an error, now is it?
376 ThrowError(path + ": Can't read directory: ");
380 if (fd.cFileName[0] == '.')
383 aPath.appendComponent(&fd.cFileName[0]);
384 result.insert(aPath);
385 } while (FindNextFile(h, &fd));
387 DWORD err = GetLastError();
389 if (err != ERROR_NO_MORE_FILES) {
391 ThrowError(path + ": Can't read directory: ");
397 Path::set(const std::string& a_path) {
398 if (a_path.size() == 0)
400 std::string save(path);
402 FlipBackSlashes(path);
411 Path::appendComponent(const std::string& name) {
414 std::string save(path);
416 size_t last = path.size() - 1;
417 if (path[last] != '/')
429 Path::eraseComponent() {
430 size_t slashpos = path.rfind('/',path.size());
431 if (slashpos == path.size() - 1 || slashpos == std::string::npos)
433 path.erase(slashpos);
438 Path::appendSuffix(const std::string& suffix) {
439 std::string save(path);
450 Path::eraseSuffix() {
451 size_t dotpos = path.rfind('.',path.size());
452 size_t slashpos = path.rfind('/',path.size());
453 if (dotpos != std::string::npos) {
454 if (slashpos == std::string::npos || dotpos > slashpos) {
455 path.erase(dotpos, path.size()-dotpos);
463 Path::createDirectoryOnDisk(bool create_parents) {
464 // Get a writeable copy of the path name
465 size_t len = path.length();
466 char *pathname = reinterpret_cast<char *>(_alloca(len+2));
467 path.copy(pathname, len);
470 // Make sure it ends with a slash.
471 if (len == 0 || pathname[len - 1] != '/') {
476 // Determine starting point for initial / search.
477 char *next = pathname;
478 if (pathname[0] == '/' && pathname[1] == '/') {
480 next = strchr(pathname+2, '/');
482 throw std::string(pathname) + ": badly formed remote directory";
484 next = strchr(next+1, '/');
486 throw std::string(pathname) + ": badly formed remote directory";
489 throw std::string(pathname) + ": badly formed remote directory";
491 if (pathname[1] == ':')
492 next += 2; // skip drive letter
494 next++; // skip root directory
497 // If we're supposed to create intermediate directories
498 if (create_parents) {
499 // Loop through the directory components until we're done
501 next = strchr(next, '/');
503 if (!CreateDirectory(pathname, NULL))
504 ThrowError(std::string(pathname) + ": Can't create directory: ");
508 // Drop trailing slash.
510 if (!CreateDirectory(pathname, NULL)) {
511 ThrowError(std::string(pathname) + ": Can't create directory: ");
518 Path::createFileOnDisk() {
520 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
521 FILE_ATTRIBUTE_NORMAL, NULL);
522 if (h == INVALID_HANDLE_VALUE)
523 ThrowError(path + ": Can't create file: ");
530 Path::eraseFromDisk(bool remove_contents) const {
532 DWORD attr = GetFileAttributes(path.c_str());
534 // If it doesn't exist, we're done.
535 if (attr == INVALID_FILE_ATTRIBUTES)
538 // Read-only files cannot be deleted on Windows. Must remove the read-only
540 if (attr & FILE_ATTRIBUTE_READONLY) {
541 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
542 ThrowError(path + ": Can't destroy file: ");
545 if (!DeleteFile(path.c_str()))
546 ThrowError(path + ": Can't destroy file: ");
548 } else /* isDirectory() */ {
549 // If it doesn't exist, we're done.
553 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
554 int lastchar = path.length() - 1 ;
555 path.copy(pathname, lastchar+1);
557 // Make path end with '/*'.
558 if (pathname[lastchar] != '/')
559 pathname[++lastchar] = '/';
560 pathname[lastchar+1] = '*';
561 pathname[lastchar+2] = 0;
563 if (remove_contents) {
565 HANDLE h = FindFirstFile(pathname, &fd);
567 // It's a bad idea to alter the contents of a directory while enumerating
568 // its contents. So build a list of its contents first, then destroy them.
570 if (h != INVALID_HANDLE_VALUE) {
571 std::vector<Path> list;
574 if (strcmp(fd.cFileName, ".") == 0)
576 if (strcmp(fd.cFileName, "..") == 0)
580 aPath.appendComponent(&fd.cFileName[0]);
581 list.push_back(aPath);
582 } while (FindNextFile(h, &fd));
584 DWORD err = GetLastError();
586 if (err != ERROR_NO_MORE_FILES) {
588 ThrowError(path + ": Can't read directory: ");
591 for (std::vector<Path>::iterator I = list.begin(); I != list.end();
594 aPath.eraseFromDisk(true);
597 if (GetLastError() != ERROR_FILE_NOT_FOUND)
598 ThrowError(path + ": Can't read directory: ");
602 pathname[lastchar] = 0;
603 if (!RemoveDirectory(pathname))
604 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
609 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
612 assert(len < 1024 && "Request for magic string too long");
613 char* buf = (char*) alloca(1 + len);
615 HANDLE h = CreateFile(path.c_str(),
620 FILE_ATTRIBUTE_NORMAL,
622 if (h == INVALID_HANDLE_VALUE)
626 BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
629 if (!ret || nRead != len)
638 Path::renamePathOnDisk(const Path& newName) {
639 if (!MoveFile(path.c_str(), newName.c_str()))
640 ThrowError("Can't move '" + path +
641 "' to '" + newName.path + "': ");
646 Path::setStatusInfoOnDisk(const StatusInfo& si) const {
647 if (!isFile()) return false;
649 HANDLE h = CreateFile(path.c_str(),
650 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
651 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
654 FILE_ATTRIBUTE_NORMAL,
656 if (h == INVALID_HANDLE_VALUE)
659 BY_HANDLE_FILE_INFORMATION bhfi;
660 if (!GetFileInformationByHandle(h, &bhfi)) {
661 DWORD err = GetLastError();
664 ThrowError(path + ": GetFileInformationByHandle: ");
668 (uint64_t&)ft = si.modTime.toWin32Time();
669 BOOL ret = SetFileTime(h, NULL, &ft, &ft);
670 DWORD err = GetLastError();
674 ThrowError(path + ": SetFileTime: ");
677 // Best we can do with Unix permission bits is to interpret the owner
679 if (si.mode & 0200) {
680 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
681 if (!SetFileAttributes(path.c_str(),
682 bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
683 ThrowError(path + ": SetFileAttributes: ");
686 if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
687 if (!SetFileAttributes(path.c_str(),
688 bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
689 ThrowError(path + ": SetFileAttributes: ");
697 sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) {
698 // Can't use CopyFile macro defined in Windows.h because it would mess up the
699 // above line. We use the expansion it would have in a non-UNICODE build.
700 if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
701 ThrowError("Can't copy '" + Src.toString() +
702 "' to '" + Dest.toString() + "': ");
706 Path::makeUnique(bool reuse_current) {
707 if (reuse_current && !exists())
708 return; // File doesn't exist already, just use it!
710 // Reserve space for -XXXXXX at the end.
711 char *FNBuffer = (char*) alloca(path.size()+8);
712 unsigned offset = path.size();
713 path.copy(FNBuffer, offset);
715 // Find a numeric suffix that isn't used by an existing file.
716 static unsigned FCounter = 0;
718 sprintf(FNBuffer+offset, "-%06u", FCounter);
719 if (++FCounter > 999999)
726 Path::createTemporaryFileOnDisk(bool reuse_current) {
727 // Make this into a unique file name
728 makeUnique( reuse_current );
730 // Now go and create it
731 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
732 FILE_ATTRIBUTE_NORMAL, NULL);
733 if (h == INVALID_HANDLE_VALUE)