summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Support/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Support/Windows')
-rw-r--r--contrib/llvm/lib/Support/Windows/DynamicLibrary.inc15
-rw-r--r--contrib/llvm/lib/Support/Windows/Memory.inc4
-rw-r--r--contrib/llvm/lib/Support/Windows/Path.inc1712
-rw-r--r--contrib/llvm/lib/Support/Windows/PathV2.inc1022
-rw-r--r--contrib/llvm/lib/Support/Windows/Process.inc116
-rw-r--r--contrib/llvm/lib/Support/Windows/Program.inc288
-rw-r--r--contrib/llvm/lib/Support/Windows/RWMutex.inc4
-rw-r--r--contrib/llvm/lib/Support/Windows/Signals.inc56
-rw-r--r--contrib/llvm/lib/Support/Windows/TimeValue.inc38
-rw-r--r--contrib/llvm/lib/Support/Windows/Windows.h30
10 files changed, 1270 insertions, 2015 deletions
diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
index 83da82a..5a7b219 100644
--- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
+++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
@@ -71,7 +71,7 @@ extern "C" {
DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
std::string *errMsg) {
- SmartScopedLock<true> lock(getMutex());
+ SmartScopedLock<true> lock(*SymbolsMutex);
if (!filename) {
// When no file is specified, enumerate all DLLs and EXEs in the process.
@@ -83,8 +83,15 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
// This is mostly to ensure that the return value still shows up as "valid".
return DynamicLibrary(&OpenedHandles);
}
+
+ SmallVector<wchar_t, MAX_PATH> filenameUnicode;
+ if (error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) {
+ SetLastError(ec.value());
+ MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16: ");
+ return DynamicLibrary();
+ }
- HMODULE a_handle = LoadLibrary(filename);
+ HMODULE a_handle = LoadLibraryW(filenameUnicode.data());
if (a_handle == 0) {
MakeErrMsg(errMsg, std::string(filename) + ": Can't open : ");
@@ -114,10 +121,10 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
#undef EXPLICIT_SYMBOL2
void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) {
- SmartScopedLock<true> Lock(getMutex());
+ SmartScopedLock<true> Lock(*SymbolsMutex);
// First check symbols added via AddSymbol().
- if (ExplicitSymbols) {
+ if (ExplicitSymbols.isConstructed()) {
StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
if (i != ExplicitSymbols->end())
diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc
index 4c5aebd..1260452 100644
--- a/contrib/llvm/lib/Support/Windows/Memory.inc
+++ b/contrib/llvm/lib/Support/Windows/Memory.inc
@@ -82,7 +82,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
NearBlock->size()
- : NULL;
+ : 0;
// If the requested address is not aligned to the allocation granularity,
// round up to get beyond NearBlock. VirtualAlloc would have rounded down.
@@ -106,7 +106,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
MemoryBlock Result;
Result.Address = PA;
Result.Size = NumBlocks*Granularity;
- ;
+
if (Flags & MF_EXEC)
Memory::InvalidateInstructionCache(Result.Address, Result.Size);
diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc
index f4898e6..0b39198 100644
--- a/contrib/llvm/lib/Support/Windows/Path.inc
+++ b/contrib/llvm/lib/Support/Windows/Path.inc
@@ -1,4 +1,4 @@
-//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
+//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,920 +7,1116 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides the Win32 specific implementation of the Path class.
+// This file implements the Windows specific implementation of the Path API.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Win32 code that
-//=== is guaranteed to work on *all* Win32 variants.
+//=== WARNING: Implementation here must contain only generic Windows code that
+//=== is guaranteed to work on *all* Windows variants.
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "Windows.h"
-#include <cstdio>
-#include <malloc.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
-// We need to undo a macro defined in Windows.h, otherwise we won't compile:
-#undef CopyFile
-#undef GetCurrentDirectory
+#undef max
-// Windows happily accepts either forward or backward slashes, though any path
-// returned by a Win32 API will have backward slashes. As LLVM code basically
-// assumes forward slashes are used, backward slashs are converted where they
-// can be introduced into a path.
-//
-// Another invariant is that a path ends with a slash if and only if the path
-// is a root directory. Any other use of a trailing slash is stripped. Unlike
-// in Unix, Windows has a rather complicated notion of a root path and this
-// invariant helps simply the code.
-
-static void FlipBackSlashes(std::string& s) {
- for (size_t i = 0; i < s.size(); i++)
- if (s[i] == '\\')
- s[i] = '/';
-}
+// MinGW doesn't define this.
+#ifndef _ERRNO_T_DEFINED
+#define _ERRNO_T_DEFINED
+typedef int errno_t;
+#endif
-namespace llvm {
-namespace sys {
+#ifdef _MSC_VER
+# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW.
+#endif
-const char PathSeparator = ';';
+using namespace llvm;
-StringRef Path::GetEXESuffix() {
- return "exe";
-}
+using llvm::sys::windows::UTF8ToUTF16;
+using llvm::sys::windows::UTF16ToUTF8;
-Path::Path(llvm::StringRef p)
- : path(p) {
- FlipBackSlashes(path);
-}
+namespace {
+ typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
+ /*__in*/ LPCWSTR lpSymlinkFileName,
+ /*__in*/ LPCWSTR lpTargetFileName,
+ /*__in*/ DWORD dwFlags);
-Path::Path(const char *StrStart, unsigned StrLen)
- : path(StrStart, StrLen) {
- FlipBackSlashes(path);
-}
+ PtrCreateSymbolicLinkW create_symbolic_link_api =
+ PtrCreateSymbolicLinkW(::GetProcAddress(
+ ::GetModuleHandleW(L"Kernel32.dll"), "CreateSymbolicLinkW"));
-Path&
-Path::operator=(StringRef that) {
- path.assign(that.data(), that.size());
- FlipBackSlashes(path);
- return *this;
-}
+ error_code TempDir(SmallVectorImpl<wchar_t> &result) {
+ retry_temp_dir:
+ DWORD len = ::GetTempPathW(result.capacity(), result.begin());
-bool
-Path::isValid() const {
- if (path.empty())
- return false;
+ if (len == 0)
+ return windows_error(::GetLastError());
- 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.
- pos = path.rfind(':',len);
- size_t rootslash = 0;
- if (pos != std::string::npos) {
- if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3)
- return false;
- rootslash = 2;
- }
+ if (len > result.capacity()) {
+ result.reserve(len);
+ goto retry_temp_dir;
+ }
- // Look for a UNC path, and if found adjust our notion of the root slash.
- if (len > 3 && path[0] == '/' && path[1] == '/') {
- rootslash = path.find('/', 2);
- if (rootslash == std::string::npos)
- rootslash = 0;
+ result.set_size(len);
+ return error_code::success();
}
- // 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;
-
- // Remove trailing slash, unless it's a root slash.
- if (len > rootslash+1 && path[len-1] == '/')
- path.erase(--len);
-
- // Check each component for legality.
- for (pos = 0; pos < len; ++pos) {
- // A component may not end in a space.
- if (path[pos] == ' ') {
- if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0')
- return false;
+ bool is_separator(const wchar_t value) {
+ switch (value) {
+ case L'\\':
+ case L'/':
+ return true;
+ default:
+ return false;
}
+ }
+}
- // A component may not end in a period.
- if (path[pos] == '.') {
- if (pos+1 == len || path[pos+1] == '/') {
- // Unless it is the pseudo-directory "."...
- if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
- return true;
- // or "..".
- if (pos > 0 && path[pos-1] == '.') {
- if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
- return true;
- }
- return false;
+// FIXME: mode should be used here and default to user r/w only,
+// it currently comes in as a UNIX mode.
+static error_code createUniqueEntity(const Twine &model, int &result_fd,
+ SmallVectorImpl<char> &result_path,
+ bool makeAbsolute, unsigned mode,
+ FSEntity Type) {
+ // Use result_path as temp storage.
+ result_path.set_size(0);
+ StringRef m = model.toStringRef(result_path);
+
+ SmallVector<wchar_t, 128> model_utf16;
+ if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
+
+ if (makeAbsolute) {
+ // Make model absolute by prepending a temp directory if it's not already.
+ bool absolute = sys::path::is_absolute(m);
+
+ if (!absolute) {
+ SmallVector<wchar_t, 64> temp_dir;
+ if (error_code ec = TempDir(temp_dir)) return ec;
+ // Handle c: by removing it.
+ if (model_utf16.size() > 2 && model_utf16[1] == L':') {
+ model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
}
+ model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
}
}
- return true;
-}
+ // Replace '%' with random chars. From here on, DO NOT modify model. It may be
+ // needed if the randomly chosen path already exists.
+ SmallVector<wchar_t, 128> random_path_utf16;
+
+ // Get a Crypto Provider for CryptGenRandom.
+ HCRYPTPROV HCPC;
+ if (!::CryptAcquireContextW(&HCPC,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return windows_error(::GetLastError());
+ ScopedCryptContext CryptoProvider(HCPC);
+
+retry_random_path:
+ random_path_utf16.set_size(0);
+ for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
+ e = model_utf16.end();
+ i != e; ++i) {
+ if (*i == L'%') {
+ BYTE val = 0;
+ if (!::CryptGenRandom(CryptoProvider, 1, &val))
+ return windows_error(::GetLastError());
+ random_path_utf16.push_back(L"0123456789abcdef"[val & 15]);
+ }
+ else
+ random_path_utf16.push_back(*i);
+ }
+ // Make random_path_utf16 null terminated.
+ random_path_utf16.push_back(0);
+ random_path_utf16.pop_back();
+
+ HANDLE TempFileHandle = INVALID_HANDLE_VALUE;
+
+ switch (Type) {
+ case FS_File: {
+ // Try to create + open the path.
+ TempFileHandle =
+ ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, NULL,
+ // Return ERROR_FILE_EXISTS if the file
+ // already exists.
+ CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
+ if (TempFileHandle == INVALID_HANDLE_VALUE) {
+ // If the file existed, try again, otherwise, error.
+ error_code ec = windows_error(::GetLastError());
+ if (ec == windows_error::file_exists)
+ goto retry_random_path;
+
+ return ec;
+ }
-void Path::makeAbsolute() {
- TCHAR FullPath[MAX_PATH + 1] = {0};
- LPTSTR FilePart = NULL;
+ // Convert the Windows API file handle into a C-runtime handle.
+ int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
+ if (fd == -1) {
+ ::CloseHandle(TempFileHandle);
+ ::DeleteFileW(random_path_utf16.begin());
+ // MSDN doesn't say anything about _open_osfhandle setting errno or
+ // GetLastError(), so just return invalid_handle.
+ return windows_error::invalid_handle;
+ }
- DWORD RetLength = ::GetFullPathNameA(path.c_str(),
- sizeof(FullPath)/sizeof(FullPath[0]),
- FullPath, &FilePart);
+ result_fd = fd;
+ break;
+ }
- if (0 == RetLength) {
- // FIXME: Report the error GetLastError()
- assert(0 && "Unable to make absolute path!");
- } else if (RetLength > MAX_PATH) {
- // FIXME: Report too small buffer (needed RetLength bytes).
- assert(0 && "Unable to make absolute path!");
- } else {
- path = FullPath;
+ case FS_Name: {
+ DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin());
+ if (attributes != INVALID_FILE_ATTRIBUTES)
+ goto retry_random_path;
+ error_code EC = make_error_code(windows_error(::GetLastError()));
+ if (EC != windows_error::file_not_found &&
+ EC != windows_error::path_not_found)
+ return EC;
+ break;
}
-}
-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] == '\\'));
+ case FS_Dir:
+ if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) {
+ error_code EC = windows_error(::GetLastError());
+ if (EC != windows_error::already_exists)
+ return EC;
+ goto retry_random_path;
+ }
+ break;
}
-}
-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] == '/');
+ // Set result_path to the utf-8 representation of the path.
+ if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
+ random_path_utf16.size(), result_path)) {
+ switch (Type) {
+ case FS_File:
+ ::CloseHandle(TempFileHandle);
+ ::DeleteFileW(random_path_utf16.begin());
+ case FS_Name:
+ break;
+ case FS_Dir:
+ ::RemoveDirectoryW(random_path_utf16.begin());
+ break;
+ }
+ return ec;
}
+
+ return error_code::success();
}
-static Path *TempDirectory;
+namespace llvm {
+namespace sys {
+namespace fs {
-Path
-Path::GetTemporaryDirectory(std::string* ErrMsg) {
- 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;
- }
+std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
+ SmallVector<wchar_t, MAX_PATH> PathName;
+ DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
- char pathname[MAX_PATH];
- if (!GetTempPath(MAX_PATH, pathname)) {
- if (ErrMsg)
- *ErrMsg = "Can't determine temporary directory";
- return Path();
- }
+ // A zero return value indicates a failure other than insufficient space.
+ if (Size == 0)
+ return "";
- Path result;
- result.set(pathname);
+ // Insufficient space is determined by a return value equal to the size of
+ // the buffer passed in.
+ if (Size == PathName.capacity())
+ return "";
- // 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.
- 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
- // happened to have the same process id, get rid of it.
- result.eraseFromDisk(true);
-
- // And finally (re-)create the empty directory.
- result.createDirectoryOnDisk(false);
- TempDirectory = new Path(result);
- 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));
-}
+ // On success, GetModuleFileNameW returns the number of characters written to
+ // the buffer not including the NULL terminator.
+ PathName.set_size(Size);
-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);
-}
+ // Convert the result from UTF-16 to UTF-8.
+ SmallVector<char, MAX_PATH> PathNameUTF8;
+ if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8))
+ return "";
-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);
+ return std::string(PathNameUTF8.data());
}
-Path
-Path::GetCurrentDirectory() {
- char pathname[MAX_PATH];
- ::GetCurrentDirectoryA(MAX_PATH,pathname);
- return Path(pathname);
+UniqueID file_status::getUniqueID() const {
+ // The file is uniquely identified by the volume serial number along
+ // with the 64-bit file identifier.
+ uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) |
+ static_cast<uint64_t>(FileIndexLow);
+
+ return UniqueID(VolumeSerialNumber, FileID);
}
-/// 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();
+TimeValue file_status::getLastModificationTime() const {
+ ULARGE_INTEGER UI;
+ UI.LowPart = LastWriteTimeLow;
+ UI.HighPart = LastWriteTimeHigh;
+
+ TimeValue Ret;
+ Ret.fromWin32Time(UI.QuadPart);
+ return Ret;
}
+error_code current_path(SmallVectorImpl<char> &result) {
+ SmallVector<wchar_t, MAX_PATH> cur_path;
+ DWORD len = MAX_PATH;
-// FIXME: the above set of functions don't map to Windows very well.
+ do {
+ cur_path.reserve(len);
+ len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
+
+ // A zero return value indicates a failure other than insufficient space.
+ if (len == 0)
+ return windows_error(::GetLastError());
+ // If there's insufficient space, the len returned is larger than the len
+ // given.
+ } while (len > cur_path.capacity());
-StringRef Path::getDirname() const {
- return getDirnameCharSep(path, "/");
+ // On success, GetCurrentDirectoryW returns the number of characters not
+ // including the null-terminator.
+ cur_path.set_size(len);
+ return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
}
-StringRef
-Path::getBasename() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+error_code create_directory(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- 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);
-}
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
-StringRef
-Path::getSuffix() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+ if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec == windows_error::already_exists)
+ existed = true;
+ else
+ return ec;
+ } else
+ existed = false;
- size_t dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef("");
- else
- return StringRef(path).substr(dot + 1);
+ return error_code::success();
}
-bool
-Path::exists() const {
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
-}
+error_code create_hard_link(const Twine &to, const Twine &from) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
+
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-bool
-Path::isDirectory() const {
- DWORD attr = GetFileAttributes(path.c_str());
- return (attr != INVALID_FILE_ATTRIBUTES) &&
- (attr & FILE_ATTRIBUTE_DIRECTORY);
+ if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
+ return windows_error(::GetLastError());
+
+ return error_code::success();
}
-bool
-Path::isSymLink() const {
- DWORD attributes = GetFileAttributes(path.c_str());
+error_code create_symlink(const Twine &to, const Twine &from) {
+ // Only do it if the function is available at runtime.
+ if (!create_symbolic_link_api)
+ return make_error_code(errc::function_not_supported);
- if (attributes == INVALID_FILE_ATTRIBUTES)
- // There's no sane way to report this :(.
- assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES");
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
- // This isn't exactly what defines a NTFS symlink, but it is only true for
- // paths that act like a symlink.
- return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
-}
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-bool
-Path::canRead() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
-}
+ if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
+ return windows_error(::GetLastError());
-bool
-Path::canWrite() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
+ return error_code::success();
}
-bool
-Path::canExecute() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
+error_code remove(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ file_status st;
+ error_code EC = status(path, st);
+ if (EC) {
+ if (EC == windows_error::file_not_found ||
+ EC == windows_error::path_not_found) {
+ existed = false;
+ return error_code::success();
+ }
+ return EC;
+ }
+
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ if (st.type() == file_type::directory_file) {
+ if (!::RemoveDirectoryW(c_str(path_utf16))) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec != windows_error::file_not_found)
+ return ec;
+ existed = false;
+ } else
+ existed = true;
+ } else {
+ if (!::DeleteFileW(c_str(path_utf16))) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec != windows_error::file_not_found)
+ return ec;
+ existed = false;
+ } else
+ existed = true;
+ }
+
+ return error_code::success();
}
-bool
-Path::isRegularFile() const {
- bool res;
- if (fs::is_regular_file(path, res))
- return false;
- return res;
+error_code rename(const Twine &from, const Twine &to) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
+
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
+
+ error_code ec = error_code::success();
+ for (int i = 0; i < 2000; i++) {
+ if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
+ return error_code::success();
+ ec = windows_error(::GetLastError());
+ if (ec != windows_error::access_denied)
+ break;
+ // Retry MoveFile() at ACCESS_DENIED.
+ // System scanners (eg. indexer) might open the source file when
+ // It is written and closed.
+ ::Sleep(1);
+ }
+
+ return ec;
}
-StringRef
-Path::getLast() const {
- // Find the last slash
- size_t pos = path.rfind('/');
+error_code resize_file(const Twine &path, uint64_t size) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- // Handle the corner cases
- if (pos == std::string::npos)
- return path;
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
- // If the last character is a slash, we have a root directory
- if (pos == path.length()-1)
- return path;
+ int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
+ if (fd == -1)
+ return error_code(errno, generic_category());
+#ifdef HAVE__CHSIZE_S
+ errno_t error = ::_chsize_s(fd, size);
+#else
+ errno_t error = ::_chsize(fd, size);
+#endif
+ ::close(fd);
+ return error_code(error, generic_category());
+}
- // Return everything after the last slash
- return StringRef(path).substr(pos+1);
+error_code exists(const Twine &path, bool &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
+
+ if (attributes == INVALID_FILE_ATTRIBUTES) {
+ // See if the file didn't actually exist.
+ error_code ec = make_error_code(windows_error(::GetLastError()));
+ if (ec != windows_error::file_not_found &&
+ ec != windows_error::path_not_found)
+ return ec;
+ result = false;
+ } else
+ result = true;
+ return error_code::success();
}
-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;
- }
+bool can_write(const Twine &Path) {
+ // FIXME: take security attributes into account.
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUtf16;
- status.fileSize = fi.nFileSizeHigh;
- status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
- status.fileSize += fi.nFileSizeLow;
+ if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
+ 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...
+ DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
+ return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY);
+}
- // 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];
+bool can_execute(const Twine &Path) {
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUtf16;
- ULARGE_INTEGER ui;
- ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
- ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
- status.modTime.fromWin32Time(ui.QuadPart);
+ if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
+ return false;
- status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- fsIsValid = true;
- }
- return &status;
+ DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
+ return Attr != INVALID_FILE_ATTRIBUTES;
}
-bool Path::makeReadableOnDisk(std::string* ErrMsg) {
- // All files are readable on Windows (ignoring security attributes).
- return false;
+bool equivalent(file_status A, file_status B) {
+ assert(status_known(A) && status_known(B));
+ return A.FileIndexHigh == B.FileIndexHigh &&
+ A.FileIndexLow == B.FileIndexLow &&
+ A.FileSizeHigh == B.FileSizeHigh &&
+ A.FileSizeLow == B.FileSizeLow &&
+ A.LastWriteTimeHigh == B.LastWriteTimeHigh &&
+ A.LastWriteTimeLow == B.LastWriteTimeLow &&
+ A.VolumeSerialNumber == B.VolumeSerialNumber;
}
-bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
- DWORD attr = GetFileAttributes(path.c_str());
+error_code equivalent(const Twine &A, const Twine &B, bool &result) {
+ file_status fsA, fsB;
+ if (error_code ec = status(A, fsA)) return ec;
+ if (error_code ec = status(B, fsB)) return ec;
+ result = equivalent(fsA, fsB);
+ return error_code::success();
+}
- // If it doesn't exist, we're done.
- if (attr == INVALID_FILE_ATTRIBUTES)
- return false;
+static bool isReservedName(StringRef path) {
+ // This list of reserved names comes from MSDN, at:
+ // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
+ static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
+ "com1", "com2", "com3", "com4", "com5", "com6",
+ "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
+ "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
+
+ // First, check to see if this is a device namespace, which always
+ // starts with \\.\, since device namespaces are not legal file paths.
+ if (path.startswith("\\\\.\\"))
+ return true;
- if (attr & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
- MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
+ // Then compare against the list of ancient reserved names
+ for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) {
+ if (path.equals_lower(sReservedNames[i]))
return true;
- }
}
- return false;
-}
-bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
- // All files are executable on Windows (ignoring security attributes).
+ // The path isn't what we consider reserved.
return false;
}
-bool
-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;
+static error_code getStatus(HANDLE FileHandle, file_status &Result) {
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ goto handle_status_error;
+
+ switch (::GetFileType(FileHandle)) {
+ default:
+ llvm_unreachable("Don't know anything about this file type");
+ case FILE_TYPE_UNKNOWN: {
+ DWORD Err = ::GetLastError();
+ if (Err != NO_ERROR)
+ return windows_error(Err);
+ Result = file_status(file_type::type_unknown);
+ return error_code::success();
+ }
+ case FILE_TYPE_DISK:
+ break;
+ case FILE_TYPE_CHAR:
+ Result = file_status(file_type::character_file);
+ return error_code::success();
+ case FILE_TYPE_PIPE:
+ Result = file_status(file_type::fifo_file);
+ return error_code::success();
}
- if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- if (ErrMsg)
- *ErrMsg = path + ": not a directory";
- return true;
+ BY_HANDLE_FILE_INFORMATION Info;
+ if (!::GetFileInformationByHandle(FileHandle, &Info))
+ goto handle_status_error;
+
+ {
+ file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ? file_type::directory_file
+ : file_type::regular_file;
+ Result =
+ file_status(Type, Info.ftLastWriteTime.dwHighDateTime,
+ Info.ftLastWriteTime.dwLowDateTime,
+ Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
+ Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
+ return error_code::success();
}
- result.clear();
- WIN32_FIND_DATA fd;
- std::string searchpath = path;
- if (path.size() == 0 || searchpath[path.size()-1] == '/')
- searchpath += "*";
+handle_status_error:
+ error_code EC = windows_error(::GetLastError());
+ if (EC == windows_error::file_not_found ||
+ EC == windows_error::path_not_found)
+ Result = file_status(file_type::file_not_found);
+ else if (EC == windows_error::sharing_violation)
+ Result = file_status(file_type::type_unknown);
else
- searchpath += "/*";
+ Result = file_status(file_type::status_error);
+ return EC;
+}
- HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
- if (h == INVALID_HANDLE_VALUE) {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return true; // not really an error, now is it?
- MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
- return true;
- }
+error_code status(const Twine &path, file_status &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- do {
- if (fd.cFileName[0] == '.')
- continue;
- Path aPath(path);
- aPath.appendComponent(&fd.cFileName[0]);
- result.insert(aPath);
- } while (FindNextFile(h, &fd));
-
- DWORD err = GetLastError();
- FindClose(h);
- if (err != ERROR_NO_MORE_FILES) {
- SetLastError(err);
- MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
- return true;
+ StringRef path8 = path.toStringRef(path_storage);
+ if (isReservedName(path8)) {
+ result = file_status(file_type::character_file);
+ return error_code::success();
}
- return false;
-}
-bool
-Path::set(StringRef a_path) {
- if (a_path.empty())
- return false;
- std::string save(path);
- path = a_path;
- FlipBackSlashes(path);
- if (!isValid()) {
- path = save;
- return false;
+ if (error_code ec = UTF8ToUTF16(path8, path_utf16))
+ return ec;
+
+ DWORD attr = ::GetFileAttributesW(path_utf16.begin());
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return getStatus(INVALID_HANDLE_VALUE, result);
+
+ // Handle reparse points.
+ if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
+ ScopedFileHandle h(
+ ::CreateFileW(path_utf16.begin(),
+ 0, // Attributes only.
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ 0));
+ if (!h)
+ return getStatus(INVALID_HANDLE_VALUE, result);
}
- return true;
+
+ ScopedFileHandle h(
+ ::CreateFileW(path_utf16.begin(), 0, // Attributes only.
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
+ if (!h)
+ return getStatus(INVALID_HANDLE_VALUE, result);
+
+ return getStatus(h, result);
}
-bool
-Path::appendComponent(StringRef name) {
- if (name.empty())
- return false;
- std::string save(path);
- if (!path.empty()) {
- size_t last = path.size() - 1;
- if (path[last] != '/')
- path += '/';
- }
- path += name;
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
+error_code status(int FD, file_status &Result) {
+ HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ return getStatus(FileHandle, Result);
}
-bool
-Path::eraseComponent() {
- size_t slashpos = path.rfind('/',path.size());
- if (slashpos == path.size() - 1 || slashpos == std::string::npos)
- return false;
- std::string save(path);
- path.erase(slashpos);
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
+error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
+ ULARGE_INTEGER UI;
+ UI.QuadPart = Time.toWin32Time();
+ FILETIME FT;
+ FT.dwLowDateTime = UI.LowPart;
+ FT.dwHighDateTime = UI.HighPart;
+ HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (!SetFileTime(FileHandle, NULL, &FT, &FT))
+ return windows_error(::GetLastError());
+ return error_code::success();
}
-bool
-Path::eraseSuffix() {
- size_t dotpos = path.rfind('.',path.size());
- size_t slashpos = path.rfind('/',path.size());
- if (dotpos != std::string::npos) {
- if (slashpos == std::string::npos || dotpos > slashpos+1) {
- std::string save(path);
- path.erase(dotpos, path.size()-dotpos);
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
- }
+error_code get_magic(const Twine &path, uint32_t len,
+ SmallVectorImpl<char> &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+ result.set_size(0);
+
+ // Convert path to UTF-16.
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ // Open file.
+ HANDLE file = ::CreateFileW(c_str(path_utf16),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return windows_error(::GetLastError());
+
+ // Allocate buffer.
+ result.reserve(len);
+
+ // Get magic!
+ DWORD bytes_read = 0;
+ BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
+ error_code ec = windows_error(::GetLastError());
+ ::CloseHandle(file);
+ if (!read_success || (bytes_read != len)) {
+ // Set result size to the number of bytes read if it's valid.
+ if (bytes_read <= len)
+ result.set_size(bytes_read);
+ // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
+ return ec;
}
- 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;
+ result.set_size(len);
+ return error_code::success();
}
-bool
-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));
- path.copy(pathname, len);
- pathname[len] = 0;
-
- // Make sure it ends with a slash.
- if (len == 0 || pathname[len - 1] != '/') {
- pathname[len] = '/';
- pathname[++len] = 0;
+error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
+ FileDescriptor = FD;
+ // Make sure that the requested size fits within SIZE_T.
+ if (Size > std::numeric_limits<SIZE_T>::max()) {
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return make_error_code(errc::invalid_argument);
}
- // Determine starting point for initial / search.
- char *next = pathname;
- if (pathname[0] == '/' && pathname[1] == '/') {
- // Skip host name.
- next = strchr(pathname+2, '/');
- if (next == NULL)
- return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+ DWORD flprotect;
+ switch (Mode) {
+ case readonly: flprotect = PAGE_READONLY; break;
+ case readwrite: flprotect = PAGE_READWRITE; break;
+ case priv: flprotect = PAGE_WRITECOPY; break;
+ }
- // Skip share name.
- next = strchr(next+1, '/');
- if (next == NULL)
- return PathMsg(ErrMsg, pathname,"badly formed remote directory");
+ FileMappingHandle =
+ ::CreateFileMappingW(FileHandle, 0, flprotect,
+ (Offset + Size) >> 32,
+ (Offset + Size) & 0xffffffff,
+ 0);
+ if (FileMappingHandle == NULL) {
+ error_code ec = windows_error(GetLastError());
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
+ }
- next++;
- if (*next == 0)
- return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+ DWORD dwDesiredAccess;
+ switch (Mode) {
+ case readonly: dwDesiredAccess = FILE_MAP_READ; break;
+ case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
+ case priv: dwDesiredAccess = FILE_MAP_COPY; break;
+ }
+ Mapping = ::MapViewOfFile(FileMappingHandle,
+ dwDesiredAccess,
+ Offset >> 32,
+ Offset & 0xffffffff,
+ Size);
+ if (Mapping == NULL) {
+ error_code ec = windows_error(GetLastError());
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
+ }
- } 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) &&
- GetLastError() != ERROR_ALREADY_EXISTS)
- return MakeErrMsg(ErrMsg,
- std::string(pathname) + ": Can't create directory: ");
- *next++ = '/';
- }
- } else {
- // Drop trailing slash.
- pathname[len-1] = 0;
- if (!CreateDirectory(pathname, NULL) &&
- GetLastError() != ERROR_ALREADY_EXISTS) {
- return MakeErrMsg(ErrMsg, std::string(pathname) +
- ": Can't create directory: ");
+ if (Size == 0) {
+ MEMORY_BASIC_INFORMATION mbi;
+ SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
+ if (Result == 0) {
+ error_code ec = windows_error(GetLastError());
+ ::UnmapViewOfFile(Mapping);
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
}
+ Size = mbi.RegionSize;
}
- 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;
+ // Close all the handles except for the view. It will keep the other handles
+ // alive.
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor); // Also closes FileHandle.
+ } else
+ ::CloseHandle(FileHandle);
+ return error_code::success();
}
-bool
-Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
- return true;
+mapped_file_region::mapped_file_region(const Twine &path,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping()
+ , FileDescriptor()
+ , FileHandle(INVALID_HANDLE_VALUE)
+ , FileMappingHandle() {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ // Convert path to UTF-16.
+ if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
+ return;
- if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- // If it doesn't exist, we're done.
- bool Exists;
- if (fs::exists(path, Exists) || !Exists)
- return false;
+ // Get file handle for creating a file mapping.
+ FileHandle = ::CreateFileW(c_str(path_utf16),
+ Mode == readonly ? GENERIC_READ
+ : GENERIC_READ | GENERIC_WRITE,
+ Mode == readonly ? FILE_SHARE_READ
+ : 0,
+ 0,
+ Mode == readonly ? OPEN_EXISTING
+ : OPEN_ALWAYS,
+ Mode == readonly ? FILE_ATTRIBUTE_READONLY
+ : FILE_ATTRIBUTE_NORMAL,
+ 0);
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ ec = windows_error(::GetLastError());
+ return;
+ }
- char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
- int lastchar = path.length() - 1 ;
- path.copy(pathname, lastchar+1);
-
- // Make path end with '/*'.
- if (pathname[lastchar] != '/')
- pathname[++lastchar] = '/';
- pathname[lastchar+1] = '*';
- pathname[lastchar+2] = 0;
-
- if (remove_contents) {
- WIN32_FIND_DATA fd;
- HANDLE h = FindFirstFile(pathname, &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);
- aPath.appendComponent(&fd.cFileName[0]);
- list.push_back(aPath);
- } while (FindNextFile(h, &fd));
-
- DWORD err = GetLastError();
- FindClose(h);
- if (err != ERROR_NO_MORE_FILES) {
- SetLastError(err);
- return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
- }
-
- for (std::vector<Path>::iterator I = list.begin(); I != list.end();
- ++I) {
- Path &aPath = *I;
- aPath.eraseFromDisk(true);
- }
- } else {
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
- }
- }
+ FileDescriptor = 0;
+ ec = init(FileDescriptor, true, offset);
+ if (ec) {
+ Mapping = FileMappingHandle = 0;
+ FileHandle = INVALID_HANDLE_VALUE;
+ FileDescriptor = 0;
+ }
+}
- pathname[lastchar] = 0;
- if (!RemoveDirectory(pathname))
- return MakeErrMsg(ErrStr,
- std::string(pathname) + ": Can't destroy directory: ");
- return false;
- } else {
- // 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: ");
- }
+mapped_file_region::mapped_file_region(int fd,
+ bool closefd,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping()
+ , FileDescriptor(fd)
+ , FileHandle(INVALID_HANDLE_VALUE)
+ , FileMappingHandle() {
+ FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ if (closefd)
+ _close(FileDescriptor);
+ FileDescriptor = 0;
+ ec = make_error_code(errc::bad_file_descriptor);
+ return;
+ }
- if (!DeleteFile(path.c_str()))
- return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
- return false;
+ ec = init(FileDescriptor, closefd, offset);
+ if (ec) {
+ Mapping = FileMappingHandle = 0;
+ FileHandle = INVALID_HANDLE_VALUE;
+ FileDescriptor = 0;
}
}
-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));
+mapped_file_region::~mapped_file_region() {
+ if (Mapping)
+ ::UnmapViewOfFile(Mapping);
+}
+
+#if LLVM_HAS_RVALUE_REFERENCES
+mapped_file_region::mapped_file_region(mapped_file_region &&other)
+ : Mode(other.Mode)
+ , Size(other.Size)
+ , Mapping(other.Mapping)
+ , FileDescriptor(other.FileDescriptor)
+ , FileHandle(other.FileHandle)
+ , FileMappingHandle(other.FileMappingHandle) {
+ other.Mapping = other.FileMappingHandle = 0;
+ other.FileHandle = INVALID_HANDLE_VALUE;
+ other.FileDescriptor = 0;
+}
+#endif
- 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;
+mapped_file_region::mapmode mapped_file_region::flags() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Mode;
+}
- DWORD nRead = 0;
- BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
- CloseHandle(h);
+uint64_t mapped_file_region::size() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Size;
+}
- if (!ret || nRead != len)
- return false;
+char *mapped_file_region::data() const {
+ assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<char*>(Mapping);
+}
- Magic = std::string(buf, len);
- return true;
+const char *mapped_file_region::const_data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<const char*>(Mapping);
}
-bool
-Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
- if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
- return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
- + "': ");
- return false;
+int mapped_file_region::alignment() {
+ SYSTEM_INFO SysInfo;
+ ::GetSystemInfo(&SysInfo);
+ return SysInfo.dwAllocationGranularity;
}
-bool
-Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
- // FIXME: should work on directories also.
- if (!si.isFile) {
- return true;
- }
+error_code detail::directory_iterator_construct(detail::DirIterState &it,
+ StringRef path){
+ SmallVector<wchar_t, 128> path_utf16;
- 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 true;
+ if (error_code ec = UTF8ToUTF16(path,
+ path_utf16))
+ return ec;
- BY_HANDLE_FILE_INFORMATION bhfi;
- if (!GetFileInformationByHandle(h, &bhfi)) {
- DWORD err = GetLastError();
- CloseHandle(h);
- SetLastError(err);
- return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
- }
-
- ULARGE_INTEGER ui;
- ui.QuadPart = si.modTime.toWin32Time();
- FILETIME ft;
- ft.dwLowDateTime = ui.LowPart;
- ft.dwHighDateTime = ui.HighPart;
- BOOL ret = SetFileTime(h, NULL, &ft, &ft);
- DWORD err = GetLastError();
- CloseHandle(h);
- if (!ret) {
- SetLastError(err);
- return MakeErrMsg(ErrMsg, 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))
- return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
- }
+ // Convert path to the format that Windows is happy with.
+ if (path_utf16.size() > 0 &&
+ !is_separator(path_utf16[path.size() - 1]) &&
+ path_utf16[path.size() - 1] != L':') {
+ path_utf16.push_back(L'\\');
+ path_utf16.push_back(L'*');
} else {
- if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
- if (!SetFileAttributes(path.c_str(),
- bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
- return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
- }
+ path_utf16.push_back(L'*');
}
- return false;
+ // Get the first directory entry.
+ WIN32_FIND_DATAW FirstFind;
+ ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
+ if (!FindHandle)
+ return windows_error(::GetLastError());
+
+ size_t FilenameLen = ::wcslen(FirstFind.cFileName);
+ while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
+ (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
+ FirstFind.cFileName[1] == L'.'))
+ if (!::FindNextFileW(FindHandle, &FirstFind)) {
+ error_code ec = windows_error(::GetLastError());
+ // Check for end.
+ if (ec == windows_error::no_more_files)
+ return detail::directory_iterator_destruct(it);
+ return ec;
+ } else
+ FilenameLen = ::wcslen(FirstFind.cFileName);
+
+ // Construct the current directory entry.
+ SmallString<128> directory_entry_name_utf8;
+ if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
+ ::wcslen(FirstFind.cFileName),
+ directory_entry_name_utf8))
+ return ec;
+
+ it.IterationHandle = intptr_t(FindHandle.take());
+ SmallString<128> directory_entry_path(path);
+ path::append(directory_entry_path, directory_entry_name_utf8.str());
+ it.CurrentEntry = directory_entry(directory_entry_path.str());
+
+ return error_code::success();
}
-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;
+error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
+ if (it.IterationHandle != 0)
+ // Closes the handle if it's valid.
+ ScopedFindHandle close(HANDLE(it.IterationHandle));
+ it.IterationHandle = 0;
+ it.CurrentEntry = directory_entry();
+ return error_code::success();
}
-bool
-Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
- 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.
- char *FNBuffer = (char*) alloca(path.size()+8);
- unsigned offset = path.size();
- path.copy(FNBuffer, offset);
-
- // 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 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;
+error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+ WIN32_FIND_DATAW FindData;
+ if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+ error_code ec = windows_error(::GetLastError());
+ // Check for end.
+ if (ec == windows_error::no_more_files)
+ return detail::directory_iterator_destruct(it);
+ return ec;
}
- do {
- sprintf(FNBuffer+offset, "-%06u", FCounter);
- if (++FCounter > 999999)
- FCounter = 0;
- path = FNBuffer;
- } while (!fs::exists(path, Exists) && Exists);
- return false;
-}
-bool
-Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
- // Make this into a unique file name
- makeUnique(reuse_current, ErrMsg);
+ size_t FilenameLen = ::wcslen(FindData.cFileName);
+ if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
+ (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
+ FindData.cFileName[1] == L'.'))
+ return directory_iterator_increment(it);
- // 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 MakeErrMsg(ErrMsg, path + ": can't create file");
+ SmallString<128> directory_entry_path_utf8;
+ if (error_code ec = UTF16ToUTF8(FindData.cFileName,
+ ::wcslen(FindData.cFileName),
+ directory_entry_path_utf8))
+ return ec;
- CloseHandle(h);
- return false;
+ it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+ return error_code::success();
}
-/// MapInFilePages - Not yet implemented on win32.
-const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) {
- return 0;
+error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
+ bool map_writable, void *&result) {
+ assert(0 && "NOT IMPLEMENTED");
+ return windows_error::invalid_function;
}
-/// MapInFilePages - Not yet implemented on win32.
-void Path::UnMapFilePages(const char *Base, size_t FileSize) {
+error_code unmap_file_pages(void *base, size_t size) {
assert(0 && "NOT IMPLEMENTED");
+ return windows_error::invalid_function;
+}
+
+error_code openFileForRead(const Twine &Name, int &ResultFD) {
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUTF16;
+
+ if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage),
+ PathUTF16))
+ return EC;
+
+ HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (H == INVALID_HANDLE_VALUE) {
+ error_code EC = windows_error(::GetLastError());
+ // Provide a better error message when trying to open directories.
+ // This only runs if we failed to open the file, so there is probably
+ // no performances issues.
+ if (EC != windows_error::access_denied)
+ return EC;
+ if (is_directory(Name))
+ return error_code(errc::is_a_directory, posix_category());
+ return EC;
+ }
+
+ int FD = ::_open_osfhandle(intptr_t(H), 0);
+ if (FD == -1) {
+ ::CloseHandle(H);
+ return windows_error::invalid_handle;
+ }
+
+ ResultFD = FD;
+ return error_code::success();
+}
+
+error_code openFileForWrite(const Twine &Name, int &ResultFD,
+ sys::fs::OpenFlags Flags, unsigned Mode) {
+ // Verify that we don't have both "append" and "excl".
+ assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
+ "Cannot specify both 'excl' and 'append' file creation flags!");
+
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUTF16;
+
+ if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage),
+ PathUTF16))
+ return EC;
+
+ DWORD CreationDisposition;
+ if (Flags & F_Excl)
+ CreationDisposition = CREATE_NEW;
+ else if (Flags & F_Append)
+ CreationDisposition = OPEN_ALWAYS;
+ else
+ CreationDisposition = CREATE_ALWAYS;
+
+ HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (H == INVALID_HANDLE_VALUE) {
+ error_code EC = windows_error(::GetLastError());
+ // Provide a better error message when trying to open directories.
+ // This only runs if we failed to open the file, so there is probably
+ // no performances issues.
+ if (EC != windows_error::access_denied)
+ return EC;
+ if (is_directory(Name))
+ return error_code(errc::is_a_directory, posix_category());
+ return EC;
+ }
+
+ int OpenFlags = 0;
+ if (Flags & F_Append)
+ OpenFlags |= _O_APPEND;
+
+ if (!(Flags & F_Binary))
+ OpenFlags |= _O_TEXT;
+
+ int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
+ if (FD == -1) {
+ ::CloseHandle(H);
+ return windows_error::invalid_handle;
+ }
+
+ ResultFD = FD;
+ return error_code::success();
}
+} // end namespace fs
+namespace windows {
+llvm::error_code UTF8ToUTF16(llvm::StringRef utf8,
+ llvm::SmallVectorImpl<wchar_t> &utf16) {
+ int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+ utf8.begin(), utf8.size(),
+ utf16.begin(), 0);
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ utf16.reserve(len + 1);
+ utf16.set_size(len);
+
+ len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+ utf8.begin(), utf8.size(),
+ utf16.begin(), utf16.size());
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ // Make utf16 null terminated.
+ utf16.push_back(0);
+ utf16.pop_back();
+
+ return llvm::error_code::success();
}
+
+llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ llvm::SmallVectorImpl<char> &utf8) {
+ // Get length.
+ int len = ::WideCharToMultiByte(CP_UTF8, 0,
+ utf16, utf16_len,
+ utf8.begin(), 0,
+ NULL, NULL);
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ utf8.reserve(len);
+ utf8.set_size(len);
+
+ // Now do the actual conversion.
+ len = ::WideCharToMultiByte(CP_UTF8, 0,
+ utf16, utf16_len,
+ utf8.data(), utf8.size(),
+ NULL, NULL);
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ // Make utf8 null terminated.
+ utf8.push_back(0);
+ utf8.pop_back();
+
+ return llvm::error_code::success();
}
+} // end namespace windows
+} // end namespace sys
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Windows/PathV2.inc b/contrib/llvm/lib/Support/Windows/PathV2.inc
deleted file mode 100644
index 23f3d14..0000000
--- a/contrib/llvm/lib/Support/Windows/PathV2.inc
+++ /dev/null
@@ -1,1022 +0,0 @@
-//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Windows specific implementation of the PathV2 API.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Windows code that
-//=== is guaranteed to work on *all* Windows variants.
-//===----------------------------------------------------------------------===//
-
-#include "Windows.h"
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#undef max
-
-// MinGW doesn't define this.
-#ifndef _ERRNO_T_DEFINED
-#define _ERRNO_T_DEFINED
-typedef int errno_t;
-#endif
-
-using namespace llvm;
-
-namespace {
- typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
- /*__in*/ LPCWSTR lpSymlinkFileName,
- /*__in*/ LPCWSTR lpTargetFileName,
- /*__in*/ DWORD dwFlags);
-
- PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
- ::GetProcAddress(::GetModuleHandleA("kernel32.dll"),
- "CreateSymbolicLinkW"));
-
- error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) {
- int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
- utf8.begin(), utf8.size(),
- utf16.begin(), 0);
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- utf16.reserve(len + 1);
- utf16.set_size(len);
-
- len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
- utf8.begin(), utf8.size(),
- utf16.begin(), utf16.size());
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- // Make utf16 null terminated.
- utf16.push_back(0);
- utf16.pop_back();
-
- return error_code::success();
- }
-
- error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8) {
- // Get length.
- int len = ::WideCharToMultiByte(CP_UTF8, 0,
- utf16, utf16_len,
- utf8.begin(), 0,
- NULL, NULL);
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- utf8.reserve(len);
- utf8.set_size(len);
-
- // Now do the actual conversion.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- utf16, utf16_len,
- utf8.data(), utf8.size(),
- NULL, NULL);
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- // Make utf8 null terminated.
- utf8.push_back(0);
- utf8.pop_back();
-
- return error_code::success();
- }
-
- error_code TempDir(SmallVectorImpl<wchar_t> &result) {
- retry_temp_dir:
- DWORD len = ::GetTempPathW(result.capacity(), result.begin());
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- if (len > result.capacity()) {
- result.reserve(len);
- goto retry_temp_dir;
- }
-
- result.set_size(len);
- return error_code::success();
- }
-
- bool is_separator(const wchar_t value) {
- switch (value) {
- case L'\\':
- case L'/':
- return true;
- default:
- return false;
- }
- }
-}
-
-namespace llvm {
-namespace sys {
-namespace fs {
-
-error_code current_path(SmallVectorImpl<char> &result) {
- SmallVector<wchar_t, 128> cur_path;
- cur_path.reserve(128);
-retry_cur_dir:
- DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
-
- // A zero return value indicates a failure other than insufficient space.
- if (len == 0)
- return windows_error(::GetLastError());
-
- // If there's insufficient space, the len returned is larger than the len
- // given.
- if (len > cur_path.capacity()) {
- cur_path.reserve(len);
- goto retry_cur_dir;
- }
-
- cur_path.set_size(len);
- // cur_path now holds the current directory in utf-16. Convert to utf-8.
-
- // Find out how much space we need. Sadly, this function doesn't return the
- // size needed unless you tell it the result size is 0, which means you
- // _always_ have to call it twice.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- cur_path.data(), cur_path.size(),
- result.data(), 0,
- NULL, NULL);
-
- if (len == 0)
- return make_error_code(windows_error(::GetLastError()));
-
- result.reserve(len);
- result.set_size(len);
- // Now do the actual conversion.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- cur_path.data(), cur_path.size(),
- result.data(), result.size(),
- NULL, NULL);
- if (len == 0)
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- // Copy the file.
- BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(),
- copt != copy_option::overwrite_if_exists);
-
- if (res == 0)
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code create_directory(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::already_exists)
- existed = true;
- else
- return ec;
- } else
- existed = false;
-
- return error_code::success();
-}
-
-error_code create_hard_link(const Twine &to, const Twine &from) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code create_symlink(const Twine &to, const Twine &from) {
- // Only do it if the function is available at runtime.
- if (!create_symbolic_link_api)
- return make_error_code(errc::function_not_supported);
-
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code remove(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- file_status st;
- if (error_code ec = status(path, st))
- return ec;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- if (st.type() == file_type::directory_file) {
- if (!::RemoveDirectoryW(c_str(path_utf16))) {
- error_code ec = windows_error(::GetLastError());
- if (ec != windows_error::file_not_found)
- return ec;
- existed = false;
- } else
- existed = true;
- } else {
- if (!::DeleteFileW(c_str(path_utf16))) {
- error_code ec = windows_error(::GetLastError());
- if (ec != windows_error::file_not_found)
- return ec;
- existed = false;
- } else
- existed = true;
- }
-
- return error_code::success();
-}
-
-error_code rename(const Twine &from, const Twine &to) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- error_code ec = error_code::success();
- for (int i = 0; i < 2000; i++) {
- if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
- MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
- return error_code::success();
- ec = windows_error(::GetLastError());
- if (ec != windows_error::access_denied)
- break;
- // Retry MoveFile() at ACCESS_DENIED.
- // System scanners (eg. indexer) might open the source file when
- // It is written and closed.
- ::Sleep(1);
- }
-
- return ec;
-}
-
-error_code resize_file(const Twine &path, uint64_t size) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
- if (fd == -1)
- return error_code(errno, generic_category());
-#ifdef HAVE__CHSIZE_S
- errno_t error = ::_chsize_s(fd, size);
-#else
- errno_t error = ::_chsize(fd, size);
-#endif
- ::close(fd);
- return error_code(error, generic_category());
-}
-
-error_code exists(const Twine &path, bool &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
-
- if (attributes == INVALID_FILE_ATTRIBUTES) {
- // See if the file didn't actually exist.
- error_code ec = make_error_code(windows_error(::GetLastError()));
- if (ec != windows_error::file_not_found &&
- ec != windows_error::path_not_found)
- return ec;
- result = false;
- } else
- result = true;
- return error_code::success();
-}
-
-bool equivalent(file_status A, file_status B) {
- assert(status_known(A) && status_known(B));
- return A.FileIndexHigh == B.FileIndexHigh &&
- A.FileIndexLow == B.FileIndexLow &&
- A.FileSizeHigh == B.FileSizeHigh &&
- A.FileSizeLow == B.FileSizeLow &&
- A.LastWriteTimeHigh == B.LastWriteTimeHigh &&
- A.LastWriteTimeLow == B.LastWriteTimeLow &&
- A.VolumeSerialNumber == B.VolumeSerialNumber;
-}
-
-error_code equivalent(const Twine &A, const Twine &B, bool &result) {
- file_status fsA, fsB;
- if (error_code ec = status(A, fsA)) return ec;
- if (error_code ec = status(B, fsB)) return ec;
- result = equivalent(fsA, fsB);
- return error_code::success();
-}
-
-error_code file_size(const Twine &path, uint64_t &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- WIN32_FILE_ATTRIBUTE_DATA FileData;
- if (!::GetFileAttributesExW(path_utf16.begin(),
- ::GetFileExInfoStandard,
- &FileData))
- return windows_error(::GetLastError());
-
- result =
- (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8))
- + FileData.nFileSizeLow;
-
- return error_code::success();
-}
-
-static bool isReservedName(StringRef path) {
- // This list of reserved names comes from MSDN, at:
- // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
- static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
- "com1", "com2", "com3", "com4", "com5", "com6",
- "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
- "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
-
- // First, check to see if this is a device namespace, which always
- // starts with \\.\, since device namespaces are not legal file paths.
- if (path.startswith("\\\\.\\"))
- return true;
-
- // Then compare against the list of ancient reserved names
- for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) {
- if (path.equals_lower(sReservedNames[i]))
- return true;
- }
-
- // The path isn't what we consider reserved.
- return false;
-}
-
-error_code status(const Twine &path, file_status &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- StringRef path8 = path.toStringRef(path_storage);
- if (isReservedName(path8)) {
- result = file_status(file_type::character_file);
- return error_code::success();
- }
-
- if (error_code ec = UTF8ToUTF16(path8, path_utf16))
- return ec;
-
- DWORD attr = ::GetFileAttributesW(path_utf16.begin());
- if (attr == INVALID_FILE_ATTRIBUTES)
- goto handle_status_error;
-
- // Handle reparse points.
- if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
- ScopedFileHandle h(
- ::CreateFileW(path_utf16.begin(),
- 0, // Attributes only.
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- 0));
- if (!h)
- goto handle_status_error;
- }
-
- if (attr & FILE_ATTRIBUTE_DIRECTORY)
- result = file_status(file_type::directory_file);
- else {
- result = file_status(file_type::regular_file);
- ScopedFileHandle h(
- ::CreateFileW(path_utf16.begin(),
- 0, // Attributes only.
- FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- 0));
- if (!h)
- goto handle_status_error;
- BY_HANDLE_FILE_INFORMATION Info;
- if (!::GetFileInformationByHandle(h, &Info))
- goto handle_status_error;
- result.FileIndexHigh = Info.nFileIndexHigh;
- result.FileIndexLow = Info.nFileIndexLow;
- result.FileSizeHigh = Info.nFileSizeHigh;
- result.FileSizeLow = Info.nFileSizeLow;
- result.LastWriteTimeHigh = Info.ftLastWriteTime.dwHighDateTime;
- result.LastWriteTimeLow = Info.ftLastWriteTime.dwLowDateTime;
- result.VolumeSerialNumber = Info.dwVolumeSerialNumber;
- }
-
- return error_code::success();
-
-handle_status_error:
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::file_not_found ||
- ec == windows_error::path_not_found)
- result = file_status(file_type::file_not_found);
- else if (ec == windows_error::sharing_violation)
- result = file_status(file_type::type_unknown);
- else {
- result = file_status(file_type::status_error);
- return ec;
- }
-
- return error_code::success();
-}
-
-
-// Modifies permissions on a file.
-error_code permissions(const Twine &path, perms prms) {
-#if 0 // verify code below before enabling:
- // If the permissions bits are not trying to modify
- // "write" permissions, there is nothing to do.
- if (!(prms & (owner_write|group_write|others_write)))
- return error_code::success();
-
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
-
- if (prms & add_perms) {
- attributes &= ~FILE_ATTRIBUTE_READONLY;
- }
- else if (prms & remove_perms) {
- attributes |= FILE_ATTRIBUTE_READONLY;
- }
- else {
- assert(0 && "neither add_perms or remove_perms is set");
- }
-
- if ( ! ::SetFileAttributesW(path_utf16.begin(), attributes))
- return windows_error(::GetLastError());
-#endif
- return error_code::success();
-}
-
-
-// FIXME: mode should be used here and default to user r/w only,
-// it currently comes in as a UNIX mode.
-error_code unique_file(const Twine &model, int &result_fd,
- SmallVectorImpl<char> &result_path,
- bool makeAbsolute, unsigned mode) {
- // Use result_path as temp storage.
- result_path.set_size(0);
- StringRef m = model.toStringRef(result_path);
-
- SmallVector<wchar_t, 128> model_utf16;
- if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
-
- if (makeAbsolute) {
- // Make model absolute by prepending a temp directory if it's not already.
- bool absolute = path::is_absolute(m);
-
- if (!absolute) {
- SmallVector<wchar_t, 64> temp_dir;
- if (error_code ec = TempDir(temp_dir)) return ec;
- // Handle c: by removing it.
- if (model_utf16.size() > 2 && model_utf16[1] == L':') {
- model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
- }
- model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
- }
- }
-
- // Replace '%' with random chars. From here on, DO NOT modify model. It may be
- // needed if the randomly chosen path already exists.
- SmallVector<wchar_t, 128> random_path_utf16;
-
- // Get a Crypto Provider for CryptGenRandom.
- HCRYPTPROV HCPC;
- if (!::CryptAcquireContextW(&HCPC,
- NULL,
- NULL,
- PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT))
- return windows_error(::GetLastError());
- ScopedCryptContext CryptoProvider(HCPC);
-
-retry_random_path:
- random_path_utf16.set_size(0);
- for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
- e = model_utf16.end();
- i != e; ++i) {
- if (*i == L'%') {
- BYTE val = 0;
- if (!::CryptGenRandom(CryptoProvider, 1, &val))
- return windows_error(::GetLastError());
- random_path_utf16.push_back("0123456789abcdef"[val & 15]);
- }
- else
- random_path_utf16.push_back(*i);
- }
- // Make random_path_utf16 null terminated.
- random_path_utf16.push_back(0);
- random_path_utf16.pop_back();
-
- // Make sure we don't fall into an infinite loop by constantly trying
- // to create the parent path.
- bool TriedToCreateParent = false;
-
- // Try to create + open the path.
-retry_create_file:
- HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- // Return ERROR_FILE_EXISTS if the file
- // already exists.
- CREATE_NEW,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (TempFileHandle == INVALID_HANDLE_VALUE) {
- // If the file existed, try again, otherwise, error.
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::file_exists)
- goto retry_random_path;
- // Check for non-existing parent directories.
- if (ec == windows_error::path_not_found && !TriedToCreateParent) {
- TriedToCreateParent = true;
-
- // Create the directories using result_path as temp storage.
- if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
- random_path_utf16.size(), result_path))
- return ec;
- StringRef p(result_path.begin(), result_path.size());
- SmallString<64> dir_to_create;
- for (path::const_iterator i = path::begin(p),
- e = --path::end(p); i != e; ++i) {
- path::append(dir_to_create, *i);
- bool Exists;
- if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
- if (!Exists) {
- // If c: doesn't exist, bail.
- if (i->endswith(":"))
- return ec;
-
- SmallVector<wchar_t, 64> dir_to_create_utf16;
- if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
- return ec;
-
- // Create the directory.
- if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
- return windows_error(::GetLastError());
- }
- }
- goto retry_create_file;
- }
- return ec;
- }
-
- // Set result_path to the utf-8 representation of the path.
- if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
- random_path_utf16.size(), result_path)) {
- ::CloseHandle(TempFileHandle);
- ::DeleteFileW(random_path_utf16.begin());
- return ec;
- }
-
- // Convert the Windows API file handle into a C-runtime handle.
- int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
- if (fd == -1) {
- ::CloseHandle(TempFileHandle);
- ::DeleteFileW(random_path_utf16.begin());
- // MSDN doesn't say anything about _open_osfhandle setting errno or
- // GetLastError(), so just return invalid_handle.
- return windows_error::invalid_handle;
- }
-
- result_fd = fd;
- return error_code::success();
-}
-
-error_code get_magic(const Twine &path, uint32_t len,
- SmallVectorImpl<char> &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
- result.set_size(0);
-
- // Convert path to UTF-16.
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- // Open file.
- HANDLE file = ::CreateFileW(c_str(path_utf16),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_READONLY,
- NULL);
- if (file == INVALID_HANDLE_VALUE)
- return windows_error(::GetLastError());
-
- // Allocate buffer.
- result.reserve(len);
-
- // Get magic!
- DWORD bytes_read = 0;
- BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
- error_code ec = windows_error(::GetLastError());
- ::CloseHandle(file);
- if (!read_success || (bytes_read != len)) {
- // Set result size to the number of bytes read if it's valid.
- if (bytes_read <= len)
- result.set_size(bytes_read);
- // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
- return ec;
- }
-
- result.set_size(len);
- return error_code::success();
-}
-
-error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
- FileDescriptor = FD;
- // Make sure that the requested size fits within SIZE_T.
- if (Size > std::numeric_limits<SIZE_T>::max()) {
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return make_error_code(errc::invalid_argument);
- }
-
- DWORD flprotect;
- switch (Mode) {
- case readonly: flprotect = PAGE_READONLY; break;
- case readwrite: flprotect = PAGE_READWRITE; break;
- case priv: flprotect = PAGE_WRITECOPY; break;
- default: llvm_unreachable("invalid mapping mode");
- }
-
- FileMappingHandle = ::CreateFileMapping(FileHandle,
- 0,
- flprotect,
- Size >> 32,
- Size & 0xffffffff,
- 0);
- if (FileMappingHandle == NULL) {
- error_code ec = windows_error(GetLastError());
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
-
- DWORD dwDesiredAccess;
- switch (Mode) {
- case readonly: dwDesiredAccess = FILE_MAP_READ; break;
- case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
- case priv: dwDesiredAccess = FILE_MAP_COPY; break;
- default: llvm_unreachable("invalid mapping mode");
- }
- Mapping = ::MapViewOfFile(FileMappingHandle,
- dwDesiredAccess,
- Offset >> 32,
- Offset & 0xffffffff,
- Size);
- if (Mapping == NULL) {
- error_code ec = windows_error(GetLastError());
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
-
- if (Size == 0) {
- MEMORY_BASIC_INFORMATION mbi;
- SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
- if (Result == 0) {
- error_code ec = windows_error(GetLastError());
- ::UnmapViewOfFile(Mapping);
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
- Size = mbi.RegionSize;
- }
-
- // Close all the handles except for the view. It will keep the other handles
- // alive.
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor); // Also closes FileHandle.
- } else
- ::CloseHandle(FileHandle);
- return error_code::success();
-}
-
-mapped_file_region::mapped_file_region(const Twine &path,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping()
- , FileDescriptor()
- , FileHandle(INVALID_HANDLE_VALUE)
- , FileMappingHandle() {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- // Convert path to UTF-16.
- if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
- return;
-
- // Get file handle for creating a file mapping.
- FileHandle = ::CreateFileW(c_str(path_utf16),
- Mode == readonly ? GENERIC_READ
- : GENERIC_READ | GENERIC_WRITE,
- Mode == readonly ? FILE_SHARE_READ
- : 0,
- 0,
- Mode == readonly ? OPEN_EXISTING
- : OPEN_ALWAYS,
- Mode == readonly ? FILE_ATTRIBUTE_READONLY
- : FILE_ATTRIBUTE_NORMAL,
- 0);
- if (FileHandle == INVALID_HANDLE_VALUE) {
- ec = windows_error(::GetLastError());
- return;
- }
-
- FileDescriptor = 0;
- ec = init(FileDescriptor, true, offset);
- if (ec) {
- Mapping = FileMappingHandle = 0;
- FileHandle = INVALID_HANDLE_VALUE;
- FileDescriptor = 0;
- }
-}
-
-mapped_file_region::mapped_file_region(int fd,
- bool closefd,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping()
- , FileDescriptor(fd)
- , FileHandle(INVALID_HANDLE_VALUE)
- , FileMappingHandle() {
- FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
- if (FileHandle == INVALID_HANDLE_VALUE) {
- if (closefd)
- _close(FileDescriptor);
- FileDescriptor = 0;
- ec = make_error_code(errc::bad_file_descriptor);
- return;
- }
-
- ec = init(FileDescriptor, closefd, offset);
- if (ec) {
- Mapping = FileMappingHandle = 0;
- FileHandle = INVALID_HANDLE_VALUE;
- FileDescriptor = 0;
- }
-}
-
-mapped_file_region::~mapped_file_region() {
- if (Mapping)
- ::UnmapViewOfFile(Mapping);
-}
-
-#if LLVM_HAS_RVALUE_REFERENCES
-mapped_file_region::mapped_file_region(mapped_file_region &&other)
- : Mode(other.Mode)
- , Size(other.Size)
- , Mapping(other.Mapping)
- , FileDescriptor(other.FileDescriptor)
- , FileHandle(other.FileHandle)
- , FileMappingHandle(other.FileMappingHandle) {
- other.Mapping = other.FileMappingHandle = 0;
- other.FileHandle = INVALID_HANDLE_VALUE;
- other.FileDescriptor = 0;
-}
-#endif
-
-mapped_file_region::mapmode mapped_file_region::flags() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Mode;
-}
-
-uint64_t mapped_file_region::size() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Size;
-}
-
-char *mapped_file_region::data() const {
- assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
- assert(Mapping && "Mapping failed but used anyway!");
- return reinterpret_cast<char*>(Mapping);
-}
-
-const char *mapped_file_region::const_data() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return reinterpret_cast<const char*>(Mapping);
-}
-
-int mapped_file_region::alignment() {
- SYSTEM_INFO SysInfo;
- ::GetSystemInfo(&SysInfo);
- return SysInfo.dwAllocationGranularity;
-}
-
-error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path,
- path_utf16))
- return ec;
-
- // Convert path to the format that Windows is happy with.
- if (path_utf16.size() > 0 &&
- !is_separator(path_utf16[path.size() - 1]) &&
- path_utf16[path.size() - 1] != L':') {
- path_utf16.push_back(L'\\');
- path_utf16.push_back(L'*');
- } else {
- path_utf16.push_back(L'*');
- }
-
- // Get the first directory entry.
- WIN32_FIND_DATAW FirstFind;
- ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
- if (!FindHandle)
- return windows_error(::GetLastError());
-
- size_t FilenameLen = ::wcslen(FirstFind.cFileName);
- while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
- (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
- FirstFind.cFileName[1] == L'.'))
- if (!::FindNextFileW(FindHandle, &FirstFind)) {
- error_code ec = windows_error(::GetLastError());
- // Check for end.
- if (ec == windows_error::no_more_files)
- return detail::directory_iterator_destruct(it);
- return ec;
- } else
- FilenameLen = ::wcslen(FirstFind.cFileName);
-
- // Construct the current directory entry.
- SmallString<128> directory_entry_name_utf8;
- if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
- ::wcslen(FirstFind.cFileName),
- directory_entry_name_utf8))
- return ec;
-
- it.IterationHandle = intptr_t(FindHandle.take());
- SmallString<128> directory_entry_path(path);
- path::append(directory_entry_path, directory_entry_name_utf8.str());
- it.CurrentEntry = directory_entry(directory_entry_path.str());
-
- return error_code::success();
-}
-
-error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
- if (it.IterationHandle != 0)
- // Closes the handle if it's valid.
- ScopedFindHandle close(HANDLE(it.IterationHandle));
- it.IterationHandle = 0;
- it.CurrentEntry = directory_entry();
- return error_code::success();
-}
-
-error_code detail::directory_iterator_increment(detail::DirIterState &it) {
- WIN32_FIND_DATAW FindData;
- if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
- error_code ec = windows_error(::GetLastError());
- // Check for end.
- if (ec == windows_error::no_more_files)
- return detail::directory_iterator_destruct(it);
- return ec;
- }
-
- size_t FilenameLen = ::wcslen(FindData.cFileName);
- if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
- (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
- FindData.cFileName[1] == L'.'))
- return directory_iterator_increment(it);
-
- SmallString<128> directory_entry_path_utf8;
- if (error_code ec = UTF16ToUTF8(FindData.cFileName,
- ::wcslen(FindData.cFileName),
- directory_entry_path_utf8))
- return ec;
-
- it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
- return error_code::success();
-}
-
-error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
- bool map_writable, void *&result) {
- assert(0 && "NOT IMPLEMENTED");
- return windows_error::invalid_function;
-}
-
-error_code unmap_file_pages(void *base, size_t size) {
- assert(0 && "NOT IMPLEMENTED");
- return windows_error::invalid_function;
-}
-
-
-
-} // end namespace fs
-} // end namespace sys
-} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc
index ad94128..f9a3db9 100644
--- a/contrib/llvm/lib/Support/Windows/Process.inc
+++ b/contrib/llvm/lib/Support/Windows/Process.inc
@@ -11,18 +11,25 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Allocator.h"
+
#include "Windows.h"
#include <direct.h>
#include <io.h>
#include <malloc.h>
#include <psapi.h>
+#include <shellapi.h>
#ifdef __MINGW32__
#if (HAVE_LIBPSAPI != 1)
#error "libpsapi.a should be present"
#endif
+ #if (HAVE_LIBSHELL32 != 1)
+ #error "libshell32.a should be present"
+ #endif
#else
#pragma comment(lib, "psapi.lib")
+ #pragma comment(lib, "shell32.lib")
#endif
//===----------------------------------------------------------------------===//
@@ -40,7 +47,7 @@ using namespace sys;
process::id_type self_process::get_id() {
- return GetCurrentProcess();
+ return GetCurrentProcessId();
}
static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
@@ -83,6 +90,8 @@ static unsigned getPageSize() {
// that LLVM ought to run as 64-bits on a 64-bit system, anyway.
SYSTEM_INFO info;
GetSystemInfo(&info);
+ // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
+ // but dwAllocationGranularity.
return static_cast<unsigned>(info.dwPageSize);
}
@@ -119,28 +128,89 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
sys_time = getTimeValueFromFILETIME(KernelTime);
}
-int Process::GetCurrentUserId()
-{
- return 65536;
-}
-
-int Process::GetCurrentGroupId()
-{
- return 65536;
-}
-
// Some LLVM programs such as bugpoint produce core files as a normal part of
-// their operation. To prevent the disk from filling up, this configuration item
-// does what's necessary to prevent their generation.
+// their operation. To prevent the disk from filling up, this configuration
+// item does what's necessary to prevent their generation.
void Process::PreventCoreFiles() {
- // Windows doesn't do core files, but it does do modal pop-up message
- // boxes. As this method is used by bugpoint, preventing these pop-ups
- // is the moral equivalent of suppressing core files.
+ // Windows does have the concept of core files, called minidumps. However,
+ // disabling minidumps for a particular application extends past the lifetime
+ // of that application, which is the incorrect behavior for this API.
+ // Additionally, the APIs require elevated privileges to disable and re-
+ // enable minidumps, which makes this untenable. For more information, see
+ // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
+ // later).
+ //
+ // Windows also has modal pop-up message boxes. As this method is used by
+ // bugpoint, preventing these pop-ups is additionally important.
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
}
+/// Returns the environment variable \arg Name's value as a string encoded in
+/// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
+Optional<std::string> Process::GetEnv(StringRef Name) {
+ // Convert the argument to UTF-16 to pass it to _wgetenv().
+ SmallVector<wchar_t, 128> NameUTF16;
+ if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16))
+ return None;
+
+ // Environment variable can be encoded in non-UTF8 encoding, and there's no
+ // way to know what the encoding is. The only reliable way to look up
+ // multibyte environment variable is to use GetEnvironmentVariableW().
+ SmallVector<wchar_t, MAX_PATH> Buf;
+ size_t Size = MAX_PATH;
+ do {
+ Buf.reserve(Size);
+ Size =
+ GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
+ if (Size == 0)
+ return None;
+
+ // Try again with larger buffer.
+ } while (Size > Buf.capacity());
+ Buf.set_size(Size);
+
+ // Convert the result from UTF-16 to UTF-8.
+ SmallVector<char, MAX_PATH> Res;
+ if (error_code ec = windows::UTF16ToUTF8(Buf.data(), Size, Res))
+ return None;
+ return std::string(Res.data());
+}
+
+error_code
+Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
+ ArrayRef<const char *>,
+ SpecificBumpPtrAllocator<char> &ArgAllocator) {
+ int NewArgCount;
+ error_code ec;
+
+ wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(),
+ &NewArgCount);
+ if (!UnicodeCommandLine)
+ return windows_error(::GetLastError());
+
+ Args.reserve(NewArgCount);
+
+ for (int i = 0; i < NewArgCount; ++i) {
+ SmallVector<char, MAX_PATH> NewArgString;
+ ec = windows::UTF16ToUTF8(UnicodeCommandLine[i],
+ wcslen(UnicodeCommandLine[i]),
+ NewArgString);
+ if (ec)
+ break;
+
+ char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1);
+ ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1);
+ Args.push_back(Buffer);
+ }
+ LocalFree(UnicodeCommandLine);
+ if (ec)
+ return ec;
+
+ return error_code::success();
+}
+
bool Process::StandardInIsUserInput() {
return FileDescriptorIsDisplayed(0);
}
@@ -187,6 +257,11 @@ bool Process::StandardErrHasColors() {
return FileDescriptorHasColors(2);
}
+static bool UseANSI = false;
+void Process::UseANSIEscapeCodes(bool enable) {
+ UseANSI = enable;
+}
+
namespace {
class DefaultColors
{
@@ -208,10 +283,12 @@ DefaultColors defaultColors;
}
bool Process::ColorNeedsFlush() {
- return true;
+ return !UseANSI;
}
const char *Process::OutputBold(bool bg) {
+ if (UseANSI) return "\033[1m";
+
WORD colors = DefaultColors::GetCurrentColor();
if (bg)
colors |= BACKGROUND_INTENSITY;
@@ -222,6 +299,8 @@ const char *Process::OutputBold(bool bg) {
}
const char *Process::OutputColor(char code, bool bold, bool bg) {
+ if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
+
WORD colors;
if (bg) {
colors = ((code&1) ? BACKGROUND_RED : 0) |
@@ -247,6 +326,8 @@ static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
}
const char *Process::OutputReverse() {
+ if (UseANSI) return "\033[7m";
+
const WORD attributes
= GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
@@ -273,6 +354,7 @@ const char *Process::OutputReverse() {
}
const char *Process::ResetColor() {
+ if (UseANSI) return "\033[0m";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
return 0;
}
diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc
index 619ae5d..dc09738 100644
--- a/contrib/llvm/lib/Support/Windows/Program.inc
+++ b/contrib/llvm/lib/Support/Windows/Program.inc
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "Windows.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/FileSystem.h"
#include <cstdio>
#include <fcntl.h>
#include <io.h>
@@ -22,37 +24,17 @@
//=== and must not be UNIX code
//===----------------------------------------------------------------------===//
-namespace {
- struct Win32ProcessInfo {
- HANDLE hProcess;
- DWORD dwProcessId;
- };
-}
-
namespace llvm {
using namespace sys;
-Program::Program() : Data_(0) {}
-
-Program::~Program() {
- if (Data_) {
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- CloseHandle(wpi->hProcess);
- delete wpi;
- Data_ = 0;
- }
-}
+ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
// This function just uses the PATH environment variable to find the program.
-Path
-Program::FindProgramByName(const std::string& progName) {
-
+std::string sys::FindProgramByName(const std::string &progName) {
// Check some degenerate cases
if (progName.length() == 0) // no program
- return Path();
- Path temp;
- if (!temp.set(progName)) // invalid name
- return Path();
+ return "";
+ std::string temp = progName;
// Return paths with slashes verbatim.
if (progName.find('\\') != std::string::npos ||
progName.find('/') != std::string::npos)
@@ -60,58 +42,60 @@ Program::FindProgramByName(const std::string& progName) {
// At this point, the file name is valid and does not contain slashes.
// Let Windows search for it.
- char buffer[MAX_PATH];
- char *dummy = NULL;
- DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH,
- buffer, &dummy);
-
- // See if it wasn't found.
- if (len == 0)
- return Path();
-
- // See if we got the entire path.
- if (len < MAX_PATH)
- return Path(buffer);
-
- // Buffer was too small; grow and retry.
- while (true) {
- char *b = reinterpret_cast<char *>(_alloca(len+1));
- DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy);
-
- // It is unlikely the search failed, but it's always possible some file
- // was added or removed since the last search, so be paranoid...
- if (len2 == 0)
- return Path();
- else if (len2 <= len)
- return Path(b);
-
- len = len2;
- }
+ SmallVector<wchar_t, MAX_PATH> progNameUnicode;
+ if (windows::UTF8ToUTF16(progName, progNameUnicode))
+ return "";
+
+ SmallVector<wchar_t, MAX_PATH> buffer;
+ DWORD len = MAX_PATH;
+ do {
+ buffer.reserve(len);
+ len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe",
+ buffer.capacity(), buffer.data(), NULL);
+
+ // See if it wasn't found.
+ if (len == 0)
+ return "";
+
+ // Buffer was too small; grow and retry.
+ } while (len > buffer.capacity());
+
+ buffer.set_size(len);
+ SmallVector<char, MAX_PATH> result;
+ if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result))
+ return "";
+
+ return std::string(result.data(), result.size());
}
-static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) {
+static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {
HANDLE h;
if (path == 0) {
- DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
- GetCurrentProcess(), &h,
- 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
+ GetCurrentProcess(), &h,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ return INVALID_HANDLE_VALUE;
return h;
}
- const char *fname;
- if (path->isEmpty())
+ std::string fname;
+ if (path->empty())
fname = "NUL";
else
- fname = path->c_str();
+ fname = *path;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
- h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ,
- &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ SmallVector<wchar_t, 128> fnameUnicode;
+ if (windows::UTF8ToUTF16(fname, fnameUnicode))
+ return INVALID_HANDLE_VALUE;
+
+ h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
(fd ? "input: " : "output: "));
@@ -181,22 +165,12 @@ static unsigned int ArgLenWithQuotes(const char *Str) {
return len;
}
+}
-bool
-Program::Execute(const Path& path,
- const char** args,
- const char** envp,
- const Path** redirects,
- unsigned memoryLimit,
- std::string* ErrMsg) {
- if (Data_) {
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- CloseHandle(wpi->hProcess);
- delete wpi;
- Data_ = 0;
- }
-
- if (!path.canExecute()) {
+static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
+ const char **envp, const StringRef **redirects,
+ unsigned memoryLimit, std::string *ErrMsg) {
+ if (!sys::fs::can_execute(Program)) {
if (ErrMsg)
*ErrMsg = "program not executable";
return false;
@@ -213,8 +187,8 @@ Program::Execute(const Path& path,
}
// Now build the command line.
- char *command = reinterpret_cast<char *>(_alloca(len+1));
- char *p = command;
+ OwningArrayPtr<char> command(new char[len+1]);
+ char *p = command.get();
for (unsigned i = 0; args[i]; i++) {
const char *arg = args[i];
@@ -245,34 +219,28 @@ Program::Execute(const Path& path,
*p = 0;
// The pointer to the environment block for the new process.
- char *envblock = 0;
+ std::vector<wchar_t> EnvBlock;
if (envp) {
// An environment block consists of a null-terminated block of
// null-terminated strings. Convert the array of environment variables to
// an environment block by concatenating them.
+ for (unsigned i = 0; envp[i]; ++i) {
+ SmallVector<wchar_t, MAX_PATH> EnvString;
+ if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
+ return false;
+ }
- // First, determine the length of the environment block.
- len = 0;
- for (unsigned i = 0; envp[i]; i++)
- len += strlen(envp[i]) + 1;
-
- // Now build the environment block.
- envblock = reinterpret_cast<char *>(_alloca(len+1));
- p = envblock;
-
- for (unsigned i = 0; envp[i]; i++) {
- const char *ev = envp[i];
- size_t len = strlen(ev) + 1;
- memcpy(p, ev, len);
- p += len;
+ EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end());
+ EnvBlock.push_back(0);
}
-
- *p = 0;
+ EnvBlock.push_back(0);
}
// Create a child process.
- STARTUPINFO si;
+ STARTUPINFOW si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.hStdInput = INVALID_HANDLE_VALUE;
@@ -296,9 +264,14 @@ Program::Execute(const Path& path,
if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
// If stdout and stderr should go to the same place, redirect stderr
// to the handle already open for stdout.
- DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
- GetCurrentProcess(), &si.hStdError,
- 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
+ GetCurrentProcess(), &si.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ MakeErrMsg(ErrMsg, "can't dup stderr to stdout");
+ return false;
+ }
} else {
// Just redirect stderr
si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
@@ -316,8 +289,27 @@ Program::Execute(const Path& path,
fflush(stdout);
fflush(stderr);
- BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0,
- envblock, NULL, &si, &pi);
+
+ SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
+ if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg,
+ std::string("Unable to convert application name to UTF-16"));
+ return false;
+ }
+
+ SmallVector<wchar_t, MAX_PATH> CommandUtf16;
+ if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg,
+ std::string("Unable to convert command-line to UTF-16"));
+ return false;
+ }
+
+ BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0,
+ TRUE, CREATE_UNICODE_ENVIRONMENT,
+ EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si,
+ &pi);
DWORD err = GetLastError();
// Regardless of whether the process got created or not, we are done with
@@ -330,13 +322,12 @@ Program::Execute(const Path& path,
if (!rc) {
SetLastError(err);
MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
- path.str() + "'");
+ Program.str() + "'");
return false;
}
- Win32ProcessInfo* wpi = new Win32ProcessInfo;
- wpi->hProcess = pi.hProcess;
- wpi->dwProcessId = pi.dwProcessId;
- Data_ = wpi;
+
+ PI.Pid = pi.dwProcessId;
+ PI.ProcessHandle = pi.hProcess;
// Make sure these get closed no matter what.
ScopedCommonHandle hThread(pi.hThread);
@@ -344,7 +335,7 @@ Program::Execute(const Path& path,
// Assign the process to a job if a memory limit is defined.
ScopedJobHandle hJob;
if (memoryLimit != 0) {
- hJob = CreateJobObject(0, 0);
+ hJob = CreateJobObjectW(0, 0);
bool success = false;
if (hJob) {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
@@ -369,72 +360,84 @@ Program::Execute(const Path& path,
return true;
}
-int
-Program::Wait(const Path &path,
- unsigned secondsToWait,
- std::string* ErrMsg) {
- if (Data_ == 0) {
- MakeErrMsg(ErrMsg, "Process not started!");
- return -1;
- }
-
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- HANDLE hProcess = wpi->hProcess;
-
- // Wait for the process to terminate.
- DWORD millisecondsToWait = INFINITE;
- if (secondsToWait > 0)
- millisecondsToWait = secondsToWait * 1000;
-
- if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
- if (!TerminateProcess(hProcess, 1)) {
- MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
- // -2 indicates a crash or timeout as opposed to failure to execute.
- return -2;
+namespace llvm {
+ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
+ bool WaitUntilChildTerminates, std::string *ErrMsg) {
+ assert(PI.Pid && "invalid pid to wait on, process not started?");
+ assert(PI.ProcessHandle &&
+ "invalid process handle to wait on, process not started?");
+ DWORD milliSecondsToWait = 0;
+ if (WaitUntilChildTerminates)
+ milliSecondsToWait = INFINITE;
+ else if (SecondsToWait > 0)
+ milliSecondsToWait = SecondsToWait * 1000;
+
+ ProcessInfo WaitResult = PI;
+ DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait);
+ if (WaitStatus == WAIT_TIMEOUT) {
+ if (SecondsToWait) {
+ if (!TerminateProcess(PI.ProcessHandle, 1)) {
+ if (ErrMsg)
+ MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
+
+ // -2 indicates a crash or timeout as opposed to failure to execute.
+ WaitResult.ReturnCode = -2;
+ CloseHandle(PI.ProcessHandle);
+ return WaitResult;
+ }
+ WaitForSingleObject(PI.ProcessHandle, INFINITE);
+ CloseHandle(PI.ProcessHandle);
+ } else {
+ // Non-blocking wait.
+ return ProcessInfo();
}
- WaitForSingleObject(hProcess, INFINITE);
}
// Get its exit status.
DWORD status;
- BOOL rc = GetExitCodeProcess(hProcess, &status);
+ BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status);
DWORD err = GetLastError();
+ CloseHandle(PI.ProcessHandle);
if (!rc) {
SetLastError(err);
- MakeErrMsg(ErrMsg, "Failed getting status for program.");
+ if (ErrMsg)
+ MakeErrMsg(ErrMsg, "Failed getting status for program.");
+
// -2 indicates a crash or timeout as opposed to failure to execute.
- return -2;
+ WaitResult.ReturnCode = -2;
+ return WaitResult;
}
if (!status)
- return 0;
+ return WaitResult;
// Pass 10(Warning) and 11(Error) to the callee as negative value.
if ((status & 0xBFFF0000U) == 0x80000000U)
- return (int)status;
-
- if (status & 0xFF)
- return status & 0x7FFFFFFF;
+ WaitResult.ReturnCode = static_cast<int>(status);
+ else if (status & 0xFF)
+ WaitResult.ReturnCode = status & 0x7FFFFFFF;
+ else
+ WaitResult.ReturnCode = 1;
- return 1;
+ return WaitResult;
}
-error_code Program::ChangeStdinToBinary(){
+error_code sys::ChangeStdinToBinary(){
int result = _setmode( _fileno(stdin), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
return make_error_code(errc::success);
}
-error_code Program::ChangeStdoutToBinary(){
+error_code sys::ChangeStdoutToBinary(){
int result = _setmode( _fileno(stdout), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
return make_error_code(errc::success);
}
-error_code Program::ChangeStderrToBinary(){
+error_code sys::ChangeStderrToBinary(){
int result = _setmode( _fileno(stderr), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
@@ -456,5 +459,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) {
}
return true;
}
-
}
diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc
index 9593923..c431844 100644
--- a/contrib/llvm/lib/Support/Windows/RWMutex.inc
+++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc
@@ -48,8 +48,7 @@ static bool loadSRW() {
if (!sChecked) {
sChecked = true;
- HMODULE hLib = ::LoadLibrary(TEXT("Kernel32"));
- if (hLib) {
+ if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
fpInitializeSRWLock =
(VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
"InitializeSRWLock");
@@ -65,7 +64,6 @@ static bool loadSRW() {
fpReleaseSRWLockShared =
(VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
"ReleaseSRWLockShared");
- ::FreeLibrary(hLib);
if (fpInitializeSRWLock != NULL) {
sHasSRW = true;
diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc
index b18b4d1..4b40d51 100644
--- a/contrib/llvm/lib/Support/Windows/Signals.inc
+++ b/contrib/llvm/lib/Support/Windows/Signals.inc
@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/FileSystem.h"
+
#include "Windows.h"
#include <algorithm>
#include <stdio.h>
@@ -133,7 +135,7 @@ typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
static fpSymFunctionTableAccess64 SymFunctionTableAccess64;
static bool load64BitDebugHelp(void) {
- HMODULE hLib = ::LoadLibrary("Dbghelp.dll");
+ HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
if (hLib) {
StackWalk64 = (fpStackWalk64)
::GetProcAddress(hLib, "StackWalk64");
@@ -158,7 +160,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
// InterruptFunction - The function to call if ctrl-c is pressed.
static void (*InterruptFunction)() = 0;
-static std::vector<llvm::sys::Path> *FilesToRemove = NULL;
+static std::vector<std::string> *FilesToRemove = NULL;
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
static bool RegisteredUnhandledExceptionFilter = false;
static bool CleanupExecuted = false;
@@ -191,34 +193,6 @@ static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
return TRUE;
}
-/// CRTReportHook - Function called on a CRT debugging event.
-static int CRTReportHook(int ReportType, char *Message, int *Return) {
- // Don't cause a DebugBreak() on return.
- if (Return)
- *Return = 0;
-
- switch (ReportType) {
- default:
- case _CRT_ASSERT:
- fprintf(stderr, "CRT assert: %s\n", Message);
- // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
- // exception code? Perhaps SetErrorMode() handles this.
- _exit(3);
- break;
- case _CRT_ERROR:
- fprintf(stderr, "CRT error: %s\n", Message);
- // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
- // exception code? Perhaps SetErrorMode() handles this.
- _exit(3);
- break;
- case _CRT_WARN:
- fprintf(stderr, "CRT warn: %s\n", Message);
- break;
- }
-
- // Don't call _CrtDbgReport.
- return TRUE;
-}
#endif
static void RegisterHandler() {
@@ -251,19 +225,10 @@ static void RegisterHandler() {
OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
-#ifdef _MSC_VER
- const char *EnableMsgbox = getenv("LLVM_ENABLE_CRT_REPORT");
- if (!EnableMsgbox || strcmp("0", EnableMsgbox) == 0) {
- // Setting a report hook overrides the default behavior of popping an "abort,
- // retry, or ignore" dialog.
- _CrtSetReportHook(AvoidMessageBoxHook);
- }
-#endif
-
// Environment variable to disable any kind of crash dialog.
if (getenv("LLVM_DISABLE_CRASH_REPORT")) {
#ifdef _MSC_VER
- _CrtSetReportHook(CRTReportHook);
+ _CrtSetReportHook(AvoidMessageBoxHook);
#endif
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
@@ -276,7 +241,7 @@ static void RegisterHandler() {
}
// RemoveFileOnSignal - The public API
-bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
+bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
RegisterHandler();
if (CleanupExecuted) {
@@ -286,7 +251,7 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
}
if (FilesToRemove == NULL)
- FilesToRemove = new std::vector<sys::Path>;
+ FilesToRemove = new std::vector<std::string>;
FilesToRemove->push_back(Filename);
@@ -295,14 +260,14 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
}
// DontRemoveFileOnSignal - The public API
-void sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
+void sys::DontRemoveFileOnSignal(StringRef Filename) {
if (FilesToRemove == NULL)
return;
RegisterHandler();
FilesToRemove->push_back(Filename);
- std::vector<sys::Path>::reverse_iterator I =
+ std::vector<std::string>::reverse_iterator I =
std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
if (I != FilesToRemove->rend())
FilesToRemove->erase(I.base()-1);
@@ -352,7 +317,8 @@ static void Cleanup() {
if (FilesToRemove != NULL)
while (!FilesToRemove->empty()) {
- FilesToRemove->back().eraseFromDisk();
+ bool Existed;
+ llvm::sys::fs::remove(FilesToRemove->back(), Existed);
FilesToRemove->pop_back();
}
diff --git a/contrib/llvm/lib/Support/Windows/TimeValue.inc b/contrib/llvm/lib/Support/Windows/TimeValue.inc
index 1227552..98b07d6 100644
--- a/contrib/llvm/lib/Support/Windows/TimeValue.inc
+++ b/contrib/llvm/lib/Support/Windows/TimeValue.inc
@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#include "Windows.h"
+#include <cctype>
#include <time.h>
-namespace llvm {
-using namespace sys;
+using namespace llvm;
+using namespace llvm::sys;
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Win32 specific code.
@@ -31,21 +32,28 @@ TimeValue TimeValue::now() {
}
std::string TimeValue::str() const {
+ struct tm *LT;
#ifdef __MINGW32__
- // This ban may be lifted by either:
- // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or
- // (ii) configure tests for either the time_t or __time64_t type.
- time_t ourTime = time_t(this->toEpochTime());
- struct tm *lt = ::localtime(&ourTime);
+ // Old versions of mingw don't have _localtime64_s. Remove this once we drop support
+ // for them.
+ time_t OurTime = time_t(this->toEpochTime());
+ LT = ::localtime(&OurTime);
+ assert(LT);
#else
- __time64_t ourTime = this->toEpochTime();
- struct tm *lt = ::_localtime64(&ourTime);
+ struct tm Storage;
+ __time64_t OurTime = this->toEpochTime();
+ int Error = ::_localtime64_s(&Storage, &OurTime);
+ assert(!Error);
+ LT = &Storage;
#endif
- char buffer[25];
- strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt);
- return std::string(buffer);
-}
-
-
+ char Buffer[25];
+ // FIXME: the windows version of strftime doesn't support %e
+ strftime(Buffer, 25, "%b %d %H:%M %Y", LT);
+ assert((Buffer[3] == ' ' && isdigit(Buffer[5]) && Buffer[6] == ' ') &&
+ "Unexpected format in strftime()!");
+ // Emulate %e on %d to mute '0'.
+ if (Buffer[4] == '0')
+ Buffer[4] = ' ';
+ return std::string(Buffer);
}
diff --git a/contrib/llvm/lib/Support/Windows/Windows.h b/contrib/llvm/lib/Support/Windows/Windows.h
index 5c1da0d..1f3417d 100644
--- a/contrib/llvm/lib/Support/Windows/Windows.h
+++ b/contrib/llvm/lib/Support/Windows/Windows.h
@@ -24,22 +24,31 @@
#define _WIN32_IE 0x0600 // MinGW at it again.
#define WIN32_LEAN_AND_MEAN
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h" // Get build system configuration settings
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/system_error.h"
#include <windows.h>
#include <wincrypt.h>
-#include <shlobj.h>
#include <cassert>
#include <string>
+#include <vector>
inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) {
if (!ErrMsg)
return true;
char *buffer = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL);
- *ErrMsg = prefix + buffer;
+ DWORD R = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL);
+ if (R)
+ *ErrMsg = prefix + buffer;
+ else
+ *ErrMsg = prefix + "Unknown error";
+
LocalFree(buffer);
- return true;
+ return R != 0;
}
template <typename HandleTraits>
@@ -75,7 +84,7 @@ public:
}
// True if Handle is valid.
- operator bool() const {
+ LLVM_EXPLICIT operator bool() const {
return HandleTraits::IsValid(Handle) ? true : false;
}
@@ -147,4 +156,13 @@ c_str(SmallVectorImpl<T> &str) {
str.pop_back();
return str.data();
}
+
+namespace sys {
+namespace windows {
+error_code UTF8ToUTF16(StringRef utf8,
+ SmallVectorImpl<wchar_t> &utf16);
+error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+} // end namespace windows
+} // end namespace sys
} // end namespace llvm.
OpenPOWER on IntegriCloud