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 {
218 WIN32_FILE_ATTRIBUTE_DATA fi;
219 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
220 ThrowError(std::string(path) + ": Can't get status: ");
221 return fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
225 Path::isHidden() const {
228 WIN32_FILE_ATTRIBUTE_DATA fi;
229 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
230 ThrowError(std::string(path) + ": Can't get status: ");
231 return fi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN;
235 Path::getBasename() const {
236 // Find the last slash
237 size_t slash = path.rfind('/');
238 if (slash == std::string::npos)
243 return path.substr(slash, path.rfind('.'));
246 bool Path::hasMagicNumber(const std::string &Magic) const {
247 std::string actualMagic;
248 if (getMagicNumber(actualMagic, Magic.size()))
249 return Magic == actualMagic;
254 Path::isBytecodeFile() const {
257 std::string actualMagic;
258 if (!getMagicNumber(actualMagic, 4))
260 return actualMagic == "llvc" || actualMagic == "llvm";
264 Path::exists() const {
265 DWORD attr = GetFileAttributes(path.c_str());
266 return attr != INVALID_FILE_ATTRIBUTES;
270 Path::canRead() const {
271 // FIXME: take security attributes into account.
272 DWORD attr = GetFileAttributes(path.c_str());
273 return attr != INVALID_FILE_ATTRIBUTES;
277 Path::canWrite() const {
278 // FIXME: take security attributes into account.
279 DWORD attr = GetFileAttributes(path.c_str());
280 return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
284 Path::canExecute() const {
285 // FIXME: take security attributes into account.
286 DWORD attr = GetFileAttributes(path.c_str());
287 return attr != INVALID_FILE_ATTRIBUTES;
291 Path::getLast() const {
292 // Find the last slash
293 size_t pos = path.rfind('/');
295 // Handle the corner cases
296 if (pos == std::string::npos)
299 // If the last character is a slash, we have a root directory
300 if (pos == path.length()-1)
303 // Return everything after the last slash
304 return path.substr(pos+1);
308 Path::getStatusInfo(StatusInfo& info) const {
309 WIN32_FILE_ATTRIBUTE_DATA fi;
310 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
311 ThrowError(std::string(path) + ": Can't get status: ");
313 info.fileSize = fi.nFileSizeHigh;
314 info.fileSize <<= 32;
315 info.fileSize += fi.nFileSizeLow;
317 info.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
318 info.user = 9999; // Not applicable to Windows, so...
319 info.group = 9999; // Not applicable to Windows, so...
321 __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
322 info.modTime.fromWin32Time(ft);
324 info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
327 static bool AddPermissionBits(const std::string& Filename, int bits) {
328 DWORD attr = GetFileAttributes(Filename.c_str());
330 // If it doesn't exist, we're done.
331 if (attr == INVALID_FILE_ATTRIBUTES)
334 // The best we can do to interpret Unix permission bits is to use
335 // the owner writable bit.
336 if ((attr & FILE_ATTRIBUTE_READONLY) && (bits & 0200)) {
337 if (!SetFileAttributes(Filename.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
338 ThrowError(Filename + ": SetFileAttributes: ");
343 void Path::makeReadableOnDisk() {
344 // All files are readable on Windows (ignoring security attributes).
347 void Path::makeWriteableOnDisk() {
348 DWORD attr = GetFileAttributes(path.c_str());
350 // If it doesn't exist, we're done.
351 if (attr == INVALID_FILE_ATTRIBUTES)
354 if (attr & FILE_ATTRIBUTE_READONLY) {
355 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
356 ThrowError(std::string(path) + ": Can't make file writable: ");
360 void Path::makeExecutableOnDisk() {
361 // All files are executable on Windows (ignoring security attributes).
365 Path::getDirectoryContents(std::set<Path>& result) const {
371 std::string searchpath = path;
372 if (path.size() == 0 || searchpath[path.size()-1] == '/')
377 HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
378 if (h == INVALID_HANDLE_VALUE) {
379 if (GetLastError() == ERROR_FILE_NOT_FOUND)
380 return true; // not really an error, now is it?
381 ThrowError(path + ": Can't read directory: ");
385 if (fd.cFileName[0] == '.')
388 aPath.appendComponent(&fd.cFileName[0]);
389 result.insert(aPath);
390 } while (FindNextFile(h, &fd));
392 DWORD err = GetLastError();
394 if (err != ERROR_NO_MORE_FILES) {
396 ThrowError(path + ": Can't read directory: ");
402 Path::set(const std::string& a_path) {
403 if (a_path.size() == 0)
405 std::string save(path);
407 FlipBackSlashes(path);
416 Path::appendComponent(const std::string& name) {
419 std::string save(path);
421 size_t last = path.size() - 1;
422 if (path[last] != '/')
434 Path::eraseComponent() {
435 size_t slashpos = path.rfind('/',path.size());
436 if (slashpos == path.size() - 1 || slashpos == std::string::npos)
438 path.erase(slashpos);
443 Path::appendSuffix(const std::string& suffix) {
444 std::string save(path);
455 Path::eraseSuffix() {
456 size_t dotpos = path.rfind('.',path.size());
457 size_t slashpos = path.rfind('/',path.size());
458 if (dotpos != std::string::npos) {
459 if (slashpos == std::string::npos || dotpos > slashpos) {
460 path.erase(dotpos, path.size()-dotpos);
468 Path::createDirectoryOnDisk(bool create_parents) {
469 // Get a writeable copy of the path name
470 size_t len = path.length();
471 char *pathname = reinterpret_cast<char *>(_alloca(len+2));
472 path.copy(pathname, len);
475 // Make sure it ends with a slash.
476 if (len == 0 || pathname[len - 1] != '/') {
481 // Determine starting point for initial / search.
482 char *next = pathname;
483 if (pathname[0] == '/' && pathname[1] == '/') {
485 next = strchr(pathname+2, '/');
487 throw std::string(pathname) + ": badly formed remote directory";
489 next = strchr(next+1, '/');
491 throw std::string(pathname) + ": badly formed remote directory";
494 throw std::string(pathname) + ": badly formed remote directory";
496 if (pathname[1] == ':')
497 next += 2; // skip drive letter
499 next++; // skip root directory
502 // If we're supposed to create intermediate directories
503 if (create_parents) {
504 // Loop through the directory components until we're done
506 next = strchr(next, '/');
508 if (!CreateDirectory(pathname, NULL))
509 ThrowError(std::string(pathname) + ": Can't create directory: ");
513 // Drop trailing slash.
515 if (!CreateDirectory(pathname, NULL)) {
516 ThrowError(std::string(pathname) + ": Can't create directory: ");
523 Path::createFileOnDisk() {
525 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
526 FILE_ATTRIBUTE_NORMAL, NULL);
527 if (h == INVALID_HANDLE_VALUE)
528 ThrowError(path + ": Can't create file: ");
535 Path::eraseFromDisk(bool remove_contents) const {
537 DWORD attr = GetFileAttributes(path.c_str());
539 // If it doesn't exist, we're done.
540 if (attr == INVALID_FILE_ATTRIBUTES)
543 // Read-only files cannot be deleted on Windows. Must remove the read-only
545 if (attr & FILE_ATTRIBUTE_READONLY) {
546 if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
547 ThrowError(path + ": Can't destroy file: ");
550 if (!DeleteFile(path.c_str()))
551 ThrowError(path + ": Can't destroy file: ");
553 } else /* isDirectory() */ {
554 // If it doesn't exist, we're done.
558 char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
559 int lastchar = path.length() - 1 ;
560 path.copy(pathname, lastchar+1);
562 // Make path end with '/*'.
563 if (pathname[lastchar] != '/')
564 pathname[++lastchar] = '/';
565 pathname[lastchar+1] = '*';
566 pathname[lastchar+2] = 0;
568 if (remove_contents) {
570 HANDLE h = FindFirstFile(pathname, &fd);
572 // It's a bad idea to alter the contents of a directory while enumerating
573 // its contents. So build a list of its contents first, then destroy them.
575 if (h != INVALID_HANDLE_VALUE) {
576 std::vector<Path> list;
579 if (strcmp(fd.cFileName, ".") == 0)
581 if (strcmp(fd.cFileName, "..") == 0)
585 aPath.appendComponent(&fd.cFileName[0]);
586 list.push_back(aPath);
587 } while (FindNextFile(h, &fd));
589 DWORD err = GetLastError();
591 if (err != ERROR_NO_MORE_FILES) {
593 ThrowError(path + ": Can't read directory: ");
596 for (std::vector<Path>::iterator I = list.begin(); I != list.end();
599 aPath.eraseFromDisk(true);
602 if (GetLastError() != ERROR_FILE_NOT_FOUND)
603 ThrowError(path + ": Can't read directory: ");
607 pathname[lastchar] = 0;
608 if (!RemoveDirectory(pathname))
609 ThrowError(std::string(pathname) + ": Can't destroy directory: ");
614 bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
617 assert(len < 1024 && "Request for magic string too long");
618 char* buf = (char*) alloca(1 + len);
620 HANDLE h = CreateFile(path.c_str(),
625 FILE_ATTRIBUTE_NORMAL,
627 if (h == INVALID_HANDLE_VALUE)
631 BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
634 if (!ret || nRead != len)
643 Path::renamePathOnDisk(const Path& newName) {
644 if (!MoveFile(path.c_str(), newName.c_str()))
645 ThrowError("Can't move '" + path +
646 "' to '" + newName.path + "': ");
651 Path::setStatusInfoOnDisk(const StatusInfo& si) const {
652 if (!isFile()) return false;
654 HANDLE h = CreateFile(path.c_str(),
655 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
656 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
659 FILE_ATTRIBUTE_NORMAL,
661 if (h == INVALID_HANDLE_VALUE)
664 BY_HANDLE_FILE_INFORMATION bhfi;
665 if (!GetFileInformationByHandle(h, &bhfi)) {
666 DWORD err = GetLastError();
669 ThrowError(path + ": GetFileInformationByHandle: ");
673 (uint64_t&)ft = si.modTime.toWin32Time();
674 BOOL ret = SetFileTime(h, NULL, &ft, &ft);
675 DWORD err = GetLastError();
679 ThrowError(path + ": SetFileTime: ");
682 // Best we can do with Unix permission bits is to interpret the owner
684 if (si.mode & 0200) {
685 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
686 if (!SetFileAttributes(path.c_str(),
687 bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
688 ThrowError(path + ": SetFileAttributes: ");
691 if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
692 if (!SetFileAttributes(path.c_str(),
693 bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
694 ThrowError(path + ": SetFileAttributes: ");
702 sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) {
703 // Can't use CopyFile macro defined in Windows.h because it would mess up the
704 // above line. We use the expansion it would have in a non-UNICODE build.
705 if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
706 ThrowError("Can't copy '" + Src.toString() +
707 "' to '" + Dest.toString() + "': ");
711 Path::makeUnique(bool reuse_current) {
712 if (reuse_current && !exists())
713 return; // File doesn't exist already, just use it!
715 // Reserve space for -XXXXXX at the end.
716 char *FNBuffer = (char*) alloca(path.size()+8);
717 unsigned offset = path.size();
718 path.copy(FNBuffer, offset);
720 // Find a numeric suffix that isn't used by an existing file.
721 static unsigned FCounter = 0;
723 sprintf(FNBuffer+offset, "-%06u", FCounter);
724 if (++FCounter > 999999)
731 Path::createTemporaryFileOnDisk(bool reuse_current) {
732 // Make this into a unique file name
733 makeUnique( reuse_current );
735 // Now go and create it
736 HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
737 FILE_ATTRIBUTE_NORMAL, NULL);
738 if (h == INVALID_HANDLE_VALUE)