summaryrefslogtreecommitdiffstats
path: root/llvm/lib/System/Win32/Path.inc
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/System/Win32/Path.inc')
-rw-r--r--llvm/lib/System/Win32/Path.inc756
1 files changed, 756 insertions, 0 deletions
diff --git a/llvm/lib/System/Win32/Path.inc b/llvm/lib/System/Win32/Path.inc
new file mode 100644
index 00000000000..a8862380e9e
--- /dev/null
+++ b/llvm/lib/System/Win32/Path.inc
@@ -0,0 +1,756 @@
+//===- llvm/System/Linux/Path.cpp - Linux Path Implementation ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Reid Spencer and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+// Modified by Henrik Bach to comply with at least MinGW.
+// Ported to Win32 by Jeff Cohen.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides the Win32 specific implementation of the Path class.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//=== WARNING: Implementation here must contain only generic Win32 code that
+//=== is guaranteed to work on *all* Win32 variants.
+//===----------------------------------------------------------------------===//
+
+#include "Win32.h"
+#include <malloc.h>
+
+// We need to undo a macro defined in Windows.h, otherwise we won't compile:
+#undef CopyFile
+
+static void FlipBackSlashes(std::string& s) {
+ for (size_t i = 0; i < s.size(); i++)
+ if (s[i] == '\\')
+ s[i] = '/';
+}
+
+namespace llvm {
+namespace sys {
+
+bool
+Path::isValid() const {
+ if (path.empty())
+ return false;
+
+ // If there is a colon, it must be the second character, preceded by a letter
+ // and followed by something.
+ size_t len = path.size();
+ size_t pos = path.rfind(':',len);
+ if (pos != std::string::npos) {
+ if (pos != 1 || !isalpha(path[0]) || len < 3)
+ return false;
+ }
+
+ // Check for illegal characters.
+ if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
+ "\013\014\015\016\017\020\021\022\023\024\025\026"
+ "\027\030\031\032\033\034\035\036\037")
+ != std::string::npos)
+ return false;
+
+ // A file or directory name may not end in a period.
+ if (path[len-1] == '.')
+ return false;
+ if (len >= 2 && path[len-2] == '.' && path[len-1] == '/')
+ return false;
+
+ // A file or directory name may not end in a space.
+ if (path[len-1] == ' ')
+ return false;
+ if (len >= 2 && path[len-2] == ' ' && path[len-1] == '/')
+ return false;
+
+ return true;
+}
+
+static Path *TempDirectory = NULL;
+
+Path
+Path::GetTemporaryDirectory() {
+ if (TempDirectory)
+ return *TempDirectory;
+
+ char pathname[MAX_PATH];
+ if (!GetTempPath(MAX_PATH, pathname))
+ throw std::string("Can't determine temporary directory");
+
+ Path result;
+ result.setDirectory(pathname);
+
+ // Append a subdirectory passed on our process id so multiple LLVMs don't
+ // step on each other's toes.
+ sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
+ result.appendDirectory(pathname);
+
+ // If there's a directory left over from a previous LLVM execution that
+ // happened to have the same process id, get rid of it.
+ result.destroyDirectory(true);
+
+ // And finally (re-)create the empty directory.
+ result.createDirectory(false);
+ TempDirectory = new Path(result);
+ return *TempDirectory;
+}
+
+Path::Path(const std::string& unverified_path)
+ : path(unverified_path)
+{
+ FlipBackSlashes(path);
+ if (unverified_path.empty())
+ return;
+ if (this->isValid())
+ return;
+ // oops, not valid.
+ path.clear();
+ throw std::string(unverified_path + ": path is not valid");
+}
+
+// FIXME: the following set of functions don't map to Windows very well.
+Path
+Path::GetRootDirectory() {
+ Path result;
+ result.setDirectory("/");
+ return result;
+}
+
+static void getPathList(const char*path, std::vector<sys::Path>& Paths) {
+ const char* at = path;
+ const char* delim = strchr(at, ';');
+ Path tmpPath;
+ while( delim != 0 ) {
+ std::string tmp(at, size_t(delim-at));
+ if (tmpPath.setDirectory(tmp))
+ if (tmpPath.readable())
+ Paths.push_back(tmpPath);
+ at = delim + 1;
+ delim = strchr(at, ';');
+ }
+ if (*at != 0)
+ if (tmpPath.setDirectory(std::string(at)))
+ if (tmpPath.readable())
+ Paths.push_back(tmpPath);
+
+}
+
+void
+Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
+ Paths.push_back(sys::Path("C:\\WINDOWS\\SYSTEM32\\"));
+ Paths.push_back(sys::Path("C:\\WINDOWS\\"));
+}
+
+void
+Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
+ char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
+ if (env_var != 0) {
+ getPathList(env_var,Paths);
+ }
+#ifdef LLVM_LIBDIR
+ {
+ Path tmpPath;
+ if (tmpPath.setDirectory(LLVM_LIBDIR))
+ if (tmpPath.readable())
+ Paths.push_back(tmpPath);
+ }
+#endif
+ GetSystemLibraryPaths(Paths);
+}
+
+Path
+Path::GetLLVMDefaultConfigDir() {
+ // TODO: this isn't going to fly on Windows
+ return Path("/etc/llvm/");
+}
+
+Path
+Path::GetUserHomeDirectory() {
+ // TODO: Typical Windows setup doesn't define HOME.
+ const char* home = getenv("HOME");
+ if (home) {
+ Path result;
+ if (result.setDirectory(home))
+ return result;
+ }
+ return GetRootDirectory();
+}
+// FIXME: the above set of functions don't map to Windows very well.
+
+bool
+Path::isFile() const {
+ return (isValid() && path[path.length()-1] != '/');
+}
+
+bool
+Path::isDirectory() const {
+ return (isValid() && path[path.length()-1] == '/');
+}
+
+std::string
+Path::getBasename() const {
+ // Find the last slash
+ size_t slash = path.rfind('/');
+ if (slash == std::string::npos)
+ slash = 0;
+ else
+ slash++;
+
+ return path.substr(slash, path.rfind('.'));
+}
+
+bool Path::hasMagicNumber(const std::string &Magic) const {
+ std::string actualMagic;
+ if (getMagicNumber(actualMagic, Magic.size()))
+ return Magic == actualMagic;
+ return false;
+}
+
+bool
+Path::isBytecodeFile() const {
+ std::string actualMagic;
+ if (!getMagicNumber(actualMagic, 4))
+ return false;
+ return actualMagic == "llvc" || actualMagic == "llvm";
+}
+
+bool
+Path::exists() const {
+ DWORD attr = GetFileAttributes(path.c_str());
+ return attr != INVALID_FILE_ATTRIBUTES;
+}
+
+bool
+Path::readable() const {
+ // FIXME: take security attributes into account.
+ DWORD attr = GetFileAttributes(path.c_str());
+ return attr != INVALID_FILE_ATTRIBUTES;
+}
+
+bool
+Path::writable() const {
+ // FIXME: take security attributes into account.
+ DWORD attr = GetFileAttributes(path.c_str());
+ return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
+}
+
+bool
+Path::executable() const {
+ // FIXME: take security attributes into account.
+ DWORD attr = GetFileAttributes(path.c_str());
+ return attr != INVALID_FILE_ATTRIBUTES;
+}
+
+std::string
+Path::getLast() const {
+ // Find the last slash
+ size_t pos = path.rfind('/');
+
+ // Handle the corner cases
+ if (pos == std::string::npos)
+ return path;
+
+ // If the last character is a slash
+ if (pos == path.length()-1) {
+ // Find the second to last slash
+ size_t pos2 = path.rfind('/', pos-1);
+ if (pos2 == std::string::npos)
+ return path.substr(0,pos);
+ else
+ return path.substr(pos2+1,pos-pos2-1);
+ }
+ // Return everything after the last slash
+ return path.substr(pos+1);
+}
+
+void
+Path::getStatusInfo(StatusInfo& info) const {
+ WIN32_FILE_ATTRIBUTE_DATA fi;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
+ ThrowError(std::string(path) + ": Can't get status: ");
+
+ info.fileSize = fi.nFileSizeHigh;
+ info.fileSize <<= 32;
+ info.fileSize += fi.nFileSizeLow;
+
+ info.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
+ info.user = 9999; // Not applicable to Windows, so...
+ info.group = 9999; // Not applicable to Windows, so...
+
+ __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
+ info.modTime.fromWin32Time(ft);
+
+ info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ if (info.isDir && path[path.length() - 1] != '/')
+ path += '/';
+ else if (!info.isDir && path[path.length() - 1] == '/')
+ path.erase(path.length() - 1);
+}
+
+static bool AddPermissionBits(const std::string& Filename, int bits) {
+ DWORD attr = GetFileAttributes(Filename.c_str());
+
+ // If it doesn't exist, we're done.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return false;
+
+ // The best we can do to interpret Unix permission bits is to use
+ // the owner writable bit.
+ if ((attr & FILE_ATTRIBUTE_READONLY) && (bits & 0200)) {
+ if (!SetFileAttributes(Filename.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
+ ThrowError(Filename + ": SetFileAttributes: ");
+ }
+ return true;
+}
+
+void Path::makeReadable() {
+ // All files are readable on Windows (ignoring security attributes).
+}
+
+void Path::makeWriteable() {
+ DWORD attr = GetFileAttributes(path.c_str());
+
+ // If it doesn't exist, we're done.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return;
+
+ if (attr & FILE_ATTRIBUTE_READONLY) {
+ if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
+ ThrowError(std::string(path) + ": Can't make file writable: ");
+ }
+}
+
+void Path::makeExecutable() {
+ // All files are executable on Windows (ignoring security attributes).
+}
+
+bool
+Path::getDirectoryContents(std::set<Path>& result) const {
+ if (!isDirectory())
+ return false;
+
+ result.clear();
+ WIN32_FIND_DATA fd;
+ HANDLE h = FindFirstFile(path.c_str(), &fd);
+ if (h == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ return true; // not really an error, now is it?
+ ThrowError(path + ": Can't read directory: ");
+ }
+
+ do {
+ if (fd.cFileName[0] == '.')
+ continue;
+ Path aPath(path + &fd.cFileName[0]);
+ if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ aPath.path += "/";
+ result.insert(aPath);
+ } while (FindNextFile(h, &fd));
+
+ DWORD err = GetLastError();
+ FindClose(h);
+ if (err != ERROR_NO_MORE_FILES) {
+ SetLastError(err);
+ ThrowError(path + ": Can't read directory: ");
+ }
+ return true;
+}
+
+bool
+Path::setDirectory(const std::string& a_path) {
+ if (a_path.size() == 0)
+ return false;
+ Path save(*this);
+ path = a_path;
+ FlipBackSlashes(path);
+ size_t last = a_path.size() -1;
+ if (a_path[last] != '/')
+ path += '/';
+ if (!isValid()) {
+ path = save.path;
+ return false;
+ }
+ return true;
+}
+
+bool
+Path::setFile(const std::string& a_path) {
+ if (a_path.size() == 0)
+ return false;
+ Path save(*this);
+ path = a_path;
+ FlipBackSlashes(path);
+ size_t last = a_path.size() - 1;
+ while (last > 0 && a_path[last] == '/')
+ last--;
+ path.erase(last+1);
+ if (!isValid()) {
+ path = save.path;
+ return false;
+ }
+ return true;
+}
+
+bool
+Path::appendDirectory(const std::string& dir) {
+ if (isFile())
+ return false;
+ Path save(*this);
+ path += dir;
+ path += "/";
+ if (!isValid()) {
+ path = save.path;
+ return false;
+ }
+ return true;
+}
+
+bool
+Path::elideDirectory() {
+ if (isFile())
+ return false;
+ size_t slashpos = path.rfind('/',path.size());
+ if (slashpos == 0 || slashpos == std::string::npos)
+ return false;
+ if (slashpos == path.size() - 1)
+ slashpos = path.rfind('/',slashpos-1);
+ if (slashpos == std::string::npos)
+ return false;
+ path.erase(slashpos);
+ return true;
+}
+
+bool
+Path::appendFile(const std::string& file) {
+ if (!isDirectory())
+ return false;
+ Path save(*this);
+ path += file;
+ if (!isValid()) {
+ path = save.path;
+ return false;
+ }
+ return true;
+}
+
+bool
+Path::elideFile() {
+ if (isDirectory())
+ return false;
+ size_t slashpos = path.rfind('/',path.size());
+ if (slashpos == std::string::npos)
+ return false;
+ path.erase(slashpos+1);
+ return true;
+}
+
+bool
+Path::appendSuffix(const std::string& suffix) {
+ if (isDirectory())
+ return false;
+ Path save(*this);
+ path.append(".");
+ path.append(suffix);
+ if (!isValid()) {
+ path = save.path;
+ return false;
+ }
+ return true;
+}
+
+bool
+Path::elideSuffix() {
+ if (isDirectory()) return false;
+ size_t dotpos = path.rfind('.',path.size());
+ size_t slashpos = path.rfind('/',path.size());
+ if (slashpos != std::string::npos && dotpos != std::string::npos &&
+ dotpos > slashpos) {
+ path.erase(dotpos, path.size()-dotpos);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+Path::createDirectory( bool create_parents) {
+ // Make sure we're dealing with a directory
+ if (!isDirectory()) return false;
+
+ // Get a writeable copy of the path name
+ char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
+ path.copy(pathname,path.length());
+ pathname[path.length()] = 0;
+
+ // Determine starting point for initial / search.
+ char *next = pathname;
+ if (pathname[0] == '/' && pathname[1] == '/') {
+ // Skip host name.
+ next = strchr(pathname+2, '/');
+ if (next == NULL)
+ throw std::string(pathname) + ": badly formed remote directory";
+ // Skip share name.
+ next = strchr(next+1, '/');
+ if (next == NULL)
+ throw std::string(pathname) + ": badly formed remote directory";
+ next++;
+ if (*next == 0)
+ throw std::string(pathname) + ": badly formed remote directory";
+ } else {
+ if (pathname[1] == ':')
+ next += 2; // skip drive letter
+ if (*next == '/')
+ next++; // skip root directory
+ }
+
+ // If we're supposed to create intermediate directories
+ if (create_parents) {
+ // Loop through the directory components until we're done
+ while (*next) {
+ next = strchr(next, '/');
+ *next = 0;
+ if (!CreateDirectory(pathname, NULL))
+ ThrowError(std::string(pathname) + ": Can't create directory: ");
+ *next++ = '/';
+ }
+ } else {
+ // Drop trailing slash.
+ pathname[path.size()-1] = 0;
+ if (!CreateDirectory(pathname, NULL)) {
+ ThrowError(std::string(pathname) + ": Can't create directory: ");
+ }
+ }
+ return true;
+}
+
+bool
+Path::createFile() {
+ // Make sure we're dealing with a file
+ if (!isFile()) return false;
+
+ // Create the file
+ HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ ThrowError(path + ": Can't create file: ");
+
+ CloseHandle(h);
+ return true;
+}
+
+bool
+Path::destroyDirectory(bool remove_contents) const {
+ // Make sure we're dealing with a directory
+ if (!isDirectory()) return false;
+
+ // If it doesn't exist, we're done.
+ if (!exists()) return true;
+
+ char *pathname = reinterpret_cast<char *>(_alloca(path.length()+1));
+ path.copy(pathname,path.length()+1);
+ int lastchar = path.length() - 1 ;
+ if (pathname[lastchar] == '/')
+ pathname[lastchar] = 0;
+
+ if (remove_contents) {
+ WIN32_FIND_DATA fd;
+ HANDLE h = FindFirstFile(path.c_str(), &fd);
+
+ // It's a bad idea to alter the contents of a directory while enumerating
+ // its contents. So build a list of its contents first, then destroy them.
+
+ if (h != INVALID_HANDLE_VALUE) {
+ std::vector<Path> list;
+
+ do {
+ if (strcmp(fd.cFileName, ".") == 0)
+ continue;
+ if (strcmp(fd.cFileName, "..") == 0)
+ continue;
+
+ Path aPath(path + &fd.cFileName[0]);
+ if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ aPath.path += "/";
+ list.push_back(aPath);
+ } while (FindNextFile(h, &fd));
+
+ DWORD err = GetLastError();
+ FindClose(h);
+ if (err != ERROR_NO_MORE_FILES) {
+ SetLastError(err);
+ ThrowError(path + ": Can't read directory: ");
+ }
+
+ for (std::vector<Path>::iterator I = list.begin(); I != list.end(); ++I) {
+ Path &aPath = *I;
+ if (aPath.isDirectory())
+ aPath.destroyDirectory(true);
+ else
+ aPath.destroyFile();
+ }
+ } else {
+ if (GetLastError() != ERROR_NO_MORE_FILES)
+ ThrowError(path + ": Can't read directory: ");
+ }
+ }
+
+ if (!RemoveDirectory(pathname))
+ ThrowError(std::string(pathname) + ": Can't destroy directory: ");
+ return true;
+}
+
+bool
+Path::destroyFile() const {
+ if (!isFile()) return false;
+
+ DWORD attr = GetFileAttributes(path.c_str());
+
+ // If it doesn't exist, we're done.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return true;
+
+ // Read-only files cannot be deleted on Windows. Must remove the read-only
+ // attribute first.
+ if (attr & FILE_ATTRIBUTE_READONLY) {
+ if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
+ ThrowError(path + ": Can't destroy file: ");
+ }
+
+ if (!DeleteFile(path.c_str()))
+ ThrowError(path + ": Can't destroy file: ");
+ return true;
+}
+
+bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
+ if (!isFile())
+ return false;
+ assert(len < 1024 && "Request for magic string too long");
+ char* buf = (char*) alloca(1 + len);
+
+ HANDLE h = CreateFile(path.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ DWORD nRead = 0;
+ BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
+ CloseHandle(h);
+
+ if (!ret || nRead != len)
+ return false;
+
+ buf[len] = '\0';
+ Magic = buf;
+ return true;
+}
+
+bool
+Path::renameFile(const Path& newName) {
+ if (!isFile()) return false;
+ if (!MoveFile(path.c_str(), newName.c_str()))
+ ThrowError("Can't move '" + path +
+ "' to '" + newName.path + "': ");
+ return true;
+}
+
+bool
+Path::setStatusInfo(const StatusInfo& si) const {
+ if (!isFile()) return false;
+
+ HANDLE h = CreateFile(path.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ BY_HANDLE_FILE_INFORMATION bhfi;
+ if (!GetFileInformationByHandle(h, &bhfi)) {
+ DWORD err = GetLastError();
+ CloseHandle(h);
+ SetLastError(err);
+ ThrowError(path + ": GetFileInformationByHandle: ");
+ }
+
+ FILETIME ft;
+ (uint64_t&)ft = si.modTime.toWin32Time();
+ BOOL ret = SetFileTime(h, NULL, &ft, &ft);
+ DWORD err = GetLastError();
+ CloseHandle(h);
+ if (!ret) {
+ SetLastError(err);
+ ThrowError(path + ": SetFileTime: ");
+ }
+
+ // Best we can do with Unix permission bits is to interpret the owner
+ // writable bit.
+ if (si.mode & 0200) {
+ if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ if (!SetFileAttributes(path.c_str(),
+ bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
+ ThrowError(path + ": SetFileAttributes: ");
+ }
+ } else {
+ if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
+ if (!SetFileAttributes(path.c_str(),
+ bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
+ ThrowError(path + ": SetFileAttributes: ");
+ }
+ }
+
+ return true;
+}
+
+void
+sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) {
+ // Can't use CopyFile macro defined in Windows.h because it would mess up the
+ // above line. We use the expansion it would have in a non-UNICODE build.
+ if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
+ ThrowError("Can't copy '" + Src.toString() +
+ "' to '" + Dest.toString() + "': ");
+}
+
+void
+Path::makeUnique(bool reuse_current) {
+ if (reuse_current && !exists())
+ return; // File doesn't exist already, just use it!
+
+ Path dir (*this);
+ dir.elideFile();
+ std::string fname = this->getLast();
+
+ char newName[MAX_PATH + 1];
+ if (!GetTempFileName(dir.c_str(), fname.c_str(), 0, newName))
+ ThrowError("Cannot make unique filename for '" + path + "': ");
+
+ path = newName;
+}
+
+bool
+Path::createTemporaryFile(bool reuse_current) {
+ // Make sure we're dealing with a file
+ if (!isFile())
+ return false;
+
+ // Make this into a unique file name
+ makeUnique( reuse_current );
+ return true;
+}
+
+}
+}
+
+// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab
+
OpenPOWER on IntegriCloud