-//===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
+//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
#include "Windows.h"
-#include <malloc.h>
#include <cstdio>
+#include <malloc.h>
// 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
return *this;
}
-// push_back 0 on create, and pop_back on delete.
-struct ScopedNullTerminator {
- std::string &str;
- ScopedNullTerminator(std::string &s) : str(s) { str.push_back(0); }
- ~ScopedNullTerminator() {
- // str.pop_back(); But wait, C++03 doesn't have this...
- assert(!str.empty() && str[str.size() - 1] == 0
- && "Null char not present!");
- str.resize(str.size() - 1);
- }
-};
-
bool
Path::isValid() const {
if (path.empty())
return false;
+ size_t len = path.size();
+ // If there is a null character, it and all its successors are ignored.
+ size_t pos = path.find_first_of('\0');
+ if (pos != std::string::npos)
+ len = pos;
+
// If there is a colon, it must be the second character, preceded by a letter
// and followed by something.
- size_t len = path.size();
- // This code assumes that path is null terminated, so make sure it is.
- ScopedNullTerminator snt(path);
- size_t pos = path.rfind(':',len);
+ pos = path.rfind(':',len);
size_t rootslash = 0;
if (pos != std::string::npos) {
- if (pos != 1 || !isalpha(path[0]) || len < 3)
+ if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3)
return false;
rootslash = 2;
}
for (pos = 0; pos < len; ++pos) {
// A component may not end in a space.
if (path[pos] == ' ') {
- if (path[pos+1] == '/' || path[pos+1] == '\0')
+ if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0')
return false;
}
// A component may not end in a period.
if (path[pos] == '.') {
- if (path[pos+1] == '/' || path[pos+1] == '\0') {
+ if (pos+1 == len || path[pos+1] == '/') {
// Unless it is the pseudo-directory "."...
if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
return true;
}
}
-bool
-Path::isAbsolute(const char *NameStart, unsigned NameLen) {
- assert(NameStart);
- // FIXME: This does not handle correctly an absolute path starting from
- // a drive letter or in UNC format.
- switch (NameLen) {
- case 0:
- return false;
- case 1:
- case 2:
- return NameStart[0] == '/';
- default:
- return
- (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) ||
- (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\'));
- }
-}
-
-bool
-Path::isAbsolute() const {
- // FIXME: This does not handle correctly an absolute path starting from
- // a drive letter or in UNC format.
- 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;
Path
Path::GetTemporaryDirectory(std::string* ErrMsg) {
- if (TempDirectory)
+ if (TempDirectory) {
+#if defined(_MSC_VER)
+ // Visual Studio gets confused and emits a diagnostic about calling exists,
+ // even though this is the implementation for PathV1. Temporarily
+ // disable the deprecated warning message
+ #pragma warning(push)
+ #pragma warning(disable:4996)
+#endif
+ assert(TempDirectory->exists() && "Who has removed TempDirectory?");
+#if defined(_MSC_VER)
+ #pragma warning(pop)
+#endif
return *TempDirectory;
+ }
char pathname[MAX_PATH];
if (!GetTempPath(MAX_PATH, pathname)) {
Path result;
result.set(pathname);
- // Append a subdirectory passed on our process id so multiple LLVMs don't
+ // Append a subdirectory based on our process id so multiple LLVMs don't
// step on each other's toes.
#ifdef __MINGW32__
// Mingw's Win32 header files are broken.
return *TempDirectory;
}
-// FIXME: the following set of functions don't map to Windows very well.
-Path
-Path::GetRootDirectory() {
- // This is the only notion that that Windows has of a root directory. Nothing
- // is here except for drives.
- return Path("file:///");
-}
-
-void
-Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
- char buff[MAX_PATH];
- // Generic form of C:\Windows\System32
- HRESULT res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_SYSTEM,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK) {
- assert(0 && "Failed to get system directory");
- return;
- }
- Paths.push_back(sys::Path(buff));
-
- // Reset buff.
- buff[0] = 0;
- // Generic form of C:\Windows
- res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_WINDOWS,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK) {
- assert(0 && "Failed to get windows directory");
- return;
- }
- Paths.push_back(sys::Path(buff));
-}
-
-void
-Path::GetBitcodeLibraryPaths(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.set(LLVM_LIBDIR))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
- }
-#endif
- GetSystemLibraryPaths(Paths);
-}
-
-Path
-Path::GetLLVMDefaultConfigDir() {
- Path ret = GetUserHomeDirectory();
- if (!ret.appendComponent(".llvm"))
- assert(0 && "Failed to append .llvm");
- return ret;
-}
-
-Path
-Path::GetUserHomeDirectory() {
- char buff[MAX_PATH];
- HRESULT res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_APPDATA,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK)
- assert(0 && "Failed to get user home directory");
- return Path(buff);
-}
-
Path
Path::GetCurrentDirectory() {
char pathname[MAX_PATH];
// FIXME: the above set of functions don't map to Windows very well.
-
-StringRef Path::getDirname() const {
- return getDirnameCharSep(path, "/");
-}
-
-StringRef
-Path::getBasename() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
-
- size_t dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef(path).substr(slash);
- else
- return StringRef(path).substr(slash, dot - slash);
-}
-
-StringRef
-Path::getSuffix() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
-
- size_t dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef("");
- else
- return StringRef(path).substr(dot + 1);
-}
-
bool
Path::exists() const {
DWORD attr = GetFileAttributes(path.c_str());
return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
}
-bool
-Path::canRead() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
-}
-
bool
Path::canWrite() const {
// FIXME: take security attributes into account.
bool
Path::isRegularFile() const {
- if (isDirectory())
+ bool res;
+ if (fs::is_regular_file(path, res))
return false;
- return true;
-}
-
-StringRef
-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, we have a root directory
- if (pos == path.length()-1)
- return path;
-
- // Return everything after the last slash
- return StringRef(path).substr(pos+1);
+ return res;
}
const FileStatus *
status.user = 9999; // Not applicable to Windows, so...
status.group = 9999; // Not applicable to Windows, so...
- // 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];
-
ULARGE_INTEGER ui;
ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
return false;
}
-bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
- // All files are executable on Windows (ignoring security attributes).
- return false;
-}
-
bool
Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
WIN32_FILE_ATTRIBUTE_DATA fi;
return false;
}
-bool
-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)
- return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
-
- CloseHandle(h);
- return false;
-}
-
bool
Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
WIN32_FILE_ATTRIBUTE_DATA fi;
if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// If it doesn't exist, we're done.
- if (!exists())
+ bool Exists;
+ if (fs::exists(path, Exists) || !Exists)
return false;
char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
}
}
-bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
- assert(len < 1024 && "Request for magic string too long");
- char* buf = reinterpret_cast<char*>(alloca(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;
-
- Magic = std::string(buf, len);
- return true;
-}
-
bool
Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
return false;
}
-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))
- return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
- "' to '" + Dest.str() + "': ");
- return false;
-}
-
bool
Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
- if (reuse_current && !exists())
+ bool Exists;
+ if (reuse_current && (fs::exists(path, Exists) || !Exists))
return false; // File doesn't exist already, just use it!
// Reserve space for -XXXXXX at the end.
// Find a numeric suffix that isn't used by an existing file. Assume there
// won't be more than 1 million files with the same prefix. Probably a safe
// bet.
- static unsigned FCounter = 0;
+ static int FCounter = -1;
+ if (FCounter < 0) {
+ // Give arbitrary initial seed.
+ // FIXME: We should use sys::fs::unique_file() in future.
+ LARGE_INTEGER cnt64;
+ DWORD x = GetCurrentProcessId();
+ x = (x << 16) | (x >> 16);
+ if (QueryPerformanceCounter(&cnt64)) // RDTSC
+ x ^= cnt64.HighPart ^ cnt64.LowPart;
+ FCounter = x % 1000000;
+ }
do {
sprintf(FNBuffer+offset, "-%06u", FCounter);
if (++FCounter > 999999)
FCounter = 0;
path = FNBuffer;
- } while (exists());
+ } while (!fs::exists(path, Exists) && Exists);
return false;
}
CloseHandle(h);
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");
-}
-
}
}