From: Rafael Espindola Date: Wed, 26 Jun 2013 19:33:03 +0000 (+0000) Subject: Rename PathV2 to just Path now that it is the only one. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7a231f5a1e346eff9d7b02f9f24dfb3d79c2f12f;p=oota-llvm.git Rename PathV2 to just Path now that it is the only one. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185015 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 7d27a291399..58238365853 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -73,7 +73,7 @@ add_llvm_library(LLVMSupport IncludeFile.cpp Memory.cpp Mutex.cpp - PathV2.cpp + Path.cpp Process.cpp Program.cpp RWMutex.cpp @@ -89,7 +89,7 @@ add_llvm_library(LLVMSupport Unix/Host.inc Unix/Memory.inc Unix/Mutex.inc - Unix/PathV2.inc + Unix/Path.inc Unix/Process.inc Unix/Program.inc Unix/RWMutex.inc @@ -102,7 +102,7 @@ add_llvm_library(LLVMSupport Windows/Host.inc Windows/Memory.inc Windows/Mutex.inc - Windows/PathV2.inc + Windows/Path.inc Windows/Process.inc Windows/Program.inc Windows/RWMutex.inc diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp new file mode 100644 index 00000000000..8b9e60a2d9e --- /dev/null +++ b/lib/Support/Path.cpp @@ -0,0 +1,969 @@ +//===-- Path.cpp - Implement OS Path Concept ------------------------------===// +// +// 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 operating system Path API. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Path.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include +#include +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#else +#include +#endif + +namespace { + using llvm::StringRef; + using llvm::sys::path::is_separator; + +#ifdef LLVM_ON_WIN32 + const char *separators = "\\/"; + const char prefered_separator = '\\'; +#else + const char separators = '/'; + const char prefered_separator = '/'; +#endif + + StringRef find_first_component(StringRef path) { + // Look for this first component in the following order. + // * empty (in this case we return an empty string) + // * either C: or {//,\\}net. + // * {/,\} + // * {.,..} + // * {file,directory}name + + if (path.empty()) + return path; + +#ifdef LLVM_ON_WIN32 + // C: + if (path.size() >= 2 && std::isalpha(static_cast(path[0])) && + path[1] == ':') + return path.substr(0, 2); +#endif + + // //net + if ((path.size() > 2) && + is_separator(path[0]) && + path[0] == path[1] && + !is_separator(path[2])) { + // Find the next directory separator. + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + // {/,\} + if (is_separator(path[0])) + return path.substr(0, 1); + + if (path.startswith("..")) + return path.substr(0, 2); + + if (path[0] == '.') + return path.substr(0, 1); + + // * {file,directory}name + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + size_t filename_pos(StringRef str) { + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef LLVM_ON_WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(StringRef str) { + // case "c:/" +#ifdef LLVM_ON_WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(StringRef path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } +} // end unnamed namespace + +namespace llvm { +namespace sys { +namespace path { + +const_iterator begin(StringRef path) { + const_iterator i; + i.Path = path; + i.Component = find_first_component(path); + i.Position = 0; + return i; +} + +const_iterator end(StringRef path) { + const_iterator i; + i.Path = path; + i.Position = path.size(); + return i; +} + +const_iterator &const_iterator::operator++() { + assert(Position < Path.size() && "Tried to increment past end!"); + + // Increment Position to past the current component + Position += Component.size(); + + // Check for end. + if (Position == Path.size()) { + Component = StringRef(); + return *this; + } + + // Both POSIX and Windows treat paths that begin with exactly two separators + // specially. + bool was_net = Component.size() > 2 && + is_separator(Component[0]) && + Component[1] == Component[0] && + !is_separator(Component[2]); + + // Handle separators. + if (is_separator(Path[Position])) { + // Root dir. + if (was_net +#ifdef LLVM_ON_WIN32 + // c:/ + || Component.endswith(":") +#endif + ) { + Component = Path.substr(Position, 1); + return *this; + } + + // Skip extra separators. + while (Position != Path.size() && + is_separator(Path[Position])) { + ++Position; + } + + // Treat trailing '/' as a '.'. + if (Position == Path.size()) { + --Position; + Component = "."; + return *this; + } + } + + // Find next component. + size_t end_pos = Path.find_first_of(separators, Position); + Component = Path.slice(Position, end_pos); + + return *this; +} + +const_iterator &const_iterator::operator--() { + // If we're at the end and the previous char was a '/', return '.'. + if (Position == Path.size() && + Path.size() > 1 && + is_separator(Path[Position - 1]) +#ifdef LLVM_ON_WIN32 + && Path[Position - 2] != ':' +#endif + ) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t root_dir_pos = root_dir_start(Path); + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(Path.substr(0, end_pos)); + Component = Path.slice(start_pos, end_pos); + Position = start_pos; + return *this; +} + +bool const_iterator::operator==(const const_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && + Position == RHS.Position; +} + +bool const_iterator::operator!=(const const_iterator &RHS) const { + return !(*this == RHS); +} + +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + +const StringRef root_path(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + if ((++pos != e) && is_separator((*pos)[0])) { + // {C:/,//net/}, so get the first two components. + return path.substr(0, b->size() + pos->size()); + } else { + // just {C:,//net}, return the first component. + return *b; + } + } + + // POSIX style root directory. + if (is_separator((*b)[0])) { + return *b; + } + } + + return StringRef(); +} + +const StringRef root_name(StringRef path) { + const_iterator b = begin(path), + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + // just {C:,//net}, return the first component. + return *b; + } + } + + // No path or no name. + return StringRef(); +} + +const StringRef root_directory(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if ((has_net || has_drive) && + // {C:,//net}, skip to the next component. + (++pos != e) && is_separator((*pos)[0])) { + return *pos; + } + + // POSIX style root directory. + if (!has_net && is_separator((*b)[0])) { + return *b; + } + } + + // No path or no root. + return StringRef(); +} + +const StringRef relative_path(StringRef path) { + StringRef root = root_path(path); + return path.substr(root.size()); +} + +void append(SmallVectorImpl &path, const Twine &a, + const Twine &b, + const Twine &c, + const Twine &d) { + SmallString<32> a_storage; + SmallString<32> b_storage; + SmallString<32> c_storage; + SmallString<32> d_storage; + + SmallVector components; + if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); + if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); + if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); + if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); + + for (SmallVectorImpl::const_iterator i = components.begin(), + e = components.end(); + i != e; ++i) { + bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); + bool component_has_sep = !i->empty() && is_separator((*i)[0]); + bool is_root_name = has_root_name(*i); + + if (path_has_sep) { + // Strip separators from beginning of component. + size_t loc = i->find_first_not_of(separators); + StringRef c = i->substr(loc); + + // Append it. + path.append(c.begin(), c.end()); + continue; + } + + if (!component_has_sep && !(path.empty() || is_root_name)) { + // Add a separator. + path.push_back(prefered_separator); + } + + path.append(i->begin(), i->end()); + } +} + +void append(SmallVectorImpl &path, + const_iterator begin, const_iterator end) { + for (; begin != end; ++begin) + path::append(path, *begin); +} + +const StringRef parent_path(StringRef path) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + return StringRef(); + else + return path.substr(0, end_pos); +} + +void remove_filename(SmallVectorImpl &path) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); + if (end_pos != StringRef::npos) + path.set_size(end_pos); +} + +void replace_extension(SmallVectorImpl &path, const Twine &extension) { + StringRef p(path.begin(), path.size()); + SmallString<32> ext_storage; + StringRef ext = extension.toStringRef(ext_storage); + + // Erase existing extension. + size_t pos = p.find_last_of('.'); + if (pos != StringRef::npos && pos >= filename_pos(p)) + path.set_size(pos); + + // Append '.' if needed. + if (ext.size() > 0 && ext[0] != '.') + path.push_back('.'); + + // Append extension. + path.append(ext.begin(), ext.end()); +} + +void native(const Twine &path, SmallVectorImpl &result) { + // Clear result. + result.clear(); +#ifdef LLVM_ON_WIN32 + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + result.reserve(p.size()); + for (StringRef::const_iterator i = p.begin(), + e = p.end(); + i != e; + ++i) { + if (*i == '/') + result.push_back('\\'); + else + result.push_back(*i); + } +#else + path.toVector(result); +#endif +} + +const StringRef filename(StringRef path) { + return *(--end(path)); +} + +const StringRef stem(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return fname; + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + else + return fname.substr(0, pos); +} + +const StringRef extension(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return StringRef(); + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + else + return fname.substr(pos); +} + +bool is_separator(char value) { + switch(value) { +#ifdef LLVM_ON_WIN32 + case '\\': // fall through +#endif + case '/': return true; + default: return false; + } +} + +void system_temp_directory(bool erasedOnReboot, SmallVectorImpl &result) { + result.clear(); + +#ifdef __APPLE__ + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, 0, 0); + if (ConfLen > 0) { + do { + result.resize(ConfLen); + ConfLen = confstr(ConfName, result.data(), result.size()); + } while (ConfLen > 0 && ConfLen != result.size()); + + if (ConfLen > 0) { + assert(result.back() == 0); + result.pop_back(); + return; + } + + result.clear(); + } +#endif + + // Check whether the temporary directory is specified by an environment + // variable. + const char *EnvironmentVariable; +#ifdef LLVM_ON_WIN32 + EnvironmentVariable = "TEMP"; +#else + EnvironmentVariable = "TMPDIR"; +#endif + if (char *RequestedDir = getenv(EnvironmentVariable)) { + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return; + } + + // Fall back to a system default. + const char *DefaultResult; +#ifdef LLVM_ON_WIN32 + (void)erasedOnReboot; + DefaultResult = "C:\\TEMP"; +#else + if (erasedOnReboot) + DefaultResult = "/tmp"; + else + DefaultResult = "/var/tmp"; +#endif + result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} + +bool has_root_name(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_name(p).empty(); +} + +bool has_root_directory(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_directory(p).empty(); +} + +bool has_root_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_path(p).empty(); +} + +bool has_relative_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !relative_path(p).empty(); +} + +bool has_filename(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !filename(p).empty(); +} + +bool has_parent_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !parent_path(p).empty(); +} + +bool has_stem(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !stem(p).empty(); +} + +bool has_extension(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !extension(p).empty(); +} + +bool is_absolute(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + bool rootDir = has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = has_root_name(p); +#else + rootName = true; +#endif + + return rootDir && rootName; +} + +bool is_relative(const Twine &path) { + return !is_absolute(path); +} + +} // end namespace path + +namespace fs { + +error_code unique_file(const Twine &Model, SmallVectorImpl &ResultPath, + bool MakeAbsolute, unsigned Mode) { + // FIXME: This is really inefficient. unique_path creates a path an tries to + // open it. We should factor the code so that we just don't create/open the + // file when we don't need it. + int FD; + error_code Ret = unique_file(Model, FD, ResultPath, MakeAbsolute, Mode); + if (Ret) + return Ret; + + if (close(FD)) + return error_code(errno, system_category()); + + StringRef P(ResultPath.begin(), ResultPath.size()); + return fs::remove(P); +} + +error_code make_absolute(SmallVectorImpl &path) { + StringRef p(path.data(), path.size()); + + bool rootDirectory = path::has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = path::has_root_name(p); +#else + rootName = true; +#endif + + // Already absolute. + if (rootName && rootDirectory) + return error_code::success(); + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + if (error_code ec = current_path(current_dir)) return ec; + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + path::append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return error_code::success(); + } + + if (!rootName && rootDirectory) { + StringRef cdrn = path::root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + path::append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return error_code::success(); + } + + if (rootName && !rootDirectory) { + StringRef pRootName = path::root_name(p); + StringRef bRootDirectory = path::root_directory(current_dir); + StringRef bRelativePath = path::relative_path(current_dir); + StringRef pRelativePath = path::relative_path(p); + + SmallString<128> res; + path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return error_code::success(); + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + +error_code create_directories(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + StringRef parent = path::parent_path(p); + if (!parent.empty()) { + bool parent_exists; + if (error_code ec = fs::exists(parent, parent_exists)) return ec; + + if (!parent_exists) + if (error_code ec = create_directories(parent, existed)) return ec; + } + + return create_directory(p, existed); +} + +bool exists(file_status status) { + return status_known(status) && status.type() != file_type::file_not_found; +} + +bool status_known(file_status s) { + return s.type() != file_type::status_error; +} + +bool is_directory(file_status status) { + return status.type() == file_type::directory_file; +} + +error_code is_directory(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_directory(st); + return error_code::success(); +} + +bool is_regular_file(file_status status) { + return status.type() == file_type::regular_file; +} + +error_code is_regular_file(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_regular_file(st); + return error_code::success(); +} + +bool is_symlink(file_status status) { + return status.type() == file_type::symlink_file; +} + +error_code is_symlink(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_symlink(st); + return error_code::success(); +} + +bool is_other(file_status status) { + return exists(status) && + !is_regular_file(status) && + !is_directory(status) && + !is_symlink(status); +} + +void directory_entry::replace_filename(const Twine &filename, file_status st) { + SmallString<128> path(Path.begin(), Path.end()); + path::remove_filename(path); + path::append(path, filename); + Path = path.str(); + Status = st; +} + +error_code has_magic(const Twine &path, const Twine &magic, bool &result) { + SmallString<32> MagicStorage; + StringRef Magic = magic.toStringRef(MagicStorage); + SmallString<32> Buffer; + + if (error_code ec = get_magic(path, Magic.size(), Buffer)) { + if (ec == errc::value_too_large) { + // Magic.size() > file_size(Path). + result = false; + return error_code::success(); + } + return ec; + } + + result = Magic == Buffer; + return error_code::success(); +} + +/// @brief Identify the magic in magic. + file_magic identify_magic(StringRef Magic) { + if (Magic.size() < 4) + return file_magic::unknown; + switch ((unsigned char)Magic[0]) { + case 0xDE: // 0x0B17C0DE = BC wraper + if (Magic[1] == (char)0xC0 && Magic[2] == (char)0x17 && + Magic[3] == (char)0x0B) + return file_magic::bitcode; + break; + case 'B': + if (Magic[1] == 'C' && Magic[2] == (char)0xC0 && Magic[3] == (char)0xDE) + return file_magic::bitcode; + break; + case '!': + if (Magic.size() >= 8) + if (memcmp(Magic.data(),"!\n",8) == 0) + return file_magic::archive; + break; + + case '\177': + if (Magic.size() >= 18 && Magic[1] == 'E' && Magic[2] == 'L' && + Magic[3] == 'F') { + bool Data2MSB = Magic[5] == 2; + unsigned high = Data2MSB ? 16 : 17; + unsigned low = Data2MSB ? 17 : 16; + if (Magic[high] == 0) + switch (Magic[low]) { + default: break; + case 1: return file_magic::elf_relocatable; + case 2: return file_magic::elf_executable; + case 3: return file_magic::elf_shared_object; + case 4: return file_magic::elf_core; + } + } + break; + + case 0xCA: + if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) && + Magic[3] == char(0xBE)) { + // This is complicated by an overlap with Java class files. + // See the Mach-O section in /usr/share/file/magic for details. + if (Magic.size() >= 8 && Magic[7] < 43) + return file_magic::macho_universal_binary; + } + break; + + // The two magic numbers for mach-o are: + // 0xfeedface - 32-bit mach-o + // 0xfeedfacf - 64-bit mach-o + case 0xFE: + case 0xCE: + case 0xCF: { + uint16_t type = 0; + if (Magic[0] == char(0xFE) && Magic[1] == char(0xED) && + Magic[2] == char(0xFA) && + (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) { + /* Native endian */ + if (Magic.size() >= 16) type = Magic[14] << 8 | Magic[15]; + } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) && + Magic[1] == char(0xFA) && Magic[2] == char(0xED) && + Magic[3] == char(0xFE)) { + /* Reverse endian */ + if (Magic.size() >= 14) type = Magic[13] << 8 | Magic[12]; + } + switch (type) { + default: break; + case 1: return file_magic::macho_object; + case 2: return file_magic::macho_executable; + case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; + case 4: return file_magic::macho_core; + case 5: return file_magic::macho_preload_executable; + case 6: return file_magic::macho_dynamically_linked_shared_lib; + case 7: return file_magic::macho_dynamic_linker; + case 8: return file_magic::macho_bundle; + case 9: return file_magic::macho_dynamic_linker; + case 10: return file_magic::macho_dsym_companion; + } + break; + } + case 0xF0: // PowerPC Windows + case 0x83: // Alpha 32-bit + case 0x84: // Alpha 64-bit + case 0x66: // MPS R4000 Windows + case 0x50: // mc68K + case 0x4c: // 80386 Windows + if (Magic[1] == 0x01) + return file_magic::coff_object; + + case 0x90: // PA-RISC Windows + case 0x68: // mc68K Windows + if (Magic[1] == 0x02) + return file_magic::coff_object; + break; + + case 0x4d: // Possible MS-DOS stub on Windows PE file + if (Magic[1] == 0x5a) { + uint32_t off = + *reinterpret_cast(Magic.data() + 0x3c); + // PE/COFF file, either EXE or DLL. + if (off < Magic.size() && memcmp(Magic.data() + off, "PE\0\0",4) == 0) + return file_magic::pecoff_executable; + } + break; + + case 0x64: // x86-64 Windows. + if (Magic[1] == char(0x86)) + return file_magic::coff_object; + break; + + default: + break; + } + return file_magic::unknown; +} + +error_code identify_magic(const Twine &path, file_magic &result) { + SmallString<32> Magic; + error_code ec = get_magic(path, Magic.capacity(), Magic); + if (ec && ec != errc::value_too_large) + return ec; + + result = identify_magic(Magic); + return error_code::success(); +} + +namespace { +error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { + if (ft == file_type::directory_file) { + // This code would be a lot better with exceptions ;/. + error_code ec; + directory_iterator i(path, ec); + if (ec) return ec; + for (directory_iterator e; i != e; i.increment(ec)) { + if (ec) return ec; + file_status st; + if (error_code ec = i->status(st)) return ec; + if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; + } + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; // Include the directory itself in the items removed. + } else { + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; + } + + return error_code::success(); +} +} // end unnamed namespace + +error_code remove_all(const Twine &path, uint32_t &num_removed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + file_status fs; + if (error_code ec = status(path, fs)) + return ec; + num_removed = 0; + return remove_all_r(p, fs.type(), num_removed); +} + +error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result); +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +// Include the truly platform-specific parts. +#if defined(LLVM_ON_UNIX) +#include "Unix/Path.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/Path.inc" +#endif diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp deleted file mode 100644 index c0be6f4ea16..00000000000 --- a/lib/Support/PathV2.cpp +++ /dev/null @@ -1,969 +0,0 @@ -//===-- PathV2.cpp - Implement OS Path Concept ------------------*- 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 operating system PathV2 API. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Path.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileSystem.h" -#include -#include -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#else -#include -#endif - -namespace { - using llvm::StringRef; - using llvm::sys::path::is_separator; - -#ifdef LLVM_ON_WIN32 - const char *separators = "\\/"; - const char prefered_separator = '\\'; -#else - const char separators = '/'; - const char prefered_separator = '/'; -#endif - - StringRef find_first_component(StringRef path) { - // Look for this first component in the following order. - // * empty (in this case we return an empty string) - // * either C: or {//,\\}net. - // * {/,\} - // * {.,..} - // * {file,directory}name - - if (path.empty()) - return path; - -#ifdef LLVM_ON_WIN32 - // C: - if (path.size() >= 2 && std::isalpha(static_cast(path[0])) && - path[1] == ':') - return path.substr(0, 2); -#endif - - // //net - if ((path.size() > 2) && - is_separator(path[0]) && - path[0] == path[1] && - !is_separator(path[2])) { - // Find the next directory separator. - size_t end = path.find_first_of(separators, 2); - return path.substr(0, end); - } - - // {/,\} - if (is_separator(path[0])) - return path.substr(0, 1); - - if (path.startswith("..")) - return path.substr(0, 2); - - if (path[0] == '.') - return path.substr(0, 1); - - // * {file,directory}name - size_t end = path.find_first_of(separators, 2); - return path.substr(0, end); - } - - size_t filename_pos(StringRef str) { - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) - return 0; - - if (str.size() > 0 && is_separator(str[str.size() - 1])) - return str.size() - 1; - - size_t pos = str.find_last_of(separators, str.size() - 1); - -#ifdef LLVM_ON_WIN32 - if (pos == StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); -#endif - - if (pos == StringRef::npos || - (pos == 1 && is_separator(str[0]))) - return 0; - - return pos + 1; - } - - size_t root_dir_start(StringRef str) { - // case "c:/" -#ifdef LLVM_ON_WIN32 - if (str.size() > 2 && - str[1] == ':' && - is_separator(str[2])) - return 2; -#endif - - // case "//" - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) - return StringRef::npos; - - // case "//net" - if (str.size() > 3 && - is_separator(str[0]) && - str[0] == str[1] && - !is_separator(str[2])) { - return str.find_first_of(separators, 2); - } - - // case "/" - if (str.size() > 0 && is_separator(str[0])) - return 0; - - return StringRef::npos; - } - - size_t parent_path_end(StringRef path) { - size_t end_pos = filename_pos(path); - - bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); - - // Skip separators except for root dir. - size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); - - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(path[end_pos - 1])) - --end_pos; - - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return StringRef::npos; - - return end_pos; - } -} // end unnamed namespace - -namespace llvm { -namespace sys { -namespace path { - -const_iterator begin(StringRef path) { - const_iterator i; - i.Path = path; - i.Component = find_first_component(path); - i.Position = 0; - return i; -} - -const_iterator end(StringRef path) { - const_iterator i; - i.Path = path; - i.Position = path.size(); - return i; -} - -const_iterator &const_iterator::operator++() { - assert(Position < Path.size() && "Tried to increment past end!"); - - // Increment Position to past the current component - Position += Component.size(); - - // Check for end. - if (Position == Path.size()) { - Component = StringRef(); - return *this; - } - - // Both POSIX and Windows treat paths that begin with exactly two separators - // specially. - bool was_net = Component.size() > 2 && - is_separator(Component[0]) && - Component[1] == Component[0] && - !is_separator(Component[2]); - - // Handle separators. - if (is_separator(Path[Position])) { - // Root dir. - if (was_net -#ifdef LLVM_ON_WIN32 - // c:/ - || Component.endswith(":") -#endif - ) { - Component = Path.substr(Position, 1); - return *this; - } - - // Skip extra separators. - while (Position != Path.size() && - is_separator(Path[Position])) { - ++Position; - } - - // Treat trailing '/' as a '.'. - if (Position == Path.size()) { - --Position; - Component = "."; - return *this; - } - } - - // Find next component. - size_t end_pos = Path.find_first_of(separators, Position); - Component = Path.slice(Position, end_pos); - - return *this; -} - -const_iterator &const_iterator::operator--() { - // If we're at the end and the previous char was a '/', return '.'. - if (Position == Path.size() && - Path.size() > 1 && - is_separator(Path[Position - 1]) -#ifdef LLVM_ON_WIN32 - && Path[Position - 2] != ':' -#endif - ) { - --Position; - Component = "."; - return *this; - } - - // Skip separators unless it's the root directory. - size_t root_dir_pos = root_dir_start(Path); - size_t end_pos = Position; - - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(Path[end_pos - 1])) - --end_pos; - - // Find next separator. - size_t start_pos = filename_pos(Path.substr(0, end_pos)); - Component = Path.slice(start_pos, end_pos); - Position = start_pos; - return *this; -} - -bool const_iterator::operator==(const const_iterator &RHS) const { - return Path.begin() == RHS.Path.begin() && - Position == RHS.Position; -} - -bool const_iterator::operator!=(const const_iterator &RHS) const { - return !(*this == RHS); -} - -ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { - return Position - RHS.Position; -} - -const StringRef root_path(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if (has_net || has_drive) { - if ((++pos != e) && is_separator((*pos)[0])) { - // {C:/,//net/}, so get the first two components. - return path.substr(0, b->size() + pos->size()); - } else { - // just {C:,//net}, return the first component. - return *b; - } - } - - // POSIX style root directory. - if (is_separator((*b)[0])) { - return *b; - } - } - - return StringRef(); -} - -const StringRef root_name(StringRef path) { - const_iterator b = begin(path), - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if (has_net || has_drive) { - // just {C:,//net}, return the first component. - return *b; - } - } - - // No path or no name. - return StringRef(); -} - -const StringRef root_directory(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); - if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif - - if ((has_net || has_drive) && - // {C:,//net}, skip to the next component. - (++pos != e) && is_separator((*pos)[0])) { - return *pos; - } - - // POSIX style root directory. - if (!has_net && is_separator((*b)[0])) { - return *b; - } - } - - // No path or no root. - return StringRef(); -} - -const StringRef relative_path(StringRef path) { - StringRef root = root_path(path); - return path.substr(root.size()); -} - -void append(SmallVectorImpl &path, const Twine &a, - const Twine &b, - const Twine &c, - const Twine &d) { - SmallString<32> a_storage; - SmallString<32> b_storage; - SmallString<32> c_storage; - SmallString<32> d_storage; - - SmallVector components; - if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); - if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); - if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); - if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); - - for (SmallVectorImpl::const_iterator i = components.begin(), - e = components.end(); - i != e; ++i) { - bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); - bool component_has_sep = !i->empty() && is_separator((*i)[0]); - bool is_root_name = has_root_name(*i); - - if (path_has_sep) { - // Strip separators from beginning of component. - size_t loc = i->find_first_not_of(separators); - StringRef c = i->substr(loc); - - // Append it. - path.append(c.begin(), c.end()); - continue; - } - - if (!component_has_sep && !(path.empty() || is_root_name)) { - // Add a separator. - path.push_back(prefered_separator); - } - - path.append(i->begin(), i->end()); - } -} - -void append(SmallVectorImpl &path, - const_iterator begin, const_iterator end) { - for (; begin != end; ++begin) - path::append(path, *begin); -} - -const StringRef parent_path(StringRef path) { - size_t end_pos = parent_path_end(path); - if (end_pos == StringRef::npos) - return StringRef(); - else - return path.substr(0, end_pos); -} - -void remove_filename(SmallVectorImpl &path) { - size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); - if (end_pos != StringRef::npos) - path.set_size(end_pos); -} - -void replace_extension(SmallVectorImpl &path, const Twine &extension) { - StringRef p(path.begin(), path.size()); - SmallString<32> ext_storage; - StringRef ext = extension.toStringRef(ext_storage); - - // Erase existing extension. - size_t pos = p.find_last_of('.'); - if (pos != StringRef::npos && pos >= filename_pos(p)) - path.set_size(pos); - - // Append '.' if needed. - if (ext.size() > 0 && ext[0] != '.') - path.push_back('.'); - - // Append extension. - path.append(ext.begin(), ext.end()); -} - -void native(const Twine &path, SmallVectorImpl &result) { - // Clear result. - result.clear(); -#ifdef LLVM_ON_WIN32 - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - result.reserve(p.size()); - for (StringRef::const_iterator i = p.begin(), - e = p.end(); - i != e; - ++i) { - if (*i == '/') - result.push_back('\\'); - else - result.push_back(*i); - } -#else - path.toVector(result); -#endif -} - -const StringRef filename(StringRef path) { - return *(--end(path)); -} - -const StringRef stem(StringRef path) { - StringRef fname = filename(path); - size_t pos = fname.find_last_of('.'); - if (pos == StringRef::npos) - return fname; - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return fname; - else - return fname.substr(0, pos); -} - -const StringRef extension(StringRef path) { - StringRef fname = filename(path); - size_t pos = fname.find_last_of('.'); - if (pos == StringRef::npos) - return StringRef(); - else - if ((fname.size() == 1 && fname == ".") || - (fname.size() == 2 && fname == "..")) - return StringRef(); - else - return fname.substr(pos); -} - -bool is_separator(char value) { - switch(value) { -#ifdef LLVM_ON_WIN32 - case '\\': // fall through -#endif - case '/': return true; - default: return false; - } -} - -void system_temp_directory(bool erasedOnReboot, SmallVectorImpl &result) { - result.clear(); - -#ifdef __APPLE__ - // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. - int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR - : _CS_DARWIN_USER_CACHE_DIR; - size_t ConfLen = confstr(ConfName, 0, 0); - if (ConfLen > 0) { - do { - result.resize(ConfLen); - ConfLen = confstr(ConfName, result.data(), result.size()); - } while (ConfLen > 0 && ConfLen != result.size()); - - if (ConfLen > 0) { - assert(result.back() == 0); - result.pop_back(); - return; - } - - result.clear(); - } -#endif - - // Check whether the temporary directory is specified by an environment - // variable. - const char *EnvironmentVariable; -#ifdef LLVM_ON_WIN32 - EnvironmentVariable = "TEMP"; -#else - EnvironmentVariable = "TMPDIR"; -#endif - if (char *RequestedDir = getenv(EnvironmentVariable)) { - result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); - return; - } - - // Fall back to a system default. - const char *DefaultResult; -#ifdef LLVM_ON_WIN32 - (void)erasedOnReboot; - DefaultResult = "C:\\TEMP"; -#else - if (erasedOnReboot) - DefaultResult = "/tmp"; - else - DefaultResult = "/var/tmp"; -#endif - result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); -} - -bool has_root_name(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_name(p).empty(); -} - -bool has_root_directory(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_directory(p).empty(); -} - -bool has_root_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !root_path(p).empty(); -} - -bool has_relative_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !relative_path(p).empty(); -} - -bool has_filename(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !filename(p).empty(); -} - -bool has_parent_path(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !parent_path(p).empty(); -} - -bool has_stem(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !stem(p).empty(); -} - -bool has_extension(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - return !extension(p).empty(); -} - -bool is_absolute(const Twine &path) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - bool rootDir = has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = has_root_name(p); -#else - rootName = true; -#endif - - return rootDir && rootName; -} - -bool is_relative(const Twine &path) { - return !is_absolute(path); -} - -} // end namespace path - -namespace fs { - -error_code unique_file(const Twine &Model, SmallVectorImpl &ResultPath, - bool MakeAbsolute, unsigned Mode) { - // FIXME: This is really inefficient. unique_path creates a path an tries to - // open it. We should factor the code so that we just don't create/open the - // file when we don't need it. - int FD; - error_code Ret = unique_file(Model, FD, ResultPath, MakeAbsolute, Mode); - if (Ret) - return Ret; - - if (close(FD)) - return error_code(errno, system_category()); - - StringRef P(ResultPath.begin(), ResultPath.size()); - return fs::remove(P); -} - -error_code make_absolute(SmallVectorImpl &path) { - StringRef p(path.data(), path.size()); - - bool rootDirectory = path::has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = path::has_root_name(p); -#else - rootName = true; -#endif - - // Already absolute. - if (rootName && rootDirectory) - return error_code::success(); - - // All of the following conditions will need the current directory. - SmallString<128> current_dir; - if (error_code ec = current_path(current_dir)) return ec; - - // Relative path. Prepend the current directory. - if (!rootName && !rootDirectory) { - // Append path to the current directory. - path::append(current_dir, p); - // Set path to the result. - path.swap(current_dir); - return error_code::success(); - } - - if (!rootName && rootDirectory) { - StringRef cdrn = path::root_name(current_dir); - SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); - path::append(curDirRootName, p); - // Set path to the result. - path.swap(curDirRootName); - return error_code::success(); - } - - if (rootName && !rootDirectory) { - StringRef pRootName = path::root_name(p); - StringRef bRootDirectory = path::root_directory(current_dir); - StringRef bRelativePath = path::relative_path(current_dir); - StringRef pRelativePath = path::relative_path(p); - - SmallString<128> res; - path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); - path.swap(res); - return error_code::success(); - } - - llvm_unreachable("All rootName and rootDirectory combinations should have " - "occurred above!"); -} - -error_code create_directories(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - StringRef parent = path::parent_path(p); - if (!parent.empty()) { - bool parent_exists; - if (error_code ec = fs::exists(parent, parent_exists)) return ec; - - if (!parent_exists) - if (error_code ec = create_directories(parent, existed)) return ec; - } - - return create_directory(p, existed); -} - -bool exists(file_status status) { - return status_known(status) && status.type() != file_type::file_not_found; -} - -bool status_known(file_status s) { - return s.type() != file_type::status_error; -} - -bool is_directory(file_status status) { - return status.type() == file_type::directory_file; -} - -error_code is_directory(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_directory(st); - return error_code::success(); -} - -bool is_regular_file(file_status status) { - return status.type() == file_type::regular_file; -} - -error_code is_regular_file(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_regular_file(st); - return error_code::success(); -} - -bool is_symlink(file_status status) { - return status.type() == file_type::symlink_file; -} - -error_code is_symlink(const Twine &path, bool &result) { - file_status st; - if (error_code ec = status(path, st)) - return ec; - result = is_symlink(st); - return error_code::success(); -} - -bool is_other(file_status status) { - return exists(status) && - !is_regular_file(status) && - !is_directory(status) && - !is_symlink(status); -} - -void directory_entry::replace_filename(const Twine &filename, file_status st) { - SmallString<128> path(Path.begin(), Path.end()); - path::remove_filename(path); - path::append(path, filename); - Path = path.str(); - Status = st; -} - -error_code has_magic(const Twine &path, const Twine &magic, bool &result) { - SmallString<32> MagicStorage; - StringRef Magic = magic.toStringRef(MagicStorage); - SmallString<32> Buffer; - - if (error_code ec = get_magic(path, Magic.size(), Buffer)) { - if (ec == errc::value_too_large) { - // Magic.size() > file_size(Path). - result = false; - return error_code::success(); - } - return ec; - } - - result = Magic == Buffer; - return error_code::success(); -} - -/// @brief Identify the magic in magic. - file_magic identify_magic(StringRef Magic) { - if (Magic.size() < 4) - return file_magic::unknown; - switch ((unsigned char)Magic[0]) { - case 0xDE: // 0x0B17C0DE = BC wraper - if (Magic[1] == (char)0xC0 && Magic[2] == (char)0x17 && - Magic[3] == (char)0x0B) - return file_magic::bitcode; - break; - case 'B': - if (Magic[1] == 'C' && Magic[2] == (char)0xC0 && Magic[3] == (char)0xDE) - return file_magic::bitcode; - break; - case '!': - if (Magic.size() >= 8) - if (memcmp(Magic.data(),"!\n",8) == 0) - return file_magic::archive; - break; - - case '\177': - if (Magic.size() >= 18 && Magic[1] == 'E' && Magic[2] == 'L' && - Magic[3] == 'F') { - bool Data2MSB = Magic[5] == 2; - unsigned high = Data2MSB ? 16 : 17; - unsigned low = Data2MSB ? 17 : 16; - if (Magic[high] == 0) - switch (Magic[low]) { - default: break; - case 1: return file_magic::elf_relocatable; - case 2: return file_magic::elf_executable; - case 3: return file_magic::elf_shared_object; - case 4: return file_magic::elf_core; - } - } - break; - - case 0xCA: - if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) && - Magic[3] == char(0xBE)) { - // This is complicated by an overlap with Java class files. - // See the Mach-O section in /usr/share/file/magic for details. - if (Magic.size() >= 8 && Magic[7] < 43) - return file_magic::macho_universal_binary; - } - break; - - // The two magic numbers for mach-o are: - // 0xfeedface - 32-bit mach-o - // 0xfeedfacf - 64-bit mach-o - case 0xFE: - case 0xCE: - case 0xCF: { - uint16_t type = 0; - if (Magic[0] == char(0xFE) && Magic[1] == char(0xED) && - Magic[2] == char(0xFA) && - (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) { - /* Native endian */ - if (Magic.size() >= 16) type = Magic[14] << 8 | Magic[15]; - } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) && - Magic[1] == char(0xFA) && Magic[2] == char(0xED) && - Magic[3] == char(0xFE)) { - /* Reverse endian */ - if (Magic.size() >= 14) type = Magic[13] << 8 | Magic[12]; - } - switch (type) { - default: break; - case 1: return file_magic::macho_object; - case 2: return file_magic::macho_executable; - case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; - case 4: return file_magic::macho_core; - case 5: return file_magic::macho_preload_executable; - case 6: return file_magic::macho_dynamically_linked_shared_lib; - case 7: return file_magic::macho_dynamic_linker; - case 8: return file_magic::macho_bundle; - case 9: return file_magic::macho_dynamic_linker; - case 10: return file_magic::macho_dsym_companion; - } - break; - } - case 0xF0: // PowerPC Windows - case 0x83: // Alpha 32-bit - case 0x84: // Alpha 64-bit - case 0x66: // MPS R4000 Windows - case 0x50: // mc68K - case 0x4c: // 80386 Windows - if (Magic[1] == 0x01) - return file_magic::coff_object; - - case 0x90: // PA-RISC Windows - case 0x68: // mc68K Windows - if (Magic[1] == 0x02) - return file_magic::coff_object; - break; - - case 0x4d: // Possible MS-DOS stub on Windows PE file - if (Magic[1] == 0x5a) { - uint32_t off = - *reinterpret_cast(Magic.data() + 0x3c); - // PE/COFF file, either EXE or DLL. - if (off < Magic.size() && memcmp(Magic.data() + off, "PE\0\0",4) == 0) - return file_magic::pecoff_executable; - } - break; - - case 0x64: // x86-64 Windows. - if (Magic[1] == char(0x86)) - return file_magic::coff_object; - break; - - default: - break; - } - return file_magic::unknown; -} - -error_code identify_magic(const Twine &path, file_magic &result) { - SmallString<32> Magic; - error_code ec = get_magic(path, Magic.capacity(), Magic); - if (ec && ec != errc::value_too_large) - return ec; - - result = identify_magic(Magic); - return error_code::success(); -} - -namespace { -error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { - if (ft == file_type::directory_file) { - // This code would be a lot better with exceptions ;/. - error_code ec; - directory_iterator i(path, ec); - if (ec) return ec; - for (directory_iterator e; i != e; i.increment(ec)) { - if (ec) return ec; - file_status st; - if (error_code ec = i->status(st)) return ec; - if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; - } - bool obviously_this_exists; - if (error_code ec = remove(path, obviously_this_exists)) return ec; - assert(obviously_this_exists); - ++count; // Include the directory itself in the items removed. - } else { - bool obviously_this_exists; - if (error_code ec = remove(path, obviously_this_exists)) return ec; - assert(obviously_this_exists); - ++count; - } - - return error_code::success(); -} -} // end unnamed namespace - -error_code remove_all(const Twine &path, uint32_t &num_removed) { - SmallString<128> path_storage; - StringRef p = path.toStringRef(path_storage); - - file_status fs; - if (error_code ec = status(path, fs)) - return ec; - num_removed = 0; - return remove_all_r(p, fs.type(), num_removed); -} - -error_code directory_entry::status(file_status &result) const { - return fs::status(Path, result); -} - -} // end namespace fs -} // end namespace sys -} // end namespace llvm - -// Include the truly platform-specific parts. -#if defined(LLVM_ON_UNIX) -#include "Unix/PathV2.inc" -#endif -#if defined(LLVM_ON_WIN32) -#include "Windows/PathV2.inc" -#endif diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc new file mode 100644 index 00000000000..94f872077a5 --- /dev/null +++ b/lib/Support/Unix/Path.inc @@ -0,0 +1,870 @@ +//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- 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 Unix specific implementation of the Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/Support/Process.h" +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif +#if HAVE_STDIO_H +#include +#endif +#if HAVE_LIMITS_H +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +// Both stdio.h and cstdio are included via different pathes and +// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros +// either. +#undef ferror +#undef feof + +// For GNU Hurd +#if defined(__GNU__) && !defined(PATH_MAX) +# define PATH_MAX 4096 +#endif + +using namespace llvm; + +namespace { + /// This class automatically closes the given file descriptor when it goes out + /// of scope. You can take back explicit ownership of the file descriptor by + /// calling take(). The destructor does not verify that close was successful. + /// Therefore, never allow this class to call close on a file descriptor that + /// has been read from or written to. + struct AutoFD { + int FileDescriptor; + + AutoFD(int fd) : FileDescriptor(fd) {} + ~AutoFD() { + if (FileDescriptor >= 0) + ::close(FileDescriptor); + } + + int take() { + int ret = FileDescriptor; + FileDescriptor = -1; + return ret; + } + + operator int() const {return FileDescriptor;} + }; + + error_code TempDir(SmallVectorImpl &result) { + // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. + const char *dir = 0; + (dir = std::getenv("TMPDIR" )) || + (dir = std::getenv("TMP" )) || + (dir = std::getenv("TEMP" )) || + (dir = std::getenv("TEMPDIR")) || +#ifdef P_tmpdir + (dir = P_tmpdir) || +#endif + (dir = "/tmp"); + + result.clear(); + StringRef d(dir); + result.append(d.begin(), d.end()); + return error_code::success(); + } +} + +namespace llvm { +namespace sys { +namespace fs { +#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ + defined(__linux__) || defined(__CYGWIN__) +static int +test_dir(char buf[PATH_MAX], char ret[PATH_MAX], + const char *dir, const char *bin) +{ + struct stat sb; + + snprintf(buf, PATH_MAX, "%s/%s", dir, bin); + if (realpath(buf, ret) == NULL) + return (1); + if (stat(buf, &sb) != 0) + return (1); + + return (0); +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ + char *pv, *s, *t, buf[PATH_MAX]; + + /* First approach: absolute path. */ + if (bin[0] == '/') { + if (test_dir(buf, ret, "/", bin) == 0) + return (ret); + return (NULL); + } + + /* Second approach: relative path. */ + if (strchr(bin, '/') != NULL) { + if (getcwd(buf, PATH_MAX) == NULL) + return (NULL); + if (test_dir(buf, ret, buf, bin) == 0) + return (ret); + return (NULL); + } + + /* Third approach: $PATH */ + if ((pv = getenv("PATH")) == NULL) + return (NULL); + s = pv = strdup(pv); + if (pv == NULL) + return (NULL); + while ((t = strsep(&s, ":")) != NULL) { + if (test_dir(buf, ret, t, bin) == 0) { + free(pv); + return (ret); + } + } + free(pv); + return (NULL); +} +#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +std::string getMainExecutable(const char *argv0, void *MainAddr) { +#if defined(__APPLE__) + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + char exe_path[MAXPATHLEN]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) == 0) { + char link_path[MAXPATHLEN]; + if (realpath(exe_path, link_path)) + return link_path; + } +#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) + char exe_path[PATH_MAX]; + + if (getprogpath(exe_path, argv0) != NULL) + return exe_path; +#elif defined(__linux__) || defined(__CYGWIN__) + char exe_path[MAXPATHLEN]; + StringRef aPath("/proc/self/exe"); + if (sys::fs::exists(aPath)) { + // /proc is not always mounted under Linux (chroot for example). + ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); + if (len >= 0) + return StringRef(exe_path, len); + } else { + // Fall back to the classical detection. + if (getprogpath(exe_path, argv0) != NULL) + return exe_path; + } +#elif defined(HAVE_DLFCN_H) + // Use dladdr to get executable path if available. + Dl_info DLInfo; + int err = dladdr(MainAddr, &DLInfo); + if (err == 0) + return ""; + + // If the filename is a symlink, we need to resolve and return the location of + // the actual executable. + char link_path[MAXPATHLEN]; + if (realpath(DLInfo.dli_fname, link_path)) + return link_path; +#else +#error GetMainExecutable is not implemented on this host yet. +#endif + return ""; +} + +TimeValue file_status::getLastModificationTime() const { + TimeValue Ret; + Ret.fromEpochTime(fs_st_mtime); + return Ret; +} + +error_code current_path(SmallVectorImpl &result) { +#ifdef MAXPATHLEN + result.reserve(MAXPATHLEN); +#else +// For GNU Hurd + result.reserve(1024); +#endif + + while (true) { + if (::getcwd(result.data(), result.capacity()) == 0) { + // See if there was a real error. + if (errno != errc::not_enough_memory) + return error_code(errno, system_category()); + // Otherwise there just wasn't enough space. + result.reserve(result.capacity() * 2); + } else + break; + } + + result.set_size(strlen(result.data())); + 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.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + const size_t buf_sz = 32768; + char buffer[buf_sz]; + int from_file = -1, to_file = -1; + + // Open from. + if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) + return error_code(errno, system_category()); + AutoFD from_fd(from_file); + + // Stat from. + struct stat from_stat; + if (::stat(f.begin(), &from_stat) != 0) + return error_code(errno, system_category()); + + // Setup to flags. + int to_flags = O_CREAT | O_WRONLY; + if (copt == copy_option::fail_if_exists) + to_flags |= O_EXCL; + + // Open to. + if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) + return error_code(errno, system_category()); + AutoFD to_fd(to_file); + + // Copy! + ssize_t sz, sz_read = 1, sz_write; + while (sz_read > 0 && + (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + sz_write = 0; + do { + if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { + sz_read = sz; // cause read loop termination. + break; // error. + } + sz_write += sz; + } while (sz_write < sz_read); + } + + // After all the file operations above the return value of close actually + // matters. + if (::close(from_fd.take()) < 0) sz_read = -1; + if (::close(to_fd.take()) < 0) sz_read = -1; + + // Check for errors. + if (sz_read < 0) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { + if (errno != errc::file_exists) + return error_code(errno, system_category()); + existed = true; + } 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.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::link(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code create_symlink(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::symlink(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat buf; + if (stat(p.begin(), &buf) != 0) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + existed = false; + return error_code::success(); + } + + // Note: this check catches strange situations. In all cases, LLVM should + // only be involved in the creation and deletion of regular files. This + // check ensures that what we're trying to erase is a regular file. It + // effectively prevents LLVM from erasing things like /dev/null, any block + // special file, or other things that aren't "regular" files. + if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) + return make_error_code(errc::operation_not_permitted); + + if (::remove(p.begin()) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + 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.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::rename(f.begin(), t.begin()) == -1) { + // If it's a cross device link, copy then delete, otherwise return the error + if (errno == EXDEV) { + if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) + return ec; + bool Existed; + if (error_code ec = remove(from, Existed)) + return ec; + } else + return error_code(errno, system_category()); + } + + return error_code::success(); +} + +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::truncate(p.begin(), size) == -1) + return error_code(errno, system_category()); + + return error_code::success(); +} + +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::access(p.begin(), F_OK) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + result = false; + } else + result = true; + + return error_code::success(); +} + +bool can_write(const Twine &Path) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + return 0 == access(P.begin(), W_OK); +} + +bool can_execute(const Twine &Path) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + if (0 != access(P.begin(), R_OK | X_OK)) + return false; + struct stat buf; + if (0 != stat(P.begin(), &buf)) + return false; + if (!S_ISREG(buf.st_mode)) + return false; + return true; +} + +bool equivalent(file_status A, file_status B) { + assert(status_known(A) && status_known(B)); + return A.fs_st_dev == B.fs_st_dev && + A.fs_st_ino == B.fs_st_ino; +} + +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; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) == -1) + return error_code(errno, system_category()); + if (!S_ISREG(status.st_mode)) + return make_error_code(errc::operation_not_permitted); + + result = status.st_size; + return error_code::success(); +} + +error_code getUniqueID(const Twine Path, uint64_t &Result) { + SmallString<128> Storage; + StringRef P = Path.toNullTerminatedStringRef(Storage); + + struct stat Status; + if (::stat(P.begin(), &Status) != 0) + return error_code(errno, system_category()); + + Result = Status.st_ino; + return error_code::success(); +} + +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) != 0) { + error_code ec(errno, system_category()); + if (ec == errc::no_such_file_or_directory) + result = file_status(file_type::file_not_found); + else + result = file_status(file_type::status_error); + return ec; + } + + perms prms = static_cast(status.st_mode & perms_mask); + + if (S_ISDIR(status.st_mode)) + result = file_status(file_type::directory_file, prms); + else if (S_ISREG(status.st_mode)) + result = file_status(file_type::regular_file, prms); + else if (S_ISBLK(status.st_mode)) + result = file_status(file_type::block_file, prms); + else if (S_ISCHR(status.st_mode)) + result = file_status(file_type::character_file, prms); + else if (S_ISFIFO(status.st_mode)) + result = file_status(file_type::fifo_file, prms); + else if (S_ISSOCK(status.st_mode)) + result = file_status(file_type::socket_file, prms); + else + result = file_status(file_type::type_unknown, prms); + + result.fs_st_dev = status.st_dev; + result.fs_st_ino = status.st_ino; + result.fs_st_mtime = status.st_mtime; + result.fs_st_uid = status.st_uid; + result.fs_st_gid = status.st_gid; + + return error_code::success(); +} + +// Modifies permissions on a file. +error_code permissions(const Twine &path, perms prms) { + if ((prms & add_perms) && (prms & remove_perms)) + llvm_unreachable("add_perms and remove_perms are mutually exclusive"); + + // Get current permissions + // FIXME: We only need this stat for add_perms and remove_perms. + file_status info; + if (error_code ec = status(path, info)) { + return ec; + } + + // Set updated permissions. + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + perms permsToSet; + if (prms & add_perms) { + permsToSet = (info.permissions() | prms) & perms_mask; + } else if (prms & remove_perms) { + permsToSet = (info.permissions() & ~prms) & perms_mask; + } else { + permsToSet = prms & perms_mask; + } + if (::chmod(p.begin(), static_cast(permsToSet))) { + return error_code(errno, system_category()); + } + + return error_code::success(); +} + +error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { + timeval Times[2]; + Times[0].tv_sec = Time.toPosixTime(); + Times[0].tv_usec = 0; + Times[1] = Times[0]; + if (::futimes(FD, Times)) + return error_code(errno, system_category()); + return error_code::success(); +} + +error_code unique_file(const Twine &model, int &result_fd, + SmallVectorImpl &result_path, + bool makeAbsolute, unsigned mode) { + SmallString<128> Model; + model.toVector(Model); + // Null terminate. + Model.c_str(); + + if (makeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = path::is_absolute(Twine(Model)); + if (!absolute) { + SmallString<128> TDir; + if (error_code ec = TempDir(TDir)) return ec; + path::append(TDir, Twine(Model)); + Model.swap(TDir); + } + } + + // From here on, DO NOT modify model. It may be needed if the randomly chosen + // path already exists. + SmallString<128> RandomPath = Model; + +retry_random_path: + // Replace '%' with random chars. + for (unsigned i = 0, e = Model.size(); i != e; ++i) { + if (Model[i] == '%') + RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; + } + + // Make sure we don't fall into an infinite loop by constantly trying + // to create the parent path. + bool TriedToCreateParent = false; + + // Try to open + create the file. +rety_open_create: + int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode); + if (RandomFD == -1) { + int SavedErrno = errno; + // If the file existed, try again, otherwise, error. + if (SavedErrno == errc::file_exists) + goto retry_random_path; + // If path prefix doesn't exist, try to create it. + if (SavedErrno == errc::no_such_file_or_directory && !TriedToCreateParent) { + TriedToCreateParent = true; + StringRef p(RandomPath); + 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) { + // Don't try to create network paths. + if (i->size() > 2 && (*i)[0] == '/' && + (*i)[1] == '/' && + (*i)[2] != '/') + return make_error_code(errc::no_such_file_or_directory); + if (::mkdir(dir_to_create.c_str(), 0700) == -1 && + errno != errc::file_exists) + return error_code(errno, system_category()); + } + } + goto rety_open_create; + } + + return error_code(SavedErrno, system_category()); + } + + // Make the path absolute. + char real_path_buff[PATH_MAX + 1]; + if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { + int error = errno; + ::close(RandomFD); + ::unlink(RandomPath.c_str()); + return error_code(error, system_category()); + } + + result_path.clear(); + StringRef d(real_path_buff); + result_path.append(d.begin(), d.end()); + + result_fd = RandomFD; + return error_code::success(); +} + +error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { + AutoFD ScopedFD(FD); + if (!CloseFD) + ScopedFD.take(); + + // Figure out how large the file is. + struct stat FileInfo; + if (fstat(FD, &FileInfo) == -1) + return error_code(errno, system_category()); + uint64_t FileSize = FileInfo.st_size; + + if (Size == 0) + Size = FileSize; + else if (FileSize < Size) { + // We need to grow the file. + if (ftruncate(FD, Size) == -1) + return error_code(errno, system_category()); + } + + int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; + int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#ifdef MAP_FILE + flags |= MAP_FILE; +#endif + Mapping = ::mmap(0, Size, prot, flags, FD, Offset); + if (Mapping == MAP_FAILED) + return error_code(errno, system_category()); + 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() { + // Make sure that the requested size fits within SIZE_T. + if (length > std::numeric_limits::max()) { + ec = make_error_code(errc::invalid_argument); + return; + } + + SmallString<128> path_storage; + StringRef name = path.toNullTerminatedStringRef(path_storage); + int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; + int ofd = ::open(name.begin(), oflags); + if (ofd == -1) { + ec = error_code(errno, system_category()); + return; + } + + ec = init(ofd, true, offset); + if (ec) + Mapping = 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() { + // Make sure that the requested size fits within SIZE_T. + if (length > std::numeric_limits::max()) { + ec = make_error_code(errc::invalid_argument); + return; + } + + ec = init(fd, closefd, offset); + if (ec) + Mapping = 0; +} + +mapped_file_region::~mapped_file_region() { + if (Mapping) + ::munmap(Mapping, Size); +} + +#if LLVM_HAS_RVALUE_REFERENCES +mapped_file_region::mapped_file_region(mapped_file_region &&other) + : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { + other.Mapping = 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(Mapping && "Mapping failed but used anyway!"); + assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); + return reinterpret_cast(Mapping); +} + +const char *mapped_file_region::const_data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast(Mapping); +} + +int mapped_file_region::alignment() { + return process::get_self()->page_size(); +} + +error_code detail::directory_iterator_construct(detail::DirIterState &it, + StringRef path){ + SmallString<128> path_null(path); + DIR *directory = ::opendir(path_null.c_str()); + if (directory == 0) + return error_code(errno, system_category()); + + it.IterationHandle = reinterpret_cast(directory); + // Add something for replace_filename to replace. + path::append(path_null, "."); + it.CurrentEntry = directory_entry(path_null.str()); + return directory_iterator_increment(it); +} + +error_code detail::directory_iterator_destruct(detail::DirIterState &it) { + if (it.IterationHandle) + ::closedir(reinterpret_cast(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return error_code::success(); +} + +error_code detail::directory_iterator_increment(detail::DirIterState &it) { + errno = 0; + dirent *cur_dir = ::readdir(reinterpret_cast(it.IterationHandle)); + if (cur_dir == 0 && errno != 0) { + return error_code(errno, system_category()); + } else if (cur_dir != 0) { + StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + if ((name.size() == 1 && name[0] == '.') || + (name.size() == 2 && name[0] == '.' && name[1] == '.')) + return directory_iterator_increment(it); + it.CurrentEntry.replace_filename(name); + } else + return directory_iterator_destruct(it); + + return error_code::success(); +} + +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl &result) { + SmallString<128> PathStorage; + StringRef Path = path.toNullTerminatedStringRef(PathStorage); + result.set_size(0); + + // Open path. + std::FILE *file = std::fopen(Path.data(), "rb"); + if (file == 0) + return error_code(errno, system_category()); + + // Reserve storage. + result.reserve(len); + + // Read magic! + size_t size = std::fread(result.data(), 1, len, file); + if (std::ferror(file) != 0) { + std::fclose(file); + return error_code(errno, system_category()); + } else if (size != len) { + if (std::feof(file) != 0) { + std::fclose(file); + result.set_size(size); + return make_error_code(errc::value_too_large); + } + } + std::fclose(file); + result.set_size(size); + return error_code::success(); +} + +error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, + bool map_writable, void *&result) { + SmallString<128> path_storage; + StringRef name = path.toNullTerminatedStringRef(path_storage); + int oflags = map_writable ? O_RDWR : O_RDONLY; + int ofd = ::open(name.begin(), oflags); + if ( ofd == -1 ) + return error_code(errno, system_category()); + AutoFD fd(ofd); + int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; + int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; +#ifdef MAP_FILE + flags |= MAP_FILE; +#endif + result = ::mmap(0, size, prot, flags, fd, file_offset); + if (result == MAP_FAILED) { + return error_code(errno, system_category()); + } + + return error_code::success(); +} + +error_code unmap_file_pages(void *base, size_t size) { + if ( ::munmap(base, size) == -1 ) + return error_code(errno, system_category()); + + return error_code::success(); +} + + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc deleted file mode 100644 index 91efcd80233..00000000000 --- a/lib/Support/Unix/PathV2.inc +++ /dev/null @@ -1,870 +0,0 @@ -//===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- 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 Unix specific implementation of the PathV2 API. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#include "llvm/Support/Process.h" -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#if HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif -#if HAVE_STDIO_H -#include -#endif -#if HAVE_LIMITS_H -#include -#endif - -#ifdef __APPLE__ -#include -#endif - -// Both stdio.h and cstdio are included via different pathes and -// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros -// either. -#undef ferror -#undef feof - -// For GNU Hurd -#if defined(__GNU__) && !defined(PATH_MAX) -# define PATH_MAX 4096 -#endif - -using namespace llvm; - -namespace { - /// This class automatically closes the given file descriptor when it goes out - /// of scope. You can take back explicit ownership of the file descriptor by - /// calling take(). The destructor does not verify that close was successful. - /// Therefore, never allow this class to call close on a file descriptor that - /// has been read from or written to. - struct AutoFD { - int FileDescriptor; - - AutoFD(int fd) : FileDescriptor(fd) {} - ~AutoFD() { - if (FileDescriptor >= 0) - ::close(FileDescriptor); - } - - int take() { - int ret = FileDescriptor; - FileDescriptor = -1; - return ret; - } - - operator int() const {return FileDescriptor;} - }; - - error_code TempDir(SmallVectorImpl &result) { - // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. - const char *dir = 0; - (dir = std::getenv("TMPDIR" )) || - (dir = std::getenv("TMP" )) || - (dir = std::getenv("TEMP" )) || - (dir = std::getenv("TEMPDIR")) || -#ifdef P_tmpdir - (dir = P_tmpdir) || -#endif - (dir = "/tmp"); - - result.clear(); - StringRef d(dir); - result.append(d.begin(), d.end()); - return error_code::success(); - } -} - -namespace llvm { -namespace sys { -namespace fs { -#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ - defined(__linux__) || defined(__CYGWIN__) -static int -test_dir(char buf[PATH_MAX], char ret[PATH_MAX], - const char *dir, const char *bin) -{ - struct stat sb; - - snprintf(buf, PATH_MAX, "%s/%s", dir, bin); - if (realpath(buf, ret) == NULL) - return (1); - if (stat(buf, &sb) != 0) - return (1); - - return (0); -} - -static char * -getprogpath(char ret[PATH_MAX], const char *bin) -{ - char *pv, *s, *t, buf[PATH_MAX]; - - /* First approach: absolute path. */ - if (bin[0] == '/') { - if (test_dir(buf, ret, "/", bin) == 0) - return (ret); - return (NULL); - } - - /* Second approach: relative path. */ - if (strchr(bin, '/') != NULL) { - if (getcwd(buf, PATH_MAX) == NULL) - return (NULL); - if (test_dir(buf, ret, buf, bin) == 0) - return (ret); - return (NULL); - } - - /* Third approach: $PATH */ - if ((pv = getenv("PATH")) == NULL) - return (NULL); - s = pv = strdup(pv); - if (pv == NULL) - return (NULL); - while ((t = strsep(&s, ":")) != NULL) { - if (test_dir(buf, ret, t, bin) == 0) { - free(pv); - return (ret); - } - } - free(pv); - return (NULL); -} -#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ - -/// GetMainExecutable - Return the path to the main executable, given the -/// value of argv[0] from program startup. -std::string getMainExecutable(const char *argv0, void *MainAddr) { -#if defined(__APPLE__) - // On OS X the executable path is saved to the stack by dyld. Reading it - // from there is much faster than calling dladdr, especially for large - // binaries with symbols. - char exe_path[MAXPATHLEN]; - uint32_t size = sizeof(exe_path); - if (_NSGetExecutablePath(exe_path, &size) == 0) { - char link_path[MAXPATHLEN]; - if (realpath(exe_path, link_path)) - return link_path; - } -#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) - char exe_path[PATH_MAX]; - - if (getprogpath(exe_path, argv0) != NULL) - return exe_path; -#elif defined(__linux__) || defined(__CYGWIN__) - char exe_path[MAXPATHLEN]; - StringRef aPath("/proc/self/exe"); - if (sys::fs::exists(aPath)) { - // /proc is not always mounted under Linux (chroot for example). - ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); - if (len >= 0) - return StringRef(exe_path, len); - } else { - // Fall back to the classical detection. - if (getprogpath(exe_path, argv0) != NULL) - return exe_path; - } -#elif defined(HAVE_DLFCN_H) - // Use dladdr to get executable path if available. - Dl_info DLInfo; - int err = dladdr(MainAddr, &DLInfo); - if (err == 0) - return ""; - - // If the filename is a symlink, we need to resolve and return the location of - // the actual executable. - char link_path[MAXPATHLEN]; - if (realpath(DLInfo.dli_fname, link_path)) - return link_path; -#else -#error GetMainExecutable is not implemented on this host yet. -#endif - return ""; -} - -TimeValue file_status::getLastModificationTime() const { - TimeValue Ret; - Ret.fromEpochTime(fs_st_mtime); - return Ret; -} - -error_code current_path(SmallVectorImpl &result) { -#ifdef MAXPATHLEN - result.reserve(MAXPATHLEN); -#else -// For GNU Hurd - result.reserve(1024); -#endif - - while (true) { - if (::getcwd(result.data(), result.capacity()) == 0) { - // See if there was a real error. - if (errno != errc::not_enough_memory) - return error_code(errno, system_category()); - // Otherwise there just wasn't enough space. - result.reserve(result.capacity() * 2); - } else - break; - } - - result.set_size(strlen(result.data())); - 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.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - const size_t buf_sz = 32768; - char buffer[buf_sz]; - int from_file = -1, to_file = -1; - - // Open from. - if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) - return error_code(errno, system_category()); - AutoFD from_fd(from_file); - - // Stat from. - struct stat from_stat; - if (::stat(f.begin(), &from_stat) != 0) - return error_code(errno, system_category()); - - // Setup to flags. - int to_flags = O_CREAT | O_WRONLY; - if (copt == copy_option::fail_if_exists) - to_flags |= O_EXCL; - - // Open to. - if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) - return error_code(errno, system_category()); - AutoFD to_fd(to_file); - - // Copy! - ssize_t sz, sz_read = 1, sz_write; - while (sz_read > 0 && - (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { - // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), - // Marc Rochkind, Addison-Wesley, 2004, page 94 - sz_write = 0; - do { - if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { - sz_read = sz; // cause read loop termination. - break; // error. - } - sz_write += sz; - } while (sz_write < sz_read); - } - - // After all the file operations above the return value of close actually - // matters. - if (::close(from_fd.take()) < 0) sz_read = -1; - if (::close(to_fd.take()) < 0) sz_read = -1; - - // Check for errors. - if (sz_read < 0) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code create_directory(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { - if (errno != errc::file_exists) - return error_code(errno, system_category()); - existed = true; - } 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.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::link(t.begin(), f.begin()) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code create_symlink(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::symlink(t.begin(), f.begin()) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code remove(const Twine &path, bool &existed) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - struct stat buf; - if (stat(p.begin(), &buf) != 0) { - if (errno != errc::no_such_file_or_directory) - return error_code(errno, system_category()); - existed = false; - return error_code::success(); - } - - // Note: this check catches strange situations. In all cases, LLVM should - // only be involved in the creation and deletion of regular files. This - // check ensures that what we're trying to erase is a regular file. It - // effectively prevents LLVM from erasing things like /dev/null, any block - // special file, or other things that aren't "regular" files. - if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) - return make_error_code(errc::operation_not_permitted); - - if (::remove(p.begin()) == -1) { - if (errno != errc::no_such_file_or_directory) - return error_code(errno, system_category()); - 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.toNullTerminatedStringRef(from_storage); - StringRef t = to.toNullTerminatedStringRef(to_storage); - - if (::rename(f.begin(), t.begin()) == -1) { - // If it's a cross device link, copy then delete, otherwise return the error - if (errno == EXDEV) { - if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) - return ec; - bool Existed; - if (error_code ec = remove(from, Existed)) - return ec; - } else - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::truncate(p.begin(), size) == -1) - return error_code(errno, system_category()); - - return error_code::success(); -} - -error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - if (::access(p.begin(), F_OK) == -1) { - if (errno != errc::no_such_file_or_directory) - return error_code(errno, system_category()); - result = false; - } else - result = true; - - return error_code::success(); -} - -bool can_write(const Twine &Path) { - SmallString<128> PathStorage; - StringRef P = Path.toNullTerminatedStringRef(PathStorage); - return 0 == access(P.begin(), W_OK); -} - -bool can_execute(const Twine &Path) { - SmallString<128> PathStorage; - StringRef P = Path.toNullTerminatedStringRef(PathStorage); - - if (0 != access(P.begin(), R_OK | X_OK)) - return false; - struct stat buf; - if (0 != stat(P.begin(), &buf)) - return false; - if (!S_ISREG(buf.st_mode)) - return false; - return true; -} - -bool equivalent(file_status A, file_status B) { - assert(status_known(A) && status_known(B)); - return A.fs_st_dev == B.fs_st_dev && - A.fs_st_ino == B.fs_st_ino; -} - -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; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - struct stat status; - if (::stat(p.begin(), &status) == -1) - return error_code(errno, system_category()); - if (!S_ISREG(status.st_mode)) - return make_error_code(errc::operation_not_permitted); - - result = status.st_size; - return error_code::success(); -} - -error_code getUniqueID(const Twine Path, uint64_t &Result) { - SmallString<128> Storage; - StringRef P = Path.toNullTerminatedStringRef(Storage); - - struct stat Status; - if (::stat(P.begin(), &Status) != 0) - return error_code(errno, system_category()); - - Result = Status.st_ino; - return error_code::success(); -} - -error_code status(const Twine &path, file_status &result) { - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - - struct stat status; - if (::stat(p.begin(), &status) != 0) { - error_code ec(errno, system_category()); - if (ec == errc::no_such_file_or_directory) - result = file_status(file_type::file_not_found); - else - result = file_status(file_type::status_error); - return ec; - } - - perms prms = static_cast(status.st_mode & perms_mask); - - if (S_ISDIR(status.st_mode)) - result = file_status(file_type::directory_file, prms); - else if (S_ISREG(status.st_mode)) - result = file_status(file_type::regular_file, prms); - else if (S_ISBLK(status.st_mode)) - result = file_status(file_type::block_file, prms); - else if (S_ISCHR(status.st_mode)) - result = file_status(file_type::character_file, prms); - else if (S_ISFIFO(status.st_mode)) - result = file_status(file_type::fifo_file, prms); - else if (S_ISSOCK(status.st_mode)) - result = file_status(file_type::socket_file, prms); - else - result = file_status(file_type::type_unknown, prms); - - result.fs_st_dev = status.st_dev; - result.fs_st_ino = status.st_ino; - result.fs_st_mtime = status.st_mtime; - result.fs_st_uid = status.st_uid; - result.fs_st_gid = status.st_gid; - - return error_code::success(); -} - -// Modifies permissions on a file. -error_code permissions(const Twine &path, perms prms) { - if ((prms & add_perms) && (prms & remove_perms)) - llvm_unreachable("add_perms and remove_perms are mutually exclusive"); - - // Get current permissions - // FIXME: We only need this stat for add_perms and remove_perms. - file_status info; - if (error_code ec = status(path, info)) { - return ec; - } - - // Set updated permissions. - SmallString<128> path_storage; - StringRef p = path.toNullTerminatedStringRef(path_storage); - perms permsToSet; - if (prms & add_perms) { - permsToSet = (info.permissions() | prms) & perms_mask; - } else if (prms & remove_perms) { - permsToSet = (info.permissions() & ~prms) & perms_mask; - } else { - permsToSet = prms & perms_mask; - } - if (::chmod(p.begin(), static_cast(permsToSet))) { - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { - timeval Times[2]; - Times[0].tv_sec = Time.toPosixTime(); - Times[0].tv_usec = 0; - Times[1] = Times[0]; - if (::futimes(FD, Times)) - return error_code(errno, system_category()); - return error_code::success(); -} - -error_code unique_file(const Twine &model, int &result_fd, - SmallVectorImpl &result_path, - bool makeAbsolute, unsigned mode) { - SmallString<128> Model; - model.toVector(Model); - // Null terminate. - Model.c_str(); - - if (makeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = path::is_absolute(Twine(Model)); - if (!absolute) { - SmallString<128> TDir; - if (error_code ec = TempDir(TDir)) return ec; - path::append(TDir, Twine(Model)); - Model.swap(TDir); - } - } - - // From here on, DO NOT modify model. It may be needed if the randomly chosen - // path already exists. - SmallString<128> RandomPath = Model; - -retry_random_path: - // Replace '%' with random chars. - for (unsigned i = 0, e = Model.size(); i != e; ++i) { - if (Model[i] == '%') - RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; - } - - // Make sure we don't fall into an infinite loop by constantly trying - // to create the parent path. - bool TriedToCreateParent = false; - - // Try to open + create the file. -rety_open_create: - int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode); - if (RandomFD == -1) { - int SavedErrno = errno; - // If the file existed, try again, otherwise, error. - if (SavedErrno == errc::file_exists) - goto retry_random_path; - // If path prefix doesn't exist, try to create it. - if (SavedErrno == errc::no_such_file_or_directory && !TriedToCreateParent) { - TriedToCreateParent = true; - StringRef p(RandomPath); - 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) { - // Don't try to create network paths. - if (i->size() > 2 && (*i)[0] == '/' && - (*i)[1] == '/' && - (*i)[2] != '/') - return make_error_code(errc::no_such_file_or_directory); - if (::mkdir(dir_to_create.c_str(), 0700) == -1 && - errno != errc::file_exists) - return error_code(errno, system_category()); - } - } - goto rety_open_create; - } - - return error_code(SavedErrno, system_category()); - } - - // Make the path absolute. - char real_path_buff[PATH_MAX + 1]; - if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { - int error = errno; - ::close(RandomFD); - ::unlink(RandomPath.c_str()); - return error_code(error, system_category()); - } - - result_path.clear(); - StringRef d(real_path_buff); - result_path.append(d.begin(), d.end()); - - result_fd = RandomFD; - return error_code::success(); -} - -error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { - AutoFD ScopedFD(FD); - if (!CloseFD) - ScopedFD.take(); - - // Figure out how large the file is. - struct stat FileInfo; - if (fstat(FD, &FileInfo) == -1) - return error_code(errno, system_category()); - uint64_t FileSize = FileInfo.st_size; - - if (Size == 0) - Size = FileSize; - else if (FileSize < Size) { - // We need to grow the file. - if (ftruncate(FD, Size) == -1) - return error_code(errno, system_category()); - } - - int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; - int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); -#ifdef MAP_FILE - flags |= MAP_FILE; -#endif - Mapping = ::mmap(0, Size, prot, flags, FD, Offset); - if (Mapping == MAP_FAILED) - return error_code(errno, system_category()); - 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() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - - SmallString<128> path_storage; - StringRef name = path.toNullTerminatedStringRef(path_storage); - int oflags = (mode == readonly) ? O_RDONLY : O_RDWR; - int ofd = ::open(name.begin(), oflags); - if (ofd == -1) { - ec = error_code(errno, system_category()); - return; - } - - ec = init(ofd, true, offset); - if (ec) - Mapping = 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() { - // Make sure that the requested size fits within SIZE_T. - if (length > std::numeric_limits::max()) { - ec = make_error_code(errc::invalid_argument); - return; - } - - ec = init(fd, closefd, offset); - if (ec) - Mapping = 0; -} - -mapped_file_region::~mapped_file_region() { - if (Mapping) - ::munmap(Mapping, Size); -} - -#if LLVM_HAS_RVALUE_REFERENCES -mapped_file_region::mapped_file_region(mapped_file_region &&other) - : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { - other.Mapping = 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(Mapping && "Mapping failed but used anyway!"); - assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); - return reinterpret_cast(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast(Mapping); -} - -int mapped_file_region::alignment() { - return process::get_self()->page_size(); -} - -error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ - SmallString<128> path_null(path); - DIR *directory = ::opendir(path_null.c_str()); - if (directory == 0) - return error_code(errno, system_category()); - - it.IterationHandle = reinterpret_cast(directory); - // Add something for replace_filename to replace. - path::append(path_null, "."); - it.CurrentEntry = directory_entry(path_null.str()); - return directory_iterator_increment(it); -} - -error_code detail::directory_iterator_destruct(detail::DirIterState &it) { - if (it.IterationHandle) - ::closedir(reinterpret_cast(it.IterationHandle)); - it.IterationHandle = 0; - it.CurrentEntry = directory_entry(); - return error_code::success(); -} - -error_code detail::directory_iterator_increment(detail::DirIterState &it) { - errno = 0; - dirent *cur_dir = ::readdir(reinterpret_cast(it.IterationHandle)); - if (cur_dir == 0 && errno != 0) { - return error_code(errno, system_category()); - } else if (cur_dir != 0) { - StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); - if ((name.size() == 1 && name[0] == '.') || - (name.size() == 2 && name[0] == '.' && name[1] == '.')) - return directory_iterator_increment(it); - it.CurrentEntry.replace_filename(name); - } else - return directory_iterator_destruct(it); - - return error_code::success(); -} - -error_code get_magic(const Twine &path, uint32_t len, - SmallVectorImpl &result) { - SmallString<128> PathStorage; - StringRef Path = path.toNullTerminatedStringRef(PathStorage); - result.set_size(0); - - // Open path. - std::FILE *file = std::fopen(Path.data(), "rb"); - if (file == 0) - return error_code(errno, system_category()); - - // Reserve storage. - result.reserve(len); - - // Read magic! - size_t size = std::fread(result.data(), 1, len, file); - if (std::ferror(file) != 0) { - std::fclose(file); - return error_code(errno, system_category()); - } else if (size != len) { - if (std::feof(file) != 0) { - std::fclose(file); - result.set_size(size); - return make_error_code(errc::value_too_large); - } - } - std::fclose(file); - result.set_size(size); - return error_code::success(); -} - -error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, - bool map_writable, void *&result) { - SmallString<128> path_storage; - StringRef name = path.toNullTerminatedStringRef(path_storage); - int oflags = map_writable ? O_RDWR : O_RDONLY; - int ofd = ::open(name.begin(), oflags); - if ( ofd == -1 ) - return error_code(errno, system_category()); - AutoFD fd(ofd); - int flags = map_writable ? MAP_SHARED : MAP_PRIVATE; - int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ; -#ifdef MAP_FILE - flags |= MAP_FILE; -#endif - result = ::mmap(0, size, prot, flags, fd, file_offset); - if (result == MAP_FAILED) { - return error_code(errno, system_category()); - } - - return error_code::success(); -} - -error_code unmap_file_pages(void *base, size_t size) { - if ( ::munmap(base, size) == -1 ) - return error_code(errno, system_category()); - - return error_code::success(); -} - - -} // end namespace fs -} // end namespace sys -} // end namespace llvm diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc new file mode 100644 index 00000000000..2b24c5487f0 --- /dev/null +++ b/lib/Support/Windows/Path.inc @@ -0,0 +1,1092 @@ +//===- llvm/Support/Windows/Path.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 Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include +#include +#include + +#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 &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 &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 &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 { + +std::string getMainExecutable(const char *argv0, void *MainExecAddr) { + char pathname[MAX_PATH]; + DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); + return ret != MAX_PATH ? pathname : ""; +} + + +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 &result) { + SmallVector 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 wide_from; + SmallVector 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 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 wide_from; + SmallVector 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 wide_from; + SmallVector 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 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 wide_from; + SmallVector 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 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 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 can_write(const Twine &Path) { + // FIXME: take security attributes into account. + SmallString<128> PathStorage; + SmallVector PathUtf16; + + if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) + return false; + + DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); + return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); +} + +bool can_execute(const Twine &Path) { + SmallString<128> PathStorage; + SmallVector PathUtf16; + + if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) + return false; + + DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); + return Attr != INVALID_FILE_ATTRIBUTES; +} + +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 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(); +} + +error_code getUniqueID(const Twine Path, uint64_t &Result) { + file_status Status; + if (error_code E = status(Path, Status)) + return E; + + // The file is uniquely identified by the volume serial number along + // with the 64-bit file identifier. + Result = (static_cast(Status.FileIndexHigh) << 32ULL) | + static_cast(Status.FileIndexLow); + + // Because the serial number is 32-bits, but we've already used up all 64 + // bits for the file index, XOR the serial number into the high 32 bits of + // the resulting value. We could potentially get collisons from this, but + // the likelihood is low. + Result ^= (static_cast(Status.VolumeSerialNumber) << 32ULL); + + 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 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 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(); +} + +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(_get_osfhandle(FD)); + if (!SetFileTime(FileHandle, NULL, &FT, &FT)) + return windows_error(::GetLastError()); + 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 &result_path, + bool makeAbsolute, unsigned mode) { + // Use result_path as temp storage. + result_path.set_size(0); + StringRef m = model.toStringRef(result_path); + + SmallVector 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 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 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::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 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 &result) { + SmallString<128> path_storage; + SmallVector 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::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 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(_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(Mapping); +} + +const char *mapped_file_region::const_data() const { + assert(Mapping && "Mapping failed but used anyway!"); + return reinterpret_cast(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 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/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc deleted file mode 100644 index 6987e5fc9da..00000000000 --- a/lib/Support/Windows/PathV2.inc +++ /dev/null @@ -1,1092 +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 -#include -#include -#include - -#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 &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 &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 &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 { - -std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - char pathname[MAX_PATH]; - DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); - return ret != MAX_PATH ? pathname : ""; -} - - -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 &result) { - SmallVector 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 wide_from; - SmallVector 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 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 wide_from; - SmallVector 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 wide_from; - SmallVector 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 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 wide_from; - SmallVector 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 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 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 can_write(const Twine &Path) { - // FIXME: take security attributes into account. - SmallString<128> PathStorage; - SmallVector PathUtf16; - - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; - - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); -} - -bool can_execute(const Twine &Path) { - SmallString<128> PathStorage; - SmallVector PathUtf16; - - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; - - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return Attr != INVALID_FILE_ATTRIBUTES; -} - -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 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(); -} - -error_code getUniqueID(const Twine Path, uint64_t &Result) { - file_status Status; - if (error_code E = status(Path, Status)) - return E; - - // The file is uniquely identified by the volume serial number along - // with the 64-bit file identifier. - Result = (static_cast(Status.FileIndexHigh) << 32ULL) | - static_cast(Status.FileIndexLow); - - // Because the serial number is 32-bits, but we've already used up all 64 - // bits for the file index, XOR the serial number into the high 32 bits of - // the resulting value. We could potentially get collisons from this, but - // the likelihood is low. - Result ^= (static_cast(Status.VolumeSerialNumber) << 32ULL); - - 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 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 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(); -} - -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(_get_osfhandle(FD)); - if (!SetFileTime(FileHandle, NULL, &FT, &FT)) - return windows_error(::GetLastError()); - 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 &result_path, - bool makeAbsolute, unsigned mode) { - // Use result_path as temp storage. - result_path.set_size(0); - StringRef m = model.toStringRef(result_path); - - SmallVector 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 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 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::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 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 &result) { - SmallString<128> path_storage; - SmallVector 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::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 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(_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(Mapping); -} - -const char *mapped_file_region::const_data() const { - assert(Mapping && "Mapping failed but used anyway!"); - return reinterpret_cast(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 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