-//===- llvm/System/Linux/Path.cpp - Linux Path Implementation ---*- C++ -*-===//
+//===- llvm/System/Win32/Path.cpp - Win32 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.
+// This file 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.
#include "Win32.h"
#include <malloc.h>
+#include <cstdio>
// We need to undo a macro defined in Windows.h, otherwise we won't compile:
#undef CopyFile
+#undef GetCurrentDirectory
// Windows happily accepts either forward or backward slashes, though any path
// returned by a Win32 API will have backward slashes. As LLVM code basically
namespace llvm {
namespace sys {
+const char PathSeparator = ';';
+
+Path::Path(const std::string& p)
+ : path(p) {
+ FlipBackSlashes(path);
+}
+
+Path::Path(const char *StrStart, unsigned StrLen)
+ : path(StrStart, StrLen) {
+ FlipBackSlashes(path);
+}
+
+Path&
+Path::operator=(const std::string &that) {
+ path = that;
+ FlipBackSlashes(path);
+ return *this;
+}
bool
Path::isValid() const {
return true;
}
+bool
+Path::isAbsolute(const char *NameStart, unsigned NameLen) {
+ assert(NameStart);
+ switch (NameLen) {
+ case 0:
+ return false;
+ case 1:
+ case 2:
+ return NameStart[0] == '/';
+ default:
+ return NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/');
+ }
+}
+
+bool
+Path::isAbsolute() const {
+ switch (path.length()) {
+ case 0:
+ return false;
+ case 1:
+ case 2:
+ return path[0] == '/';
+ default:
+ return path[0] == '/' || (path[1] == ':' && path[2] == '/');
+ }
+}
+
static Path *TempDirectory = NULL;
Path
-Path::GetTemporaryDirectory() {
+Path::GetTemporaryDirectory(std::string* ErrMsg) {
if (TempDirectory)
return *TempDirectory;
char pathname[MAX_PATH];
- if (!GetTempPath(MAX_PATH, pathname))
- throw std::string("Can't determine temporary directory");
+ if (!GetTempPath(MAX_PATH, pathname)) {
+ if (ErrMsg)
+ *ErrMsg = "Can't determine temporary directory";
+ return Path();
+ }
Path result;
result.set(pathname);
// Append a subdirectory passed on our process id so multiple LLVMs don't
// step on each other's toes.
+#ifdef __MINGW32__
+ // Mingw's Win32 header files are broken.
sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
+#else
+ sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
+#endif
result.appendComponent(pathname);
// If there's a directory left over from a previous LLVM execution that
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() {
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.set(tmp))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
- at = delim + 1;
- delim = strchr(at, ';');
- }
-
- if (*at != 0)
- if (tmpPath.set(std::string(at)))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
-}
-
void
Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
Paths.push_back(sys::Path("C:/WINDOWS/SYSTEM32"));
}
void
-Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) {
+Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
if (env_var != 0) {
getPathList(env_var,Paths);
}
return GetRootDirectory();
}
-// FIXME: the above set of functions don't map to Windows very well.
-bool
-Path::isFile() const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- BOOL rc = GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi);
- if (rc)
- return !(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
- else if (GetLastError() != ERROR_FILE_NOT_FOUND) {
- ThrowError("isFile(): " + std::string(path) + ": Can't get status: ");
- }
- return false;
+Path
+Path::GetCurrentDirectory() {
+ char pathname[MAX_PATH];
+ ::GetCurrentDirectoryA(MAX_PATH,pathname);
+ return Path(pathname);
}
-bool
-Path::isDirectory() const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- BOOL rc = GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi);
- if (rc)
- return fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- else if (GetLastError() != ERROR_FILE_NOT_FOUND)
- ThrowError("isDirectory(): " + std::string(path) + ": Can't get status: ");
- return false;
+/// GetMainExecutable - Return the path to the main executable, given the
+/// value of argv[0] from program startup.
+Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
+ char pathname[MAX_PATH];
+ DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
+ return ret != MAX_PATH ? Path(pathname) : Path();
}
-bool
-Path::isHidden() const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- BOOL rc = GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi);
- if (rc)
- return fi.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN;
- else if (GetLastError() != ERROR_FILE_NOT_FOUND)
- ThrowError("isHidden(): " + std::string(path) + ": Can't get status: ");
- return false;
-}
+
+// FIXME: the above set of functions don't map to Windows very well.
+
bool
Path::isRootDirectory() const {
return len > 0 && path[len-1] == '/';
}
+std::string Path::getDirname() const {
+ return getDirnameCharSep(path, '/');
+}
+
std::string
Path::getBasename() const {
// Find the last slash
return path.substr(slash, dot - slash);
}
-bool Path::hasMagicNumber(const std::string &Magic) const {
- std::string actualMagic;
- if (getMagicNumber(actualMagic, Magic.size()))
- return Magic == actualMagic;
- return false;
-}
+std::string
+Path::getSuffix() const {
+ // Find the last slash
+ size_t slash = path.rfind('/');
+ if (slash == std::string::npos)
+ slash = 0;
+ else
+ slash++;
-bool
-Path::isBytecodeFile() const {
- if (!isFile())
- return false;
- std::string actualMagic;
- if (!getMagicNumber(actualMagic, 4))
- return false;
- return actualMagic == "llvc" || actualMagic == "llvm";
+ size_t dot = path.rfind('.');
+ if (dot == std::string::npos || dot < slash)
+ return std::string();
+ else
+ return path.substr(dot + 1);
}
bool
return attr != INVALID_FILE_ATTRIBUTES;
}
+bool
+Path::isDirectory() const {
+ DWORD attr = GetFileAttributes(path.c_str());
+ return (attr != INVALID_FILE_ATTRIBUTES) &&
+ (attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
bool
Path::canRead() const {
// FIXME: take security attributes into account.
return path.substr(pos+1);
}
-bool
-Path::getStatusInfo(FileStatus &info, std::string *ErrStr) const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
- return GetError("getStatusInfo():" + std::string(path) +
- ": Can't get status: ", ErrStr);
-
- info.fileSize = fi.nFileSizeHigh;
- info.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
- 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...
+const FileStatus *
+PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
+ if (!fsIsValid || update) {
+ WIN32_FILE_ATTRIBUTE_DATA fi;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
+ MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
+ ": Can't get status: ");
+ return 0;
+ }
- __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
- info.modTime.fromWin32Time(ft);
+ status.fileSize = fi.nFileSizeHigh;
+ status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
+ status.fileSize += fi.nFileSizeLow;
- info.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- return false;
-}
+ status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
+ status.user = 9999; // Not applicable to Windows, so...
+ status.group = 9999; // Not applicable to Windows, so...
-static bool AddPermissionBits(const std::string& Filename, int bits) {
- DWORD attr = GetFileAttributes(Filename.c_str());
+ // FIXME: this is only unique if the file is accessed by the same file path.
+ // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
+ // numbers, but the concept doesn't exist in Windows.
+ status.uniqueID = 0;
+ for (unsigned i = 0; i < path.length(); ++i)
+ status.uniqueID += path[i];
- // If it doesn't exist, we're done.
- if (attr == INVALID_FILE_ATTRIBUTES)
- return false;
+ __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime);
+ status.modTime.fromWin32Time(ft);
- // 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: ");
+ status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ fsIsValid = true;
}
- return true;
+ return &status;
}
-void Path::makeReadableOnDisk() {
+bool Path::makeReadableOnDisk(std::string* ErrMsg) {
// All files are readable on Windows (ignoring security attributes).
+ return false;
}
-void Path::makeWriteableOnDisk() {
+bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
DWORD attr = GetFileAttributes(path.c_str());
// If it doesn't exist, we're done.
if (attr == INVALID_FILE_ATTRIBUTES)
- return;
+ return false;
if (attr & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY))
- ThrowError(std::string(path) + ": Can't make file writable: ");
+ if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
+ MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
+ return true;
+ }
}
+ return false;
}
-void Path::makeExecutableOnDisk() {
+bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
// All files are executable on Windows (ignoring security attributes).
+ return false;
}
bool
-Path::getDirectoryContents(std::set<Path>& result) const {
- if (!isDirectory())
- return false;
+Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
+ WIN32_FILE_ATTRIBUTE_DATA fi;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
+ MakeErrMsg(ErrMsg, path + ": can't get status of file");
+ return true;
+ }
+
+ if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ if (ErrMsg)
+ *ErrMsg = path + ": not a directory";
+ return true;
+ }
result.clear();
WIN32_FIND_DATA fd;
if (h == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND)
return true; // not really an error, now is it?
- ThrowError(path + ": Can't read directory: ");
+ MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
+ return true;
}
do {
FindClose(h);
if (err != ERROR_NO_MORE_FILES) {
SetLastError(err);
- ThrowError(path + ": Can't read directory: ");
+ MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
+ return true;
}
- return true;
+ return false;
}
bool
Path::set(const std::string& a_path) {
- if (a_path.size() == 0)
+ if (a_path.empty())
return false;
std::string save(path);
path = a_path;
return false;
}
+inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
+ if (ErrMsg)
+ *ErrMsg = std::string(pathname) + ": " + std::string(msg);
+ return true;
+}
+
bool
-Path::createDirectoryOnDisk(bool create_parents) {
+Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
// Get a writeable copy of the path name
size_t len = path.length();
char *pathname = reinterpret_cast<char *>(_alloca(len+2));
// Skip host name.
next = strchr(pathname+2, '/');
if (next == NULL)
- throw std::string(pathname) + ": badly formed remote directory";
+ return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+
// Skip share name.
next = strchr(next+1, '/');
if (next == NULL)
- throw std::string(pathname) + ": badly formed remote directory";
+ return PathMsg(ErrMsg, pathname,"badly formed remote directory");
+
next++;
if (*next == 0)
- throw std::string(pathname) + ": badly formed remote directory";
+ return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+
} else {
if (pathname[1] == ':')
next += 2; // skip drive letter
next = strchr(next, '/');
*next = 0;
if (!CreateDirectory(pathname, NULL))
- ThrowError(std::string(pathname) + ": Can't create directory: ");
+ return MakeErrMsg(ErrMsg,
+ std::string(pathname) + ": Can't create directory: ");
*next++ = '/';
}
} else {
// Drop trailing slash.
pathname[len-1] = 0;
if (!CreateDirectory(pathname, NULL)) {
- ThrowError(std::string(pathname) + ": Can't create directory: ");
+ return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: ");
}
}
- return true;
+ return false;
}
bool
-Path::createFileOnDisk() {
+Path::createFileOnDisk(std::string* ErrMsg) {
// 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: ");
+ return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
CloseHandle(h);
- return true;
+ return false;
}
bool
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- if (isFile()) {
- DWORD attr = GetFileAttributes(path.c_str());
-
- // If it doesn't exist, we're done.
- if (attr == INVALID_FILE_ATTRIBUTES)
- return false;
-
- // 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))
- return GetError(path + ": Can't destroy file: ", ErrStr);
- }
-
- if (!DeleteFile(path.c_str()))
- ThrowError(path + ": Can't destroy file: ");
+ WIN32_FILE_ATTRIBUTE_DATA fi;
+ if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
return true;
- } else if (isDirectory()) {
+
+ if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// If it doesn't exist, we're done.
if (!exists())
return false;
FindClose(h);
if (err != ERROR_NO_MORE_FILES) {
SetLastError(err);
- return GetError(path + ": Can't read directory: ", ErrStr);
+ return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
}
for (std::vector<Path>::iterator I = list.begin(); I != list.end();
}
} else {
if (GetLastError() != ERROR_FILE_NOT_FOUND)
- return GetError(path + ": Can't read directory: ", ErrStr);
+ return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
}
}
pathname[lastchar] = 0;
if (!RemoveDirectory(pathname))
- return GetError(std::string(pathname) + ": Can't destroy directory: ",
- ErrStr);
+ return MakeErrMsg(ErrStr,
+ std::string(pathname) + ": Can't destroy directory: ");
return false;
} else {
- // It appears the path doesn't exist.
- return true;
+ // Read-only files cannot be deleted on Windows. Must remove the read-only
+ // attribute first.
+ if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ if (!SetFileAttributes(path.c_str(),
+ fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
+ return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
+ }
+
+ if (!DeleteFile(path.c_str()))
+ return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
+ return false;
}
}
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);
}
bool
-Path::renamePathOnDisk(const Path& newName) {
+Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
- ThrowError("Can't move '" + path +
- "' to '" + newName.path + "': ");
- return true;
+ return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
+ + "': ");
+ return false;
}
bool
-Path::setStatusInfoOnDisk(const FileStatus &si) const {
+Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
// FIXME: should work on directories also.
- if (!isFile()) return false;
-
+ if (!si.isFile) {
+ return true;
+ }
+
HANDLE h = CreateFile(path.c_str(),
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (h == INVALID_HANDLE_VALUE)
- return false;
+ return true;
BY_HANDLE_FILE_INFORMATION bhfi;
if (!GetFileInformationByHandle(h, &bhfi)) {
DWORD err = GetLastError();
CloseHandle(h);
SetLastError(err);
- ThrowError(path + ": GetFileInformationByHandle: ");
+ return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
}
FILETIME ft;
CloseHandle(h);
if (!ret) {
SetLastError(err);
- ThrowError(path + ": SetFileTime: ");
+ return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
}
// Best we can do with Unix permission bits is to interpret the owner
if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
if (!SetFileAttributes(path.c_str(),
bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
- ThrowError(path + ": SetFileAttributes: ");
+ return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
}
} else {
if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
if (!SetFileAttributes(path.c_str(),
bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
- ThrowError(path + ": SetFileAttributes: ");
+ return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
}
}
- return true;
+ return false;
}
-void
-CopyFile(const sys::Path &Dest, const sys::Path &Src) {
+bool
+CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
// 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() +
+ return MakeErrMsg(ErrMsg, "Can't copy '" + Src.toString() +
"' to '" + Dest.toString() + "': ");
+ return false;
}
-void
-Path::makeUnique(bool reuse_current) {
+bool
+Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
if (reuse_current && !exists())
- return; // File doesn't exist already, just use it!
+ return false; // File doesn't exist already, just use it!
// Reserve space for -XXXXXX at the end.
char *FNBuffer = (char*) alloca(path.size()+8);
FCounter = 0;
path = FNBuffer;
} while (exists());
+ return false;
}
bool
-Path::createTemporaryFileOnDisk(bool reuse_current) {
+Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
// Make this into a unique file name
- makeUnique(reuse_current);
+ makeUnique(reuse_current, ErrMsg);
// Now go and create it
HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
- return false;
+ return MakeErrMsg(ErrMsg, path + ": can't create file");
CloseHandle(h);
- return true;
+ return false;
+}
+
+/// MapInFilePages - Not yet implemented on win32.
+const char *Path::MapInFilePages(int FD, uint64_t FileSize) {
+ return 0;
+}
+
+/// MapInFilePages - Not yet implemented on win32.
+void Path::UnMapFilePages(const char *Base, uint64_t FileSize) {
+ assert(0 && "NOT IMPLEMENTED");
}
}