build-llvm.sh: Bump to llvmorg-13.0.0-rc1
Notable changes since 12.0.0 for llvm-mingw are: llvm: - Produce proper cross-section relative relocations on ARM and AArch64 - Fixed the calling convention for AArch64 for variadic functions involving floats in the fixed arguments - Added a windres compatible frontend in llvm-rc, avoiding the need for external wrappers - Build LLVM with -ffunction-sections and --gc-sections, shrinking a full build of llvm-mingw without LLVM_BUILD_LLVM_DYLIB by 22% (but llvm-mingw uses LLVM_BUILD_LLVM_DYLIB these days, which shrinks the build even more) - Avoid optimizing/changing function calls into stpcpy due to optimizations - llvm-ml has improved to the point where it can build the OpenMP assembly file without needing to use another assembler tool lld: - Support linking directly against DLLs without using import libraries - Improved reliability when running on Windows, avoiding some hangs when terminating - Fixed linking with --export-all-symbols in combination with -ffunction-sections - Fixed --export-all-symbols when linking EXEs - Fixed autoexport from LTO objects with comdat symbols - Print warnings with a "ld.lld" prefix instead of "lld-link" - Avoid thread exhaustion on 32 bit Windows - Accepting more forms of options, like -static and --stack= clang: - Fixed reading long doubles with va_arg on x86_64 - Fixed calling std::once in a dynamically linked libstdc++ runtimes: - Complete support for std::filesystem in libc++ (which was previously backported to 12.0.0 in llvm-mingw too, but the previous release had a bug in using e.g. the u8path() method when linking against the DLL version of libc++) - Implemented semaphores in libc++ - Provide the __gcc_personality_seh0 symbol, fixing building C code with -fexceptions and __attribute__((cleanup)) - Simplified building/installing compiler-rt and libunwind - Silenced lots of build warnings in OpenMP
This commit is contained in:
1 parent
1f5a7e0577
commit
9188cce153
28 files changed
+1
-2966
No files matched your search
@@ -57,7 +57,6 @@ COPY wrappers/uasm-wrapper.sh $TOOLCHAIN_PREFIX/bin
|
||||
# Build everything that uses the llvm monorepo. We need to build the mingw runtime before the compiler-rt/libunwind/libcxxabi/libcxx runtimes.
|
||||
COPY build-llvm.sh strip-llvm.sh install-wrappers.sh build-mingw-w64.sh build-mingw-w64-tools.sh build-compiler-rt.sh build-mingw-w64-libraries.sh build-libcxx.sh build-openmp.sh ./
|
||||
COPY wrappers/*.sh wrappers/*.c wrappers/*.h ./wrappers/
|
||||
COPY patches/llvm-project/*.patch ./patches/llvm-project/
|
||||
RUN ./build-llvm.sh $TOOLCHAIN_PREFIX && \
|
||||
./strip-llvm.sh $TOOLCHAIN_PREFIX && \
|
||||
./install-wrappers.sh $TOOLCHAIN_PREFIX && \
|
||||
|
||||
@@ -44,7 +44,6 @@ ARG FULL_LLVM
|
||||
|
||||
# Build LLVM
|
||||
COPY build-llvm.sh ./
|
||||
COPY patches/llvm-project/*.patch ./patches/llvm-project/
|
||||
RUN ./build-llvm.sh $TOOLCHAIN_PREFIX
|
||||
|
||||
# Strip the LLVM install output immediately. (This doesn't reduce the
|
||||
|
||||
+1
-6
@@ -16,7 +16,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
: ${LLVM_VERSION:=llvmorg-12.0.0}
|
||||
: ${LLVM_VERSION:=llvmorg-13.0.0-rc1}
|
||||
ASSERTS=OFF
|
||||
unset HOST
|
||||
BUILDDIR="build"
|
||||
@@ -89,11 +89,6 @@ if [ -n "$SYNC" ] || [ -n "$CHECKOUT" ]; then
|
||||
git fetch --depth 1 origin "$LLVM_VERSION"
|
||||
git checkout FETCH_HEAD
|
||||
fi
|
||||
if [ "$LLVM_VERSION" = "llvmorg-12.0.0" ]; then
|
||||
# The bundled patches for std::filesystem apply on the 12.0.0 release,
|
||||
# but don't try to apply them if a different version was requested.
|
||||
git am -3 --keep-non-patch ../patches/llvm-project/*.patch
|
||||
fi
|
||||
cd ..
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
From 4655075efa11ee17c28493d13760d51e360f7ddd Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 16:59:07 +0200
|
||||
Subject: [PATCH 01/25] [libcxx] Implement the stat function family on top of
|
||||
native windows APIs
|
||||
|
||||
While the windows CRTs (the modern UCRT, and the legacy msvcrt.dll
|
||||
that mingw still often defaults to) do provide stat functions, they're
|
||||
a bit lacking - they only provide second precision on the modification
|
||||
time, lack support for symlinks and a few other details.
|
||||
|
||||
Instead reimplement them using a couple windows native functions,
|
||||
getting exactly the info we need. (Technically, the implementation
|
||||
within the CRT calls these functions anyway.)
|
||||
|
||||
If we only need a few fields, we could also do with fewer calls, as a
|
||||
later optimization.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91141
|
||||
|
||||
(cherry picked from commit 2ff8662b5d16129ec6d1ee60dcec4f6ff8f717e2)
|
||||
---
|
||||
libcxx/src/CMakeLists.txt | 1 +
|
||||
libcxx/src/filesystem/filesystem_common.h | 32 ++++
|
||||
libcxx/src/filesystem/operations.cpp | 10 +-
|
||||
libcxx/src/filesystem/posix_compat.h | 187 ++++++++++++++++++++++
|
||||
4 files changed, 226 insertions(+), 4 deletions(-)
|
||||
create mode 100644 libcxx/src/filesystem/posix_compat.h
|
||||
|
||||
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
|
||||
index 9965104cb5b2..0d95e766100d 100644
|
||||
--- a/libcxx/src/CMakeLists.txt
|
||||
+++ b/libcxx/src/CMakeLists.txt
|
||||
@@ -91,6 +91,7 @@ if (LIBCXX_ENABLE_FILESYSTEM)
|
||||
filesystem/filesystem_common.h
|
||||
filesystem/operations.cpp
|
||||
filesystem/directory_iterator.cpp
|
||||
+ filesystem/posix_compat.h
|
||||
)
|
||||
# Filesystem uses __int128_t, which requires a definition of __muloi4 when
|
||||
# compiled with UBSAN. This definition is not provided by libgcc_s, but is
|
||||
diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h
|
||||
index e0fdbccf96b1..8204e9a2e5f8 100644
|
||||
--- a/libcxx/src/filesystem/filesystem_common.h
|
||||
+++ b/libcxx/src/filesystem/filesystem_common.h
|
||||
@@ -224,9 +224,41 @@ private:
|
||||
using chrono::duration;
|
||||
using chrono::duration_cast;
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+// Various C runtime versions (UCRT, or the legacy msvcrt.dll used by
|
||||
+// some mingw toolchains) provide different stat function implementations,
|
||||
+// with a number of limitations with respect to what we want from the
|
||||
+// stat function. Instead provide our own (in the anonymous detail namespace
|
||||
+// in posix_compat.h) which does exactly what we want, along with our own
|
||||
+// stat structure and flag macros.
|
||||
+
|
||||
+struct TimeSpec {
|
||||
+ int64_t tv_sec;
|
||||
+ int64_t tv_nsec;
|
||||
+};
|
||||
+struct StatT {
|
||||
+ unsigned st_mode;
|
||||
+ TimeSpec st_atim;
|
||||
+ TimeSpec st_mtim;
|
||||
+ uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber
|
||||
+ struct FileIdStruct {
|
||||
+ unsigned char id[16]; // FILE_ID_INFO::FileId
|
||||
+ bool operator==(const FileIdStruct &other) const {
|
||||
+ for (int i = 0; i < 16; i++)
|
||||
+ if (id[i] != other.id[i])
|
||||
+ return false;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } st_ino;
|
||||
+ uint32_t st_nlink;
|
||||
+ uintmax_t st_size;
|
||||
+};
|
||||
+
|
||||
+#else
|
||||
using TimeSpec = struct timespec;
|
||||
using TimeVal = struct timeval;
|
||||
using StatT = struct stat;
|
||||
+#endif
|
||||
|
||||
template <class FileTimeT, class TimeT,
|
||||
bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 50a895dc2fae..548a0273ce71 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "filesystem_common.h"
|
||||
|
||||
+#include "posix_compat.h"
|
||||
+
|
||||
#if defined(_LIBCPP_WIN32API)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOMINMAX
|
||||
@@ -495,7 +497,7 @@ file_status create_file_status(error_code& m_ec, path const& p,
|
||||
|
||||
file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
|
||||
error_code m_ec;
|
||||
- if (::stat(p.c_str(), &path_stat) == -1)
|
||||
+ if (detail::stat(p.c_str(), &path_stat) == -1)
|
||||
m_ec = detail::capture_errno();
|
||||
return create_file_status(m_ec, p, path_stat, ec);
|
||||
}
|
||||
@@ -507,7 +509,7 @@ file_status posix_stat(path const& p, error_code* ec) {
|
||||
|
||||
file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
|
||||
error_code m_ec;
|
||||
- if (::lstat(p.c_str(), &path_stat) == -1)
|
||||
+ if (detail::lstat(p.c_str(), &path_stat) == -1)
|
||||
m_ec = detail::capture_errno();
|
||||
return create_file_status(m_ec, p, path_stat, ec);
|
||||
}
|
||||
@@ -545,7 +547,7 @@ file_status FileDescriptor::refresh_status(error_code& ec) {
|
||||
m_status = file_status{};
|
||||
m_stat = {};
|
||||
error_code m_ec;
|
||||
- if (::fstat(fd, &m_stat) == -1)
|
||||
+ if (detail::fstat(fd, &m_stat) == -1)
|
||||
m_ec = capture_errno();
|
||||
m_status = create_file_status(m_ec, name, m_stat, &ec);
|
||||
return m_status;
|
||||
@@ -1197,7 +1199,7 @@ path __read_symlink(const path& p, error_code* ec) {
|
||||
auto buff = std::unique_ptr<char[], NullDeleter>(stack_buff);
|
||||
#else
|
||||
StatT sb;
|
||||
- if (::lstat(p.c_str(), &sb) == -1) {
|
||||
+ if (detail::lstat(p.c_str(), &sb) == -1) {
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
const size_t size = sb.st_size + 1;
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
new file mode 100644
|
||||
index 000000000000..3eec4634e929
|
||||
--- /dev/null
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -0,0 +1,187 @@
|
||||
+//===----------------------------------------------------------------------===//
|
||||
+//
|
||||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
+// See https://llvm.org/LICENSE.txt for license information.
|
||||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
+//
|
||||
+//===----------------------------------------------------------------------===//
|
||||
+
|
||||
+//
|
||||
+// POSIX-like portability helper functions.
|
||||
+//
|
||||
+// These generally behave like the proper posix functions, with these
|
||||
+// exceptions:
|
||||
+// On Windows, they take paths in wchar_t* form, instead of char* form.
|
||||
+//
|
||||
+// These are provided within an anonymous namespace within the detail
|
||||
+// namespace - callers need to include this header and call them as
|
||||
+// detail::function(), regardless of platform.
|
||||
+//
|
||||
+
|
||||
+#ifndef POSIX_COMPAT_H
|
||||
+#define POSIX_COMPAT_H
|
||||
+
|
||||
+#include "filesystem"
|
||||
+
|
||||
+#include "filesystem_common.h"
|
||||
+
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+# define WIN32_LEAN_AND_MEAN
|
||||
+# define NOMINMAX
|
||||
+# include <windows.h>
|
||||
+# include <io.h>
|
||||
+#else
|
||||
+# include <unistd.h>
|
||||
+# include <sys/stat.h>
|
||||
+# include <sys/statvfs.h>
|
||||
+#endif
|
||||
+#include <time.h>
|
||||
+
|
||||
+_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
|
||||
+
|
||||
+namespace detail {
|
||||
+namespace {
|
||||
+
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+
|
||||
+// Various C runtime header sets provide more or less of these. As we
|
||||
+// provide our own implementation, undef all potential defines from the
|
||||
+// C runtime headers and provide a complete set of macros of our own.
|
||||
+
|
||||
+#undef _S_IFMT
|
||||
+#undef _S_IFDIR
|
||||
+#undef _S_IFCHR
|
||||
+#undef _S_IFIFO
|
||||
+#undef _S_IFREG
|
||||
+#undef _S_IFBLK
|
||||
+#undef _S_IFLNK
|
||||
+#undef _S_IFSOCK
|
||||
+
|
||||
+#define _S_IFMT 0xF000
|
||||
+#define _S_IFDIR 0x4000
|
||||
+#define _S_IFCHR 0x2000
|
||||
+#define _S_IFIFO 0x1000
|
||||
+#define _S_IFREG 0x8000
|
||||
+#define _S_IFBLK 0x6000
|
||||
+#define _S_IFLNK 0xA000
|
||||
+#define _S_IFSOCK 0xC000
|
||||
+
|
||||
+#undef S_ISDIR
|
||||
+#undef S_ISFIFO
|
||||
+#undef S_ISCHR
|
||||
+#undef S_ISREG
|
||||
+#undef S_ISLNK
|
||||
+#undef S_ISBLK
|
||||
+#undef S_ISSOCK
|
||||
+
|
||||
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
||||
+#define S_ISCHR(m) (((m) & _S_IFMT) == _S_IFCHR)
|
||||
+#define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO)
|
||||
+#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||
+#define S_ISBLK(m) (((m) & _S_IFMT) == _S_IFBLK)
|
||||
+#define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK)
|
||||
+#define S_ISSOCK(m) (((m) & _S_IFMT) == _S_IFSOCK)
|
||||
+
|
||||
+
|
||||
+// There were 369 years and 89 leap days from the Windows epoch
|
||||
+// (1601) to the Unix epoch (1970).
|
||||
+#define FILE_TIME_OFFSET_SECS (uint64_t(369 * 365 + 89) * (24 * 60 * 60))
|
||||
+
|
||||
+TimeSpec filetime_to_timespec(LARGE_INTEGER li) {
|
||||
+ TimeSpec ret;
|
||||
+ ret.tv_sec = li.QuadPart / 10000000 - FILE_TIME_OFFSET_SECS;
|
||||
+ ret.tv_nsec = (li.QuadPart % 10000000) * 100;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int set_errno(int e = GetLastError()) {
|
||||
+ errno = static_cast<int>(__win_err_to_errc(e));
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+class WinHandle {
|
||||
+public:
|
||||
+ WinHandle(const wchar_t *p, DWORD access, DWORD flags) {
|
||||
+ h = CreateFileW(
|
||||
+ p, access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | flags, nullptr);
|
||||
+ }
|
||||
+ ~WinHandle() {
|
||||
+ if (h != INVALID_HANDLE_VALUE)
|
||||
+ CloseHandle(h);
|
||||
+ }
|
||||
+ operator HANDLE() const { return h; }
|
||||
+ operator bool() const { return h != INVALID_HANDLE_VALUE; }
|
||||
+
|
||||
+private:
|
||||
+ HANDLE h;
|
||||
+};
|
||||
+
|
||||
+int stat_handle(HANDLE h, StatT *buf) {
|
||||
+ FILE_BASIC_INFO basic;
|
||||
+ if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic)))
|
||||
+ return set_errno();
|
||||
+ memset(buf, 0, sizeof(*buf));
|
||||
+ buf->st_mtim = filetime_to_timespec(basic.LastWriteTime);
|
||||
+ buf->st_atim = filetime_to_timespec(basic.LastAccessTime);
|
||||
+ buf->st_mode = 0555; // Read-only
|
||||
+ if (!(basic.FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
+ buf->st_mode |= 0222; // Write
|
||||
+ if (basic.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
+ buf->st_mode |= _S_IFDIR;
|
||||
+ } else {
|
||||
+ buf->st_mode |= _S_IFREG;
|
||||
+ }
|
||||
+ if (basic.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
+ FILE_ATTRIBUTE_TAG_INFO tag;
|
||||
+ if (!GetFileInformationByHandleEx(h, FileAttributeTagInfo, &tag,
|
||||
+ sizeof(tag)))
|
||||
+ return set_errno();
|
||||
+ if (tag.ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
||||
+ buf->st_mode = (buf->st_mode & ~_S_IFMT) | _S_IFLNK;
|
||||
+ }
|
||||
+ FILE_STANDARD_INFO standard;
|
||||
+ if (!GetFileInformationByHandleEx(h, FileStandardInfo, &standard,
|
||||
+ sizeof(standard)))
|
||||
+ return set_errno();
|
||||
+ buf->st_nlink = standard.NumberOfLinks;
|
||||
+ buf->st_size = standard.EndOfFile.QuadPart;
|
||||
+ BY_HANDLE_FILE_INFORMATION info;
|
||||
+ if (!GetFileInformationByHandle(h, &info))
|
||||
+ return set_errno();
|
||||
+ buf->st_dev = info.dwVolumeSerialNumber;
|
||||
+ memcpy(&buf->st_ino.id[0], &info.nFileIndexHigh, 4);
|
||||
+ memcpy(&buf->st_ino.id[4], &info.nFileIndexLow, 4);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int stat_file(const wchar_t *path, StatT *buf, DWORD flags) {
|
||||
+ WinHandle h(path, FILE_READ_ATTRIBUTES, flags);
|
||||
+ if (!h)
|
||||
+ return set_errno();
|
||||
+ int ret = stat_handle(h, buf);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int stat(const wchar_t *path, StatT *buf) { return stat_file(path, buf, 0); }
|
||||
+
|
||||
+int lstat(const wchar_t *path, StatT *buf) {
|
||||
+ return stat_file(path, buf, FILE_FLAG_OPEN_REPARSE_POINT);
|
||||
+}
|
||||
+
|
||||
+int fstat(int fd, StatT *buf) {
|
||||
+ HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||
+ return stat_handle(h, buf);
|
||||
+}
|
||||
+#else
|
||||
+using ::fstat;
|
||||
+using ::lstat;
|
||||
+using ::stat;
|
||||
+#endif
|
||||
+
|
||||
+} // namespace
|
||||
+} // end namespace detail
|
||||
+
|
||||
+_LIBCPP_END_NAMESPACE_FILESYSTEM
|
||||
+
|
||||
+#endif // POSIX_COMPAT_H
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
From ab432bcd28596265e97eb062a19cbbbdc3d426f5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 22:56:03 +0200
|
||||
Subject: [PATCH 02/25] [libcxx] Implement _FilesystemClock::now() and
|
||||
__last_write_time for windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91142
|
||||
|
||||
(cherry picked from commit 592d62352933d34af62334d172c6fc665933e0de)
|
||||
---
|
||||
libcxx/src/filesystem/filesystem_common.h | 6 ++++++
|
||||
libcxx/src/filesystem/operations.cpp | 23 +++++++++++++++++++++--
|
||||
libcxx/src/filesystem/posix_compat.h | 17 +++++++++++++++++
|
||||
3 files changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h
|
||||
index 8204e9a2e5f8..a4505171c3eb 100644
|
||||
--- a/libcxx/src/filesystem/filesystem_common.h
|
||||
+++ b/libcxx/src/filesystem/filesystem_common.h
|
||||
@@ -437,7 +437,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+using fs_time = time_util<file_time_type, int64_t, TimeSpec>;
|
||||
+#else
|
||||
using fs_time = time_util<file_time_type, time_t, TimeSpec>;
|
||||
+#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
|
||||
@@ -456,6 +460,7 @@ inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
|
||||
inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
|
||||
#endif
|
||||
|
||||
+#if !defined(_LIBCPP_WIN32API)
|
||||
inline TimeVal make_timeval(TimeSpec const& ts) {
|
||||
using namespace chrono;
|
||||
auto Convert = [](long nsec) {
|
||||
@@ -498,6 +503,7 @@ bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
|
||||
return posix_utimensat(p, TS, ec);
|
||||
#endif
|
||||
}
|
||||
+#endif /* !_LIBCPP_WIN32API */
|
||||
|
||||
} // namespace
|
||||
} // end namespace detail
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 548a0273ce71..40a863db69a1 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -42,7 +42,7 @@
|
||||
# define _LIBCPP_FILESYSTEM_USE_FSTREAM
|
||||
#endif
|
||||
|
||||
-#if !defined(CLOCK_REALTIME)
|
||||
+#if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API)
|
||||
# include <sys/time.h> // for gettimeofday and timeval
|
||||
#endif
|
||||
|
||||
@@ -567,7 +567,14 @@ const bool _FilesystemClock::is_steady;
|
||||
|
||||
_FilesystemClock::time_point _FilesystemClock::now() noexcept {
|
||||
typedef chrono::duration<rep> __secs;
|
||||
-#if defined(CLOCK_REALTIME)
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ typedef chrono::duration<rep, nano> __nsecs;
|
||||
+ FILETIME time;
|
||||
+ GetSystemTimeAsFileTime(&time);
|
||||
+ TimeSpec tp = detail::filetime_to_timespec(time);
|
||||
+ return time_point(__secs(tp.tv_sec) +
|
||||
+ chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
|
||||
+#elif defined(CLOCK_REALTIME)
|
||||
typedef chrono::duration<rep, nano> __nsecs;
|
||||
struct timespec tp;
|
||||
if (0 != clock_gettime(CLOCK_REALTIME, &tp))
|
||||
@@ -1121,6 +1128,17 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
|
||||
using detail::fs_time;
|
||||
ErrorHandler<void> err("last_write_time", ec, &p);
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ TimeSpec ts;
|
||||
+ if (!fs_time::convert_to_timespec(ts, new_time))
|
||||
+ return err.report(errc::value_too_large);
|
||||
+ detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0);
|
||||
+ if (!h)
|
||||
+ return err.report(detail::make_windows_error(GetLastError()));
|
||||
+ FILETIME last_write = timespec_to_filetime(ts);
|
||||
+ if (!SetFileTime(h, nullptr, nullptr, &last_write))
|
||||
+ return err.report(detail::make_windows_error(GetLastError()));
|
||||
+#else
|
||||
error_code m_ec;
|
||||
array<TimeSpec, 2> tbuf;
|
||||
#if !defined(_LIBCPP_USE_UTIMENSAT)
|
||||
@@ -1142,6 +1160,7 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
|
||||
detail::set_file_times(p, tbuf, m_ec);
|
||||
if (m_ec)
|
||||
return err.report(m_ec);
|
||||
+#endif
|
||||
}
|
||||
|
||||
void __permissions(const path& p, perms prms, perm_options opts,
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 3eec4634e929..7caf9d28b49d 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -94,6 +94,23 @@ TimeSpec filetime_to_timespec(LARGE_INTEGER li) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
+TimeSpec filetime_to_timespec(FILETIME ft) {
|
||||
+ LARGE_INTEGER li;
|
||||
+ li.LowPart = ft.dwLowDateTime;
|
||||
+ li.HighPart = ft.dwHighDateTime;
|
||||
+ return filetime_to_timespec(li);
|
||||
+}
|
||||
+
|
||||
+FILETIME timespec_to_filetime(TimeSpec ts) {
|
||||
+ LARGE_INTEGER li;
|
||||
+ li.QuadPart =
|
||||
+ ts.tv_nsec / 100 + (ts.tv_sec + FILE_TIME_OFFSET_SECS) * 10000000;
|
||||
+ FILETIME ft;
|
||||
+ ft.dwLowDateTime = li.LowPart;
|
||||
+ ft.dwHighDateTime = li.HighPart;
|
||||
+ return ft;
|
||||
+}
|
||||
+
|
||||
int set_errno(int e = GetLastError()) {
|
||||
errno = static_cast<int>(__win_err_to_errc(e));
|
||||
return -1;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
From 13bc151ad49587f94a123cdb3e2ba770c1513d9d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Fri, 6 Nov 2020 11:16:30 +0200
|
||||
Subject: [PATCH 03/25] [libcxx] Hook up a number of operation functions to
|
||||
their windows counterparts
|
||||
|
||||
Use the corresponding wchar functions, named "_wfunc" instead of "func",
|
||||
where feasible, or reimplement functions with native windows APIs.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91143
|
||||
|
||||
(cherry picked from commit efec3cc6524bc536459b9cb6faca190b1e3804b6)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 41 ++++++-----
|
||||
libcxx/src/filesystem/posix_compat.h | 102 +++++++++++++++++++++++++++
|
||||
2 files changed, 124 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 40a863db69a1..ddb4d7588e54 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -405,7 +405,7 @@ struct FileDescriptor {
|
||||
static FileDescriptor create(const path* p, error_code& ec, Args... args) {
|
||||
ec.clear();
|
||||
int fd;
|
||||
- if ((fd = ::open(p->c_str(), args...)) == -1) {
|
||||
+ if ((fd = detail::open(p->c_str(), args...)) == -1) {
|
||||
ec = capture_errno();
|
||||
return FileDescriptor{p};
|
||||
}
|
||||
@@ -431,7 +431,7 @@ struct FileDescriptor {
|
||||
|
||||
void close() noexcept {
|
||||
if (fd != -1)
|
||||
- ::close(fd);
|
||||
+ detail::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ file_status posix_lstat(path const& p, error_code* ec) {
|
||||
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
|
||||
bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
|
||||
- if (::ftruncate(fd.fd, to_size) == -1) {
|
||||
+ if (detail::ftruncate(fd.fd, to_size) == -1) {
|
||||
ec = capture_errno();
|
||||
return true;
|
||||
}
|
||||
@@ -828,8 +828,8 @@ bool __copy_file(const path& from, const path& to, copy_options options,
|
||||
ErrorHandler<bool> err("copy_file", ec, &to, &from);
|
||||
|
||||
error_code m_ec;
|
||||
- FileDescriptor from_fd =
|
||||
- FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
|
||||
+ FileDescriptor from_fd = FileDescriptor::create_with_status(
|
||||
+ &from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY);
|
||||
if (m_ec)
|
||||
return err.report(m_ec);
|
||||
|
||||
@@ -881,7 +881,7 @@ bool __copy_file(const path& from, const path& to, copy_options options,
|
||||
|
||||
// Don't truncate right away. We may not be opening the file we originally
|
||||
// looked at; we'll check this later.
|
||||
- int to_open_flags = O_WRONLY;
|
||||
+ int to_open_flags = O_WRONLY | O_BINARY;
|
||||
if (!to_exists)
|
||||
to_open_flags |= O_CREAT;
|
||||
FileDescriptor to_fd = FileDescriptor::create_with_status(
|
||||
@@ -917,10 +917,13 @@ void __copy_symlink(const path& existing_symlink, const path& new_symlink,
|
||||
if (ec && *ec) {
|
||||
return;
|
||||
}
|
||||
- // NOTE: proposal says you should detect if you should call
|
||||
- // create_symlink or create_directory_symlink. I don't think this
|
||||
- // is needed with POSIX
|
||||
- __create_symlink(real_path, new_symlink, ec);
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ error_code local_ec;
|
||||
+ if (is_directory(real_path, local_ec))
|
||||
+ __create_directory_symlink(real_path, new_symlink, ec);
|
||||
+ else
|
||||
+#endif
|
||||
+ __create_symlink(real_path, new_symlink, ec);
|
||||
}
|
||||
|
||||
bool __create_directories(const path& p, error_code* ec) {
|
||||
@@ -953,7 +956,7 @@ bool __create_directories(const path& p, error_code* ec) {
|
||||
bool __create_directory(const path& p, error_code* ec) {
|
||||
ErrorHandler<bool> err("create_directory", ec, &p);
|
||||
|
||||
- if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
|
||||
+ if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
|
||||
return true;
|
||||
|
||||
if (errno == EEXIST) {
|
||||
@@ -981,7 +984,7 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) {
|
||||
return err.report(errc::not_a_directory,
|
||||
"the specified attribute path is invalid");
|
||||
|
||||
- if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
|
||||
+ if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0)
|
||||
return true;
|
||||
|
||||
if (errno == EEXIST) {
|
||||
@@ -1000,19 +1003,19 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) {
|
||||
void __create_directory_symlink(path const& from, path const& to,
|
||||
error_code* ec) {
|
||||
ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
|
||||
- if (::symlink(from.c_str(), to.c_str()) != 0)
|
||||
+ if (detail::symlink_dir(from.c_str(), to.c_str()) == -1)
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
|
||||
void __create_hard_link(const path& from, const path& to, error_code* ec) {
|
||||
ErrorHandler<void> err("create_hard_link", ec, &from, &to);
|
||||
- if (::link(from.c_str(), to.c_str()) == -1)
|
||||
+ if (detail::link(from.c_str(), to.c_str()) == -1)
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
|
||||
void __create_symlink(path const& from, path const& to, error_code* ec) {
|
||||
ErrorHandler<void> err("create_symlink", ec, &from, &to);
|
||||
- if (::symlink(from.c_str(), to.c_str()) == -1)
|
||||
+ if (detail::symlink_file(from.c_str(), to.c_str()) == -1)
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
|
||||
@@ -1032,7 +1035,7 @@ path __current_path(error_code* ec) {
|
||||
|
||||
void __current_path(const path& p, error_code* ec) {
|
||||
ErrorHandler<void> err("current_path", ec, &p);
|
||||
- if (::chdir(p.c_str()) == -1)
|
||||
+ if (detail::chdir(p.c_str()) == -1)
|
||||
err.report(capture_errno());
|
||||
}
|
||||
|
||||
@@ -1236,7 +1239,7 @@ path __read_symlink(const path& p, error_code* ec) {
|
||||
|
||||
bool __remove(const path& p, error_code* ec) {
|
||||
ErrorHandler<bool> err("remove", ec, &p);
|
||||
- if (::remove(p.c_str()) == -1) {
|
||||
+ if (detail::remove(p.c_str()) == -1) {
|
||||
if (errno != ENOENT)
|
||||
err.report(capture_errno());
|
||||
return false;
|
||||
@@ -1285,13 +1288,13 @@ uintmax_t __remove_all(const path& p, error_code* ec) {
|
||||
|
||||
void __rename(const path& from, const path& to, error_code* ec) {
|
||||
ErrorHandler<void> err("rename", ec, &from, &to);
|
||||
- if (::rename(from.c_str(), to.c_str()) == -1)
|
||||
+ if (detail::rename(from.c_str(), to.c_str()) == -1)
|
||||
err.report(capture_errno());
|
||||
}
|
||||
|
||||
void __resize_file(const path& p, uintmax_t size, error_code* ec) {
|
||||
ErrorHandler<void> err("resize_file", ec, &p);
|
||||
- if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
|
||||
+ if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 7caf9d28b49d..1e70e12cb4d7 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -12,6 +12,8 @@
|
||||
// These generally behave like the proper posix functions, with these
|
||||
// exceptions:
|
||||
// On Windows, they take paths in wchar_t* form, instead of char* form.
|
||||
+// The symlink() function is split into two frontends, symlink_file()
|
||||
+// and symlink_dir().
|
||||
//
|
||||
// These are provided within an anonymous namespace within the detail
|
||||
// namespace - callers need to include this header and call them as
|
||||
@@ -82,6 +84,8 @@ namespace {
|
||||
#define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK)
|
||||
#define S_ISSOCK(m) (((m) & _S_IFMT) == _S_IFSOCK)
|
||||
|
||||
+#define O_NONBLOCK 0
|
||||
+
|
||||
|
||||
// There were 369 years and 89 leap days from the Windows epoch
|
||||
// (1601) to the Unix epoch (1970).
|
||||
@@ -190,10 +194,108 @@ int fstat(int fd, StatT *buf) {
|
||||
HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||
return stat_handle(h, buf);
|
||||
}
|
||||
+
|
||||
+int mkdir(const wchar_t *path, int permissions) {
|
||||
+ (void)permissions;
|
||||
+ return _wmkdir(path);
|
||||
+}
|
||||
+
|
||||
+int symlink_file_dir(const wchar_t *oldname, const wchar_t *newname,
|
||||
+ bool is_dir) {
|
||||
+ DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
|
||||
+ if (CreateSymbolicLinkW(newname, oldname,
|
||||
+ flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
+ return 0;
|
||||
+ int e = GetLastError();
|
||||
+ if (e != ERROR_INVALID_PARAMETER)
|
||||
+ return set_errno(e);
|
||||
+ if (CreateSymbolicLinkW(newname, oldname, flags))
|
||||
+ return 0;
|
||||
+ return set_errno();
|
||||
+}
|
||||
+
|
||||
+int symlink_file(const wchar_t *oldname, const wchar_t *newname) {
|
||||
+ return symlink_file_dir(oldname, newname, false);
|
||||
+}
|
||||
+
|
||||
+int symlink_dir(const wchar_t *oldname, const wchar_t *newname) {
|
||||
+ return symlink_file_dir(oldname, newname, true);
|
||||
+}
|
||||
+
|
||||
+int link(const wchar_t *oldname, const wchar_t *newname) {
|
||||
+ if (CreateHardLinkW(newname, oldname, nullptr))
|
||||
+ return 0;
|
||||
+ return set_errno();
|
||||
+}
|
||||
+
|
||||
+int remove(const wchar_t *path) {
|
||||
+ detail::WinHandle h(path, DELETE, FILE_FLAG_OPEN_REPARSE_POINT);
|
||||
+ if (!h)
|
||||
+ return set_errno();
|
||||
+ FILE_DISPOSITION_INFO info;
|
||||
+ info.DeleteFile = TRUE;
|
||||
+ if (!SetFileInformationByHandle(h, FileDispositionInfo, &info, sizeof(info)))
|
||||
+ return set_errno();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int truncate_handle(HANDLE h, off_t length) {
|
||||
+ LARGE_INTEGER size_param;
|
||||
+ size_param.QuadPart = length;
|
||||
+ if (!SetFilePointerEx(h, size_param, 0, FILE_BEGIN))
|
||||
+ return set_errno();
|
||||
+ if (!SetEndOfFile(h))
|
||||
+ return set_errno();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int ftruncate(int fd, off_t length) {
|
||||
+ HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||
+ return truncate_handle(h, length);
|
||||
+}
|
||||
+
|
||||
+int truncate(const wchar_t *path, off_t length) {
|
||||
+ detail::WinHandle h(path, GENERIC_WRITE, 0);
|
||||
+ if (!h)
|
||||
+ return set_errno();
|
||||
+ return truncate_handle(h, length);
|
||||
+}
|
||||
+
|
||||
+int rename(const wchar_t *from, const wchar_t *to) {
|
||||
+ if (!(MoveFileExW(from, to,
|
||||
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING |
|
||||
+ MOVEFILE_WRITE_THROUGH)))
|
||||
+ return set_errno();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+template <class... Args> int open(const wchar_t *filename, Args... args) {
|
||||
+ return _wopen(filename, args...);
|
||||
+}
|
||||
+int close(int fd) { return _close(fd); }
|
||||
+int chdir(const wchar_t *path) { return _wchdir(path); }
|
||||
#else
|
||||
+int symlink_file(const char *oldname, const char *newname) {
|
||||
+ return ::symlink(oldname, newname);
|
||||
+}
|
||||
+int symlink_dir(const char *oldname, const char *newname) {
|
||||
+ return ::symlink(oldname, newname);
|
||||
+}
|
||||
+using ::chdir;
|
||||
+using ::close;
|
||||
using ::fstat;
|
||||
+using ::ftruncate;
|
||||
+using ::link;
|
||||
using ::lstat;
|
||||
+using ::mkdir;
|
||||
+using ::open;
|
||||
+using ::remove;
|
||||
+using ::rename;
|
||||
using ::stat;
|
||||
+using ::truncate;
|
||||
+
|
||||
+#define O_BINARY 0
|
||||
+
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
From 21ffff20ef2e05f8c99bd120d7b1212d75f14dcd Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Mon, 9 Nov 2020 15:20:18 +0200
|
||||
Subject: [PATCH 04/25] [libcxx] Sanitize paths before creating symlinks on
|
||||
windows
|
||||
|
||||
The MS STL does even more cleanup (corresponding to lexically_normal
|
||||
I think), but this seems to be the very minimum needed for making the
|
||||
symlinks work when the target path contains non-native paths.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91145
|
||||
|
||||
(cherry picked from commit f65ba25cf37a57dc87db7af389c9dc637ca7dd8c)
|
||||
---
|
||||
libcxx/src/filesystem/posix_compat.h | 3 +++
|
||||
.../create_symlink.pass.cpp | 20 +++++++++++++++++++
|
||||
2 files changed, 23 insertions(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 1e70e12cb4d7..0dbae1235a00 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -202,6 +202,9 @@ int mkdir(const wchar_t *path, int permissions) {
|
||||
|
||||
int symlink_file_dir(const wchar_t *oldname, const wchar_t *newname,
|
||||
bool is_dir) {
|
||||
+ path dest(oldname);
|
||||
+ dest.make_preferred();
|
||||
+ oldname = dest.c_str();
|
||||
DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
|
||||
if (CreateSymbolicLinkW(newname, oldname,
|
||||
flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp
|
||||
index 47ec916a169b..3b54cff309b7 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp
|
||||
@@ -71,5 +71,25 @@ TEST_CASE(create_symlink_basic)
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_CASE(create_symlink_dest_cleanup)
|
||||
+{
|
||||
+ scoped_test_env env;
|
||||
+ const path dir = env.create_dir("dir");
|
||||
+ const path file = env.create_file("file", 42);
|
||||
+ const path sym = dir / "link";
|
||||
+ // The target path has to be normalized to backslashes before creating
|
||||
+ // the link on windows, otherwise the link isn't dereferencable.
|
||||
+ const path sym_target = "../file";
|
||||
+ path sym_target_normalized = sym_target;
|
||||
+ sym_target_normalized.make_preferred();
|
||||
+ std::error_code ec;
|
||||
+ fs::create_symlink(sym_target, sym, ec);
|
||||
+ TEST_REQUIRE(!ec);
|
||||
+ TEST_CHECK(equivalent(sym, file, ec));
|
||||
+ const path ret = fs::read_symlink(sym, ec);
|
||||
+ TEST_CHECK(!ec);
|
||||
+ TEST_CHECK(ret.native() == sym_target_normalized.native());
|
||||
+}
|
||||
+
|
||||
|
||||
TEST_SUITE_END()
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
From 51a0f3a5af65c8e8e1618dc5621705471aba2151 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 23:32:13 +0200
|
||||
Subject: [PATCH 05/25] [libcxx] Implement the space function for windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91168
|
||||
|
||||
(cherry picked from commit a3cc99658d52f79faad26beeea06691b3a50bc95)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 4 +--
|
||||
libcxx/src/filesystem/posix_compat.h | 37 ++++++++++++++++++++++++++++
|
||||
2 files changed, 39 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index ddb4d7588e54..fcb5c2def23c 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1301,8 +1301,8 @@ void __resize_file(const path& p, uintmax_t size, error_code* ec) {
|
||||
space_info __space(const path& p, error_code* ec) {
|
||||
ErrorHandler<void> err("space", ec, &p);
|
||||
space_info si;
|
||||
- struct statvfs m_svfs = {};
|
||||
- if (::statvfs(p.c_str(), &m_svfs) == -1) {
|
||||
+ detail::StatVFS m_svfs = {};
|
||||
+ if (detail::statvfs(p.c_str(), &m_svfs) == -1) {
|
||||
err.report(capture_errno());
|
||||
si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
|
||||
return si;
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 0dbae1235a00..5f868a090693 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -277,6 +277,40 @@ template <class... Args> int open(const wchar_t *filename, Args... args) {
|
||||
}
|
||||
int close(int fd) { return _close(fd); }
|
||||
int chdir(const wchar_t *path) { return _wchdir(path); }
|
||||
+
|
||||
+struct StatVFS {
|
||||
+ uint64_t f_frsize;
|
||||
+ uint64_t f_blocks;
|
||||
+ uint64_t f_bfree;
|
||||
+ uint64_t f_bavail;
|
||||
+};
|
||||
+
|
||||
+int statvfs(const wchar_t *p, StatVFS *buf) {
|
||||
+ path dir = p;
|
||||
+ while (true) {
|
||||
+ error_code local_ec;
|
||||
+ const file_status st = status(dir, local_ec);
|
||||
+ if (!exists(st) || is_directory(st))
|
||||
+ break;
|
||||
+ path parent = dir.parent_path();
|
||||
+ if (parent == dir) {
|
||||
+ errno = ENOENT;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ dir = parent;
|
||||
+ }
|
||||
+ ULARGE_INTEGER free_bytes_available_to_caller, total_number_of_bytes,
|
||||
+ total_number_of_free_bytes;
|
||||
+ if (!GetDiskFreeSpaceExW(dir.c_str(), &free_bytes_available_to_caller,
|
||||
+ &total_number_of_bytes, &total_number_of_free_bytes))
|
||||
+ return set_errno();
|
||||
+ buf->f_frsize = 1;
|
||||
+ buf->f_blocks = total_number_of_bytes.QuadPart;
|
||||
+ buf->f_bfree = total_number_of_free_bytes.QuadPart;
|
||||
+ buf->f_bavail = free_bytes_available_to_caller.QuadPart;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
#else
|
||||
int symlink_file(const char *oldname, const char *newname) {
|
||||
return ::symlink(oldname, newname);
|
||||
@@ -295,10 +329,13 @@ using ::open;
|
||||
using ::remove;
|
||||
using ::rename;
|
||||
using ::stat;
|
||||
+using ::statvfs;
|
||||
using ::truncate;
|
||||
|
||||
#define O_BINARY 0
|
||||
|
||||
+using StatVFS = struct statvfs;
|
||||
+
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
From 0bdb2f73e8ba72de291d1ca95363835ab538bdab Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 23:46:12 +0200
|
||||
Subject: [PATCH 06/25] [libcxx] Implement the current_path function for
|
||||
windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91169
|
||||
|
||||
(cherry picked from commit 0c71c914faa371ba502a2e1835f763104837cb9f)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 25 +++++++++++++++++++++----
|
||||
libcxx/src/filesystem/posix_compat.h | 2 ++
|
||||
2 files changed, 23 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index fcb5c2def23c..429a58501a49 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1022,15 +1022,32 @@ void __create_symlink(path const& from, path const& to, error_code* ec) {
|
||||
path __current_path(error_code* ec) {
|
||||
ErrorHandler<path> err("current_path", ec);
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ // Common extension outside of POSIX getcwd() spec, without needing to
|
||||
+ // preallocate a buffer. Also supported by a number of other POSIX libcs.
|
||||
+ int size = 0;
|
||||
+ path::value_type* ptr = nullptr;
|
||||
+ typedef decltype(&::free) Deleter;
|
||||
+ Deleter deleter = &::free;
|
||||
+#else
|
||||
auto size = ::pathconf(".", _PC_PATH_MAX);
|
||||
_LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
|
||||
|
||||
- auto buff = unique_ptr<char[]>(new char[size + 1]);
|
||||
- char* ret;
|
||||
- if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
|
||||
+ auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]);
|
||||
+ path::value_type* ptr = buff.get();
|
||||
+
|
||||
+ // Preallocated buffer, don't free the buffer in the second unique_ptr
|
||||
+ // below.
|
||||
+ struct Deleter { void operator()(void*) const {} };
|
||||
+ Deleter deleter;
|
||||
+#endif
|
||||
+
|
||||
+ unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size),
|
||||
+ deleter);
|
||||
+ if (hold.get() == nullptr)
|
||||
return err.report(capture_errno(), "call to getcwd failed");
|
||||
|
||||
- return {buff.get()};
|
||||
+ return {hold.get()};
|
||||
}
|
||||
|
||||
void __current_path(const path& p, error_code* ec) {
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 5f868a090693..13753fdbb760 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -311,6 +311,7 @@ int statvfs(const wchar_t *p, StatVFS *buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+wchar_t *getcwd(wchar_t *buff, size_t size) { return _wgetcwd(buff, size); }
|
||||
#else
|
||||
int symlink_file(const char *oldname, const char *newname) {
|
||||
return ::symlink(oldname, newname);
|
||||
@@ -322,6 +323,7 @@ using ::chdir;
|
||||
using ::close;
|
||||
using ::fstat;
|
||||
using ::ftruncate;
|
||||
+using ::getcwd;
|
||||
using ::link;
|
||||
using ::lstat;
|
||||
using ::mkdir;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
From b6ef948856bfde6326ebc2d1fddc24890b4182f9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 23:51:12 +0200
|
||||
Subject: [PATCH 07/25] [libcxx] Implement the canonical function for windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91170
|
||||
|
||||
(cherry picked from commit 83d705adb2e043e576c9cbaf9709795bc69fe5cf)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 14 +++++-----
|
||||
libcxx/src/filesystem/posix_compat.h | 38 ++++++++++++++++++++++++++++
|
||||
2 files changed, 45 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 429a58501a49..fc18de9e5d80 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -636,20 +636,20 @@ path __canonical(path const& orig_p, error_code* ec) {
|
||||
ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
|
||||
|
||||
path p = __do_absolute(orig_p, &cwd, ec);
|
||||
-#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112
|
||||
- std::unique_ptr<char, decltype(&::free)>
|
||||
- hold(::realpath(p.c_str(), nullptr), &::free);
|
||||
+#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
|
||||
+ std::unique_ptr<path::value_type, decltype(&::free)>
|
||||
+ hold(detail::realpath(p.c_str(), nullptr), &::free);
|
||||
if (hold.get() == nullptr)
|
||||
return err.report(capture_errno());
|
||||
return {hold.get()};
|
||||
#else
|
||||
#if defined(__MVS__) && !defined(PATH_MAX)
|
||||
- char buff[ _XOPEN_PATH_MAX + 1 ];
|
||||
+ path::value_type buff[ _XOPEN_PATH_MAX + 1 ];
|
||||
#else
|
||||
- char buff[PATH_MAX + 1];
|
||||
+ path::value_type buff[PATH_MAX + 1];
|
||||
#endif
|
||||
- char* ret;
|
||||
- if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
|
||||
+ path::value_type* ret;
|
||||
+ if ((ret = detail::realpath(p.c_str(), buff)) == nullptr)
|
||||
return err.report(capture_errno());
|
||||
return {ret};
|
||||
#endif
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 13753fdbb760..1adce3a779c2 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -312,6 +312,43 @@ int statvfs(const wchar_t *p, StatVFS *buf) {
|
||||
}
|
||||
|
||||
wchar_t *getcwd(wchar_t *buff, size_t size) { return _wgetcwd(buff, size); }
|
||||
+
|
||||
+wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) {
|
||||
+ // Only expected to be used with us allocating the buffer.
|
||||
+ _LIBCPP_ASSERT(resolved_name == nullptr,
|
||||
+ "Windows realpath() assumes a null resolved_name");
|
||||
+
|
||||
+ WinHandle h(path, FILE_READ_ATTRIBUTES, 0);
|
||||
+ if (!h) {
|
||||
+ set_errno();
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ size_t buff_size = MAX_PATH + 10;
|
||||
+ std::unique_ptr<wchar_t, decltype(&::free)> buff(
|
||||
+ static_cast<wchar_t *>(malloc(buff_size * sizeof(wchar_t))), &::free);
|
||||
+ DWORD retval = GetFinalPathNameByHandleW(
|
||||
+ h, buff.get(), buff_size, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
|
||||
+ if (retval > buff_size) {
|
||||
+ buff_size = retval;
|
||||
+ buff.reset(static_cast<wchar_t *>(malloc(buff_size * sizeof(wchar_t))));
|
||||
+ retval = GetFinalPathNameByHandleW(h, buff.get(), buff_size,
|
||||
+ FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
|
||||
+ }
|
||||
+ if (!retval) {
|
||||
+ set_errno();
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ wchar_t *ptr = buff.get();
|
||||
+ if (!wcsncmp(ptr, L"\\\\?\\", 4)) {
|
||||
+ if (ptr[5] == ':') { // \\?\X: -> X:
|
||||
+ memmove(&ptr[0], &ptr[4], (wcslen(&ptr[4]) + 1) * sizeof(wchar_t));
|
||||
+ } else if (!wcsncmp(&ptr[4], L"UNC\\", 4)) { // \\?\UNC\server -> \\server
|
||||
+ wcscpy(&ptr[0], L"\\\\");
|
||||
+ memmove(&ptr[2], &ptr[8], (wcslen(&ptr[8]) + 1) * sizeof(wchar_t));
|
||||
+ }
|
||||
+ }
|
||||
+ return buff.release();
|
||||
+}
|
||||
#else
|
||||
int symlink_file(const char *oldname, const char *newname) {
|
||||
return ::symlink(oldname, newname);
|
||||
@@ -328,6 +365,7 @@ using ::link;
|
||||
using ::lstat;
|
||||
using ::mkdir;
|
||||
using ::open;
|
||||
+using ::realpath;
|
||||
using ::remove;
|
||||
using ::rename;
|
||||
using ::stat;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
From 96748da73f57e6b080643d03e41e8a690ee571a9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 23:55:10 +0200
|
||||
Subject: [PATCH 08/25] [libcxx] Implement the permissions function for windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91171
|
||||
|
||||
(cherry picked from commit 40117b700f723a27b90989a429ceb66c0873b161)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 10 ++----
|
||||
libcxx/src/filesystem/posix_compat.h | 54 ++++++++++++++++++++++++++++
|
||||
2 files changed, 57 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index fc18de9e5d80..47cd5e23c092 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -455,10 +455,6 @@ perms posix_get_perms(const StatT& st) noexcept {
|
||||
return static_cast<perms>(st.st_mode) & perms::mask;
|
||||
}
|
||||
|
||||
-::mode_t posix_convert_perms(perms prms) {
|
||||
- return static_cast< ::mode_t>(prms & perms::mask);
|
||||
-}
|
||||
-
|
||||
file_status create_file_status(error_code& m_ec, path const& p,
|
||||
const StatT& path_stat, error_code* ec) {
|
||||
if (ec)
|
||||
@@ -530,7 +526,7 @@ bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
|
||||
}
|
||||
|
||||
bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
|
||||
- if (::fchmod(fd.fd, st.st_mode) == -1) {
|
||||
+ if (detail::fchmod(fd.fd, st.st_mode) == -1) {
|
||||
ec = capture_errno();
|
||||
return true;
|
||||
}
|
||||
@@ -1212,11 +1208,11 @@ void __permissions(const path& p, perms prms, perm_options opts,
|
||||
else if (remove_perms)
|
||||
prms = st.permissions() & ~prms;
|
||||
}
|
||||
- const auto real_perms = detail::posix_convert_perms(prms);
|
||||
+ const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask);
|
||||
|
||||
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
|
||||
const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
|
||||
- if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
|
||||
+ if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
#else
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 1adce3a779c2..af4a3691db33 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -349,6 +349,57 @@ wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) {
|
||||
}
|
||||
return buff.release();
|
||||
}
|
||||
+
|
||||
+#define AT_FDCWD -1
|
||||
+#define AT_SYMLINK_NOFOLLOW 1
|
||||
+using ModeT = int;
|
||||
+
|
||||
+int fchmod_handle(HANDLE h, int perms) {
|
||||
+ FILE_BASIC_INFO basic;
|
||||
+ if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic)))
|
||||
+ return set_errno();
|
||||
+ DWORD orig_attributes = basic.FileAttributes;
|
||||
+ basic.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
|
||||
+ if ((perms & 0222) == 0)
|
||||
+ basic.FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
+ if (basic.FileAttributes != orig_attributes &&
|
||||
+ !SetFileInformationByHandle(h, FileBasicInfo, &basic, sizeof(basic)))
|
||||
+ return set_errno();
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int fchmodat(int fd, const wchar_t *path, int perms, int flag) {
|
||||
+ DWORD attributes = GetFileAttributesW(path);
|
||||
+ if (attributes == INVALID_FILE_ATTRIBUTES)
|
||||
+ return set_errno();
|
||||
+ if (attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
|
||||
+ !(flag & AT_SYMLINK_NOFOLLOW)) {
|
||||
+ // If the file is a symlink, and we are supposed to operate on the target
|
||||
+ // of the symlink, we need to open a handle to it, without the
|
||||
+ // FILE_FLAG_OPEN_REPARSE_POINT flag, to open the destination of the
|
||||
+ // symlink, and operate on it via the handle.
|
||||
+ detail::WinHandle h(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 0);
|
||||
+ if (!h)
|
||||
+ return set_errno();
|
||||
+ return fchmod_handle(h, perms);
|
||||
+ } else {
|
||||
+ // For a non-symlink, or if operating on the symlink itself instead of
|
||||
+ // its target, we can use SetFileAttributesW, saving a few calls.
|
||||
+ DWORD orig_attributes = attributes;
|
||||
+ attributes &= ~FILE_ATTRIBUTE_READONLY;
|
||||
+ if ((perms & 0222) == 0)
|
||||
+ attributes |= FILE_ATTRIBUTE_READONLY;
|
||||
+ if (attributes != orig_attributes && !SetFileAttributesW(path, attributes))
|
||||
+ return set_errno();
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int fchmod(int fd, int perms) {
|
||||
+ HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||
+ return fchmod_handle(h, perms);
|
||||
+}
|
||||
+
|
||||
#else
|
||||
int symlink_file(const char *oldname, const char *newname) {
|
||||
return ::symlink(oldname, newname);
|
||||
@@ -358,6 +409,8 @@ int symlink_dir(const char *oldname, const char *newname) {
|
||||
}
|
||||
using ::chdir;
|
||||
using ::close;
|
||||
+using ::fchmod;
|
||||
+using ::fchmodat;
|
||||
using ::fstat;
|
||||
using ::ftruncate;
|
||||
using ::getcwd;
|
||||
@@ -375,6 +428,7 @@ using ::truncate;
|
||||
#define O_BINARY 0
|
||||
|
||||
using StatVFS = struct statvfs;
|
||||
+using ModeT = ::mode_t;
|
||||
|
||||
#endif
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
From f28542330202fae54a6fee1bf02a311feef3f60a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 23:51:18 +0200
|
||||
Subject: [PATCH 09/25] [libcxx] Implement the read_symlink function for
|
||||
windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91172
|
||||
|
||||
(cherry picked from commit cdc60a3b9aa523b49329a7a5e4c1774d3b9e3db9)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 16 +++---
|
||||
libcxx/src/filesystem/posix_compat.h | 79 ++++++++++++++++++++++++++++
|
||||
2 files changed, 89 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 47cd5e23c092..a5463e48f4d7 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1227,21 +1227,25 @@ void __permissions(const path& p, perms prms, perm_options opts,
|
||||
path __read_symlink(const path& p, error_code* ec) {
|
||||
ErrorHandler<path> err("read_symlink", ec, &p);
|
||||
|
||||
-#ifdef PATH_MAX
|
||||
+#if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE)
|
||||
struct NullDeleter { void operator()(void*) const {} };
|
||||
+#ifdef MAX_SYMLINK_SIZE
|
||||
+ const size_t size = MAX_SYMLINK_SIZE + 1;
|
||||
+#else
|
||||
const size_t size = PATH_MAX + 1;
|
||||
- char stack_buff[size];
|
||||
- auto buff = std::unique_ptr<char[], NullDeleter>(stack_buff);
|
||||
+#endif
|
||||
+ path::value_type stack_buff[size];
|
||||
+ auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff);
|
||||
#else
|
||||
StatT sb;
|
||||
if (detail::lstat(p.c_str(), &sb) == -1) {
|
||||
return err.report(capture_errno());
|
||||
}
|
||||
const size_t size = sb.st_size + 1;
|
||||
- auto buff = unique_ptr<char[]>(new char[size]);
|
||||
+ auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]);
|
||||
#endif
|
||||
- ::ssize_t ret;
|
||||
- if ((ret = ::readlink(p.c_str(), buff.get(), size)) == -1)
|
||||
+ detail::SSizeT ret;
|
||||
+ if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1)
|
||||
return err.report(capture_errno());
|
||||
_LIBCPP_ASSERT(ret > 0, "TODO");
|
||||
if (static_cast<size_t>(ret) >= size)
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index af4a3691db33..8062bd65ce00 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -32,6 +32,7 @@
|
||||
# define NOMINMAX
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
+# include <winioctl.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/stat.h>
|
||||
@@ -39,6 +40,36 @@
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+// This struct isn't defined in the normal Windows SDK, but only in the
|
||||
+// Windows Driver Kit.
|
||||
+struct LIBCPP_REPARSE_DATA_BUFFER {
|
||||
+ unsigned long ReparseTag;
|
||||
+ unsigned short ReparseDataLength;
|
||||
+ unsigned short Reserved;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ unsigned short SubstituteNameOffset;
|
||||
+ unsigned short SubstituteNameLength;
|
||||
+ unsigned short PrintNameOffset;
|
||||
+ unsigned short PrintNameLength;
|
||||
+ unsigned long Flags;
|
||||
+ wchar_t PathBuffer[1];
|
||||
+ } SymbolicLinkReparseBuffer;
|
||||
+ struct {
|
||||
+ unsigned short SubstituteNameOffset;
|
||||
+ unsigned short SubstituteNameLength;
|
||||
+ unsigned short PrintNameOffset;
|
||||
+ unsigned short PrintNameLength;
|
||||
+ wchar_t PathBuffer[1];
|
||||
+ } MountPointReparseBuffer;
|
||||
+ struct {
|
||||
+ unsigned char DataBuffer[1];
|
||||
+ } GenericReparseBuffer;
|
||||
+ };
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
|
||||
|
||||
namespace detail {
|
||||
@@ -400,6 +431,52 @@ int fchmod(int fd, int perms) {
|
||||
return fchmod_handle(h, perms);
|
||||
}
|
||||
|
||||
+#define MAX_SYMLINK_SIZE MAXIMUM_REPARSE_DATA_BUFFER_SIZE
|
||||
+using SSizeT = ::int64_t;
|
||||
+
|
||||
+SSizeT readlink(const wchar_t *path, wchar_t *ret_buf, size_t bufsize) {
|
||||
+ uint8_t buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
+ detail::WinHandle h(path, FILE_READ_ATTRIBUTES, FILE_FLAG_OPEN_REPARSE_POINT);
|
||||
+ if (!h)
|
||||
+ return set_errno();
|
||||
+ DWORD out;
|
||||
+ if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf, sizeof(buf),
|
||||
+ &out, 0))
|
||||
+ return set_errno();
|
||||
+ const auto *reparse = reinterpret_cast<LIBCPP_REPARSE_DATA_BUFFER *>(buf);
|
||||
+ size_t path_buf_offset = offsetof(LIBCPP_REPARSE_DATA_BUFFER,
|
||||
+ SymbolicLinkReparseBuffer.PathBuffer[0]);
|
||||
+ if (out < path_buf_offset) {
|
||||
+ errno = EINVAL;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
|
||||
+ errno = EINVAL;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ const auto &symlink = reparse->SymbolicLinkReparseBuffer;
|
||||
+ unsigned short name_offset, name_length;
|
||||
+ if (symlink.PrintNameLength == 0) {
|
||||
+ name_offset = symlink.SubstituteNameOffset;
|
||||
+ name_length = symlink.SubstituteNameLength;
|
||||
+ } else {
|
||||
+ name_offset = symlink.PrintNameOffset;
|
||||
+ name_length = symlink.PrintNameLength;
|
||||
+ }
|
||||
+ // name_offset/length are expressed in bytes, not in wchar_t
|
||||
+ if (path_buf_offset + name_offset + name_length > out) {
|
||||
+ errno = EINVAL;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ if (name_length / sizeof(wchar_t) > bufsize) {
|
||||
+ errno = ENOMEM;
|
||||
+ return -1;
|
||||
+ }
|
||||
+ memcpy(ret_buf, &symlink.PathBuffer[name_offset / sizeof(wchar_t)],
|
||||
+ name_length);
|
||||
+ return name_length / sizeof(wchar_t);
|
||||
+}
|
||||
+
|
||||
#else
|
||||
int symlink_file(const char *oldname, const char *newname) {
|
||||
return ::symlink(oldname, newname);
|
||||
@@ -418,6 +495,7 @@ using ::link;
|
||||
using ::lstat;
|
||||
using ::mkdir;
|
||||
using ::open;
|
||||
+using ::readlink;
|
||||
using ::realpath;
|
||||
using ::remove;
|
||||
using ::rename;
|
||||
@@ -429,6 +507,7 @@ using ::truncate;
|
||||
|
||||
using StatVFS = struct statvfs;
|
||||
using ModeT = ::mode_t;
|
||||
+using SSizeT = ::ssize_t;
|
||||
|
||||
#endif
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
From 6f225c9fca50bda8911a4909b3cbf0eb28733384 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Fri, 30 Oct 2020 22:24:25 +0200
|
||||
Subject: [PATCH 10/25] [libcxx] Use the posix code for
|
||||
directory_entry::__do_refresh
|
||||
|
||||
This works just fine for windows, as all the functions it calls
|
||||
are implemented and wrapped for windows.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91173
|
||||
|
||||
(cherry picked from commit 4d292d531bea6f7a6021f212e59b3826bc7cd913)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 43 ----------------------------
|
||||
1 file changed, 43 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index a5463e48f4d7..dccec9378531 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1847,7 +1847,6 @@ size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) {
|
||||
// directory entry definitions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-#ifndef _LIBCPP_WIN32API
|
||||
error_code directory_entry::__do_refresh() noexcept {
|
||||
__data_.__reset();
|
||||
error_code failure_ec;
|
||||
@@ -1901,47 +1900,5 @@ error_code directory_entry::__do_refresh() noexcept {
|
||||
|
||||
return failure_ec;
|
||||
}
|
||||
-#else
|
||||
-error_code directory_entry::__do_refresh() noexcept {
|
||||
- __data_.__reset();
|
||||
- error_code failure_ec;
|
||||
-
|
||||
- file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
|
||||
- if (!status_known(st)) {
|
||||
- __data_.__reset();
|
||||
- return failure_ec;
|
||||
- }
|
||||
-
|
||||
- if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
|
||||
- __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
|
||||
- __data_.__type_ = st.type();
|
||||
- __data_.__non_sym_perms_ = st.permissions();
|
||||
- } else { // we have a symlink
|
||||
- __data_.__sym_perms_ = st.permissions();
|
||||
- // Get the information about the linked entity.
|
||||
- // Ignore errors from stat, since we don't want errors regarding symlink
|
||||
- // resolution to be reported to the user.
|
||||
- error_code ignored_ec;
|
||||
- st = _VSTD_FS::status(__p_, ignored_ec);
|
||||
-
|
||||
- __data_.__type_ = st.type();
|
||||
- __data_.__non_sym_perms_ = st.permissions();
|
||||
-
|
||||
- // If we failed to resolve the link, then only partially populate the
|
||||
- // cache.
|
||||
- if (!status_known(st)) {
|
||||
- __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
|
||||
- return error_code{};
|
||||
- }
|
||||
- __data_.__cache_type_ = directory_entry::_RefreshSymlink;
|
||||
- }
|
||||
-
|
||||
- // FIXME: This is currently broken, and the implementation only a placeholder.
|
||||
- // We need to cache last_write_time, file_size, and hard_link_count here before
|
||||
- // the implementation actually works.
|
||||
-
|
||||
- return failure_ec;
|
||||
-}
|
||||
-#endif
|
||||
|
||||
_LIBCPP_END_NAMESPACE_FILESYSTEM
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
From 3474a416fef709f218ff5897842819d379495cad Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Thu, 29 Oct 2020 12:10:26 +0200
|
||||
Subject: [PATCH 11/25] [libcxx] Implement temp_directory_path using
|
||||
GetTempPath on windows
|
||||
|
||||
This does roughly the same as the manual implementation, but checks
|
||||
a slightly different set of environment variables and has a more
|
||||
appropriate fallback if no environment variables are available
|
||||
(/tmp isn't a very useful fallback on windows).
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91175
|
||||
|
||||
(cherry picked from commit d4f4e723d0b4f09d72880f1679c02d586bf8abfa)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index dccec9378531..674f19154e6f 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1347,6 +1347,19 @@ file_status __symlink_status(const path& p, error_code* ec) {
|
||||
path __temp_directory_path(error_code* ec) {
|
||||
ErrorHandler<path> err("temp_directory_path", ec);
|
||||
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ wchar_t buf[MAX_PATH];
|
||||
+ DWORD retval = GetTempPathW(MAX_PATH, buf);
|
||||
+ if (!retval)
|
||||
+ return err.report(detail::make_windows_error(GetLastError()));
|
||||
+ if (retval > MAX_PATH)
|
||||
+ return err.report(errc::filename_too_long);
|
||||
+ // GetTempPathW returns a path with a trailing slash, which we
|
||||
+ // shouldn't include for consistency.
|
||||
+ if (buf[retval-1] == L'\\')
|
||||
+ buf[retval-1] = L'\0';
|
||||
+ path p(buf);
|
||||
+#else
|
||||
const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
|
||||
const char* ret = nullptr;
|
||||
|
||||
@@ -1357,6 +1370,7 @@ path __temp_directory_path(error_code* ec) {
|
||||
ret = "/tmp";
|
||||
|
||||
path p(ret);
|
||||
+#endif
|
||||
error_code m_ec;
|
||||
file_status st = detail::posix_stat(p, &m_ec);
|
||||
if (!status_known(st))
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
From 3f12aeb4ae3fd43d98f0c698952713d9fef7bef3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Tue, 3 Nov 2020 23:52:32 +0200
|
||||
Subject: [PATCH 12/25] [libcxx] Implement parsing of root_name for paths on
|
||||
windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91176
|
||||
|
||||
(cherry picked from commit 929f0bcc24e246ea02ab57df8009a6fd5751d45c)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 92 +++++++++++++++++++++++++---
|
||||
1 file changed, 85 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 674f19154e6f..88a039f85021 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -64,6 +64,10 @@ bool isSeparator(path::value_type C) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+bool isDriveLetter(path::value_type C) {
|
||||
+ return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z');
|
||||
+}
|
||||
+
|
||||
namespace parser {
|
||||
|
||||
using string_view_t = path::__string_view;
|
||||
@@ -120,6 +124,12 @@ public:
|
||||
|
||||
switch (State) {
|
||||
case PS_BeforeBegin: {
|
||||
+ PosPtr TkEnd = consumeRootName(Start, End);
|
||||
+ if (TkEnd)
|
||||
+ return makeState(PS_InRootName, Start, TkEnd);
|
||||
+ }
|
||||
+ _LIBCPP_FALLTHROUGH();
|
||||
+ case PS_InRootName: {
|
||||
PosPtr TkEnd = consumeSeparator(Start, End);
|
||||
if (TkEnd)
|
||||
return makeState(PS_InRootDir, Start, TkEnd);
|
||||
@@ -142,7 +152,6 @@ public:
|
||||
case PS_InTrailingSep:
|
||||
return makeState(PS_AtEnd);
|
||||
|
||||
- case PS_InRootName:
|
||||
case PS_AtEnd:
|
||||
_LIBCPP_UNREACHABLE();
|
||||
}
|
||||
@@ -160,9 +169,15 @@ public:
|
||||
if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
|
||||
if (SepEnd == REnd)
|
||||
return makeState(PS_InRootDir, Path.data(), RStart + 1);
|
||||
+ PosPtr TkStart = consumeRootName(SepEnd, REnd);
|
||||
+ if (TkStart == REnd)
|
||||
+ return makeState(PS_InRootDir, RStart, RStart + 1);
|
||||
return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
|
||||
} else {
|
||||
- PosPtr TkStart = consumeName(RStart, REnd);
|
||||
+ PosPtr TkStart = consumeRootName(RStart, REnd);
|
||||
+ if (TkStart == REnd)
|
||||
+ return makeState(PS_InRootName, TkStart + 1, RStart + 1);
|
||||
+ TkStart = consumeName(RStart, REnd);
|
||||
return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
|
||||
}
|
||||
}
|
||||
@@ -173,11 +188,17 @@ public:
|
||||
PosPtr SepEnd = consumeSeparator(RStart, REnd);
|
||||
if (SepEnd == REnd)
|
||||
return makeState(PS_InRootDir, Path.data(), RStart + 1);
|
||||
- PosPtr TkEnd = consumeName(SepEnd, REnd);
|
||||
- return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
|
||||
+ PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd);
|
||||
+ if (TkStart == REnd) {
|
||||
+ if (SepEnd)
|
||||
+ return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);
|
||||
+ return makeState(PS_InRootName, TkStart + 1, RStart + 1);
|
||||
+ }
|
||||
+ TkStart = consumeName(SepEnd, REnd);
|
||||
+ return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1);
|
||||
}
|
||||
case PS_InRootDir:
|
||||
- // return makeState(PS_InRootName, Path.data(), RStart + 1);
|
||||
+ return makeState(PS_InRootName, Path.data(), RStart + 1);
|
||||
case PS_InRootName:
|
||||
case PS_BeforeBegin:
|
||||
_LIBCPP_UNREACHABLE();
|
||||
@@ -284,7 +305,7 @@ private:
|
||||
}
|
||||
|
||||
PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
|
||||
- if (P == End || !isSeparator(*P))
|
||||
+ if (P == nullptr || P == End || !isSeparator(*P))
|
||||
return nullptr;
|
||||
const int Inc = P < End ? 1 : -1;
|
||||
P += Inc;
|
||||
@@ -293,15 +314,72 @@ private:
|
||||
return P;
|
||||
}
|
||||
|
||||
+ // Consume exactly N separators, or return nullptr.
|
||||
+ PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept {
|
||||
+ PosPtr Ret = consumeSeparator(P, End);
|
||||
+ if (Ret == nullptr)
|
||||
+ return nullptr;
|
||||
+ if (P < End) {
|
||||
+ if (Ret == P + N)
|
||||
+ return Ret;
|
||||
+ } else {
|
||||
+ if (Ret == P - N)
|
||||
+ return Ret;
|
||||
+ }
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+
|
||||
PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
|
||||
- if (P == End || isSeparator(*P))
|
||||
+ PosPtr Start = P;
|
||||
+ if (P == nullptr || P == End || isSeparator(*P))
|
||||
return nullptr;
|
||||
const int Inc = P < End ? 1 : -1;
|
||||
P += Inc;
|
||||
while (P != End && !isSeparator(*P))
|
||||
P += Inc;
|
||||
+ if (P == End && Inc < 0) {
|
||||
+ // Iterating backwards and consumed all the rest of the input.
|
||||
+ // Check if the start of the string would have been considered
|
||||
+ // a root name.
|
||||
+ PosPtr RootEnd = consumeRootName(End + 1, Start);
|
||||
+ if (RootEnd)
|
||||
+ return RootEnd - 1;
|
||||
+ }
|
||||
return P;
|
||||
}
|
||||
+
|
||||
+ PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept {
|
||||
+ if (P == End)
|
||||
+ return nullptr;
|
||||
+ if (P < End) {
|
||||
+ if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':')
|
||||
+ return nullptr;
|
||||
+ return P + 2;
|
||||
+ } else {
|
||||
+ if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':')
|
||||
+ return nullptr;
|
||||
+ return P - 2;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept {
|
||||
+ if (P == End)
|
||||
+ return nullptr;
|
||||
+ if (P < End)
|
||||
+ return consumeName(consumeNSeparators(P, End, 2), End);
|
||||
+ else
|
||||
+ return consumeNSeparators(consumeName(P, End), End, 2);
|
||||
+ }
|
||||
+
|
||||
+ PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept {
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ if (PosPtr Ret = consumeDriveLetter(P, End))
|
||||
+ return Ret;
|
||||
+ if (PosPtr Ret = consumeNetworkRoot(P, End))
|
||||
+ return Ret;
|
||||
+#endif
|
||||
+ return nullptr;
|
||||
+ }
|
||||
};
|
||||
|
||||
string_view_pair separate_filename(string_view_t const& s) {
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
From bd50990c64deae4ce6027767659c75a22822e2f5 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Sun, 1 Nov 2020 23:39:03 +0200
|
||||
Subject: [PATCH 13/25] [libcxx] Implement is_absolute properly for windows
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91177
|
||||
|
||||
(cherry picked from commit 8a783e68452f646360d9902d2c2bc0e115d7bfa9)
|
||||
---
|
||||
libcxx/include/filesystem | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
|
||||
index 92e37e183def..eecf416e851c 100644
|
||||
--- a/libcxx/include/filesystem
|
||||
+++ b/libcxx/include/filesystem
|
||||
@@ -1341,7 +1341,28 @@ public:
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY bool is_absolute() const {
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ __string_view __root_name_str = __root_name();
|
||||
+ __string_view __root_dir = __root_directory();
|
||||
+ if (__root_name_str.size() == 2 && __root_name_str[1] == ':') {
|
||||
+ // A drive letter with no root directory is relative, e.g. x:example.
|
||||
+ return !__root_dir.empty();
|
||||
+ }
|
||||
+ // If no root name, it's relative, e.g. \example is relative to the current drive
|
||||
+ if (__root_name_str.empty())
|
||||
+ return false;
|
||||
+ if (__root_name_str.size() < 3)
|
||||
+ return false;
|
||||
+ // A server root name, like \\server, is always absolute
|
||||
+ if (__root_name_str[0] != '/' && __root_name_str[0] != '\\')
|
||||
+ return false;
|
||||
+ if (__root_name_str[1] != '/' && __root_name_str[1] != '\\')
|
||||
+ return false;
|
||||
+ // Seems to be a server root name
|
||||
+ return true;
|
||||
+#else
|
||||
return has_root_directory();
|
||||
+#endif
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); }
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
From bd884f520faaa41618d6e901e1631ff02fab3044 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Wed, 4 Nov 2020 15:59:56 +0200
|
||||
Subject: [PATCH 14/25] [libcxx] Implement append and operator/ properly for
|
||||
windows
|
||||
|
||||
The root_path function has to be changed to return the parsed bit
|
||||
as-is; otherwise a path like "//net" gets a root path of "//net/", as
|
||||
the root name, "//net", gets the root directory (an empty string) appended,
|
||||
forming "//net/". (The same doesn't happen for the root dir "c:" though.)
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91178
|
||||
|
||||
(cherry picked from commit 78d693faecf98718dadfa6e39f291e5999f380c7)
|
||||
---
|
||||
libcxx/include/filesystem | 52 ++++++++++++++++---
|
||||
.../path.member/path.append.pass.cpp | 48 +++++++++++++++++
|
||||
2 files changed, 92 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
|
||||
index eecf416e851c..201cecc0e8b2 100644
|
||||
--- a/libcxx/include/filesystem
|
||||
+++ b/libcxx/include/filesystem
|
||||
@@ -1006,14 +1006,44 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
-private:
|
||||
- template <class _ECharT>
|
||||
- static bool __source_is_absolute(_ECharT __first_or_null) {
|
||||
- return __is_separator(__first_or_null);
|
||||
- }
|
||||
-
|
||||
public:
|
||||
// appends
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ path& operator/=(const path& __p) {
|
||||
+ auto __p_root_name = __p.__root_name();
|
||||
+ auto __p_root_name_size = __p_root_name.size();
|
||||
+ if (__p.is_absolute() ||
|
||||
+ (!__p_root_name.empty() && __p_root_name != root_name())) {
|
||||
+ __pn_ = __p.__pn_;
|
||||
+ return *this;
|
||||
+ }
|
||||
+ if (__p.has_root_directory()) {
|
||||
+ path __root_name_str = root_name();
|
||||
+ __pn_ = __root_name_str.native();
|
||||
+ __pn_ += __p.__pn_.substr(__p_root_name_size);
|
||||
+ return *this;
|
||||
+ }
|
||||
+ if (has_filename() || (!has_root_directory() && is_absolute()))
|
||||
+ __pn_ += preferred_separator;
|
||||
+ __pn_ += __p.__pn_.substr(__p_root_name_size);
|
||||
+ return *this;
|
||||
+ }
|
||||
+ template <class _Source>
|
||||
+ _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
|
||||
+ operator/=(const _Source& __src) {
|
||||
+ return operator/=(path(__src));
|
||||
+ }
|
||||
+
|
||||
+ template <class _Source>
|
||||
+ _EnableIfPathable<_Source> append(const _Source& __src) {
|
||||
+ return operator/=(path(__src));
|
||||
+ }
|
||||
+
|
||||
+ template <class _InputIt>
|
||||
+ path& append(_InputIt __first, _InputIt __last) {
|
||||
+ return operator/=(path(__first, __last));
|
||||
+ }
|
||||
+#else
|
||||
path& operator/=(const path& __p) {
|
||||
if (__p.is_absolute()) {
|
||||
__pn_ = __p.__pn_;
|
||||
@@ -1038,7 +1068,8 @@ public:
|
||||
_EnableIfPathable<_Source> append(const _Source& __src) {
|
||||
using _Traits = __is_pathable<_Source>;
|
||||
using _CVT = _PathCVT<_SourceChar<_Source> >;
|
||||
- if (__source_is_absolute(_Traits::__first_or_null(__src)))
|
||||
+ bool __source_is_absolute = __is_separator(_Traits::__first_or_null(__src));
|
||||
+ if (__source_is_absolute)
|
||||
__pn_.clear();
|
||||
else if (has_filename())
|
||||
__pn_ += preferred_separator;
|
||||
@@ -1051,13 +1082,14 @@ public:
|
||||
typedef typename iterator_traits<_InputIt>::value_type _ItVal;
|
||||
static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
|
||||
using _CVT = _PathCVT<_ItVal>;
|
||||
- if (__first != __last && __source_is_absolute(*__first))
|
||||
+ if (__first != __last && __is_separator(*__first))
|
||||
__pn_.clear();
|
||||
else if (has_filename())
|
||||
__pn_ += preferred_separator;
|
||||
_CVT::__append_range(__pn_, __first, __last);
|
||||
return *this;
|
||||
}
|
||||
+#endif
|
||||
|
||||
// concatenation
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -1295,7 +1327,11 @@ public:
|
||||
return string_type(__root_directory());
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY path root_path() const {
|
||||
+#if defined(_LIBCPP_WIN32API)
|
||||
+ return string_type(__root_path_raw());
|
||||
+#else
|
||||
return root_name().append(string_type(__root_directory()));
|
||||
+#endif
|
||||
}
|
||||
_LIBCPP_INLINE_VISIBILITY path relative_path() const {
|
||||
return string_type(__relative_path());
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
index eabd6f92da3c..ad9d06eb9849 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
@@ -63,6 +63,54 @@ const AppendOperatorTestcase Cases[] =
|
||||
, {S("/p1"), S("/p2/"), S("/p2/")}
|
||||
, {S("p1"), S(""), S("p1/")}
|
||||
, {S("p1/"), S(""), S("p1/")}
|
||||
+
|
||||
+ , {S("//host"), S("foo"), S("//host/foo")}
|
||||
+ , {S("//host/"), S("foo"), S("//host/foo")}
|
||||
+ , {S("//host"), S(""), S("//host/")}
|
||||
+
|
||||
+#ifdef _WIN32
|
||||
+ , {S("foo"), S("C:/bar"), S("C:/bar")}
|
||||
+ , {S("foo"), S("C:"), S("C:")}
|
||||
+
|
||||
+ , {S("C:"), S(""), S("C:")}
|
||||
+ , {S("C:foo"), S("/bar"), S("C:/bar")}
|
||||
+ , {S("C:foo"), S("bar"), S("C:foo/bar")}
|
||||
+ , {S("C:/foo"), S("bar"), S("C:/foo/bar")}
|
||||
+ , {S("C:/foo"), S("/bar"), S("C:/bar")}
|
||||
+
|
||||
+ , {S("C:foo"), S("C:/bar"), S("C:/bar")}
|
||||
+ , {S("C:foo"), S("C:bar"), S("C:foo/bar")}
|
||||
+ , {S("C:/foo"), S("C:/bar"), S("C:/bar")}
|
||||
+ , {S("C:/foo"), S("C:bar"), S("C:/foo/bar")}
|
||||
+
|
||||
+ , {S("C:foo"), S("c:/bar"), S("c:/bar")}
|
||||
+ , {S("C:foo"), S("c:bar"), S("c:bar")}
|
||||
+ , {S("C:/foo"), S("c:/bar"), S("c:/bar")}
|
||||
+ , {S("C:/foo"), S("c:bar"), S("c:bar")}
|
||||
+
|
||||
+ , {S("C:/foo"), S("D:bar"), S("D:bar")}
|
||||
+#else
|
||||
+ , {S("foo"), S("C:/bar"), S("foo/C:/bar")}
|
||||
+ , {S("foo"), S("C:"), S("foo/C:")}
|
||||
+
|
||||
+ , {S("C:"), S(""), S("C:/")}
|
||||
+ , {S("C:foo"), S("/bar"), S("/bar")}
|
||||
+ , {S("C:foo"), S("bar"), S("C:foo/bar")}
|
||||
+ , {S("C:/foo"), S("bar"), S("C:/foo/bar")}
|
||||
+ , {S("C:/foo"), S("/bar"), S("/bar")}
|
||||
+
|
||||
+ , {S("C:foo"), S("C:/bar"), S("C:foo/C:/bar")}
|
||||
+ , {S("C:foo"), S("C:bar"), S("C:foo/C:bar")}
|
||||
+ , {S("C:/foo"), S("C:/bar"), S("C:/foo/C:/bar")}
|
||||
+ , {S("C:/foo"), S("C:bar"), S("C:/foo/C:bar")}
|
||||
+
|
||||
+ , {S("C:foo"), S("c:/bar"), S("C:foo/c:/bar")}
|
||||
+ , {S("C:foo"), S("c:bar"), S("C:foo/c:bar")}
|
||||
+ , {S("C:/foo"), S("c:/bar"), S("C:/foo/c:/bar")}
|
||||
+ , {S("C:/foo"), S("c:bar"), S("C:/foo/c:bar")}
|
||||
+
|
||||
+ , {S("C:/foo"), S("D:bar"), S("C:/foo/D:bar")}
|
||||
+#endif
|
||||
};
|
||||
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
From 6131abb23fc2990f9a869ef3d9c63bb0fd5ff464 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Thu, 5 Nov 2020 23:09:15 +0200
|
||||
Subject: [PATCH 15/25] [libcxx] Have lexically_normal return the path with
|
||||
preferred separators
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91179
|
||||
|
||||
(cherry picked from commit 513463fd266f059864ce3c0236494cced5de0f56)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 88a039f85021..a3b93b594a07 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1719,6 +1719,7 @@ path path::lexically_normal() const {
|
||||
if (NeedTrailingSep)
|
||||
Result /= PS("");
|
||||
|
||||
+ Result.make_preferred();
|
||||
return Result;
|
||||
}
|
||||
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
From 415ea201cb19775f253dfb0cf8dc561891cff02d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Mon, 9 Nov 2020 11:45:13 +0200
|
||||
Subject: [PATCH 16/25] [libcxx] Make generic_*string return paths with forward
|
||||
slashes on windows
|
||||
|
||||
This matches what MS STL returns; in std::filesystem, forward slashes
|
||||
are considered generic dir separators that are valid on all platforms.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D91181
|
||||
|
||||
(cherry picked from commit f4f5fb915104887fefa602cfcbd1d4fc8447d46b)
|
||||
---
|
||||
libcxx/include/filesystem | 22 ++++++++++++++++---
|
||||
.../path.generic.obs/named_overloads.pass.cpp | 15 +++++++++----
|
||||
2 files changed, 30 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
|
||||
index 201cecc0e8b2..19efca2d8fc2 100644
|
||||
--- a/libcxx/include/filesystem
|
||||
+++ b/libcxx/include/filesystem
|
||||
@@ -1193,7 +1193,12 @@ public:
|
||||
#if defined(_LIBCPP_WIN32API)
|
||||
_LIBCPP_INLINE_VISIBILITY _VSTD::wstring wstring() const { return __pn_; }
|
||||
|
||||
- _VSTD::wstring generic_wstring() const { return __pn_; }
|
||||
+ _VSTD::wstring generic_wstring() const {
|
||||
+ _VSTD::wstring __s;
|
||||
+ __s.resize(__pn_.size());
|
||||
+ _VSTD::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/');
|
||||
+ return __s;
|
||||
+ }
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
||||
template <class _ECharT, class _Traits = char_traits<_ECharT>,
|
||||
@@ -1230,13 +1235,24 @@ public:
|
||||
class _Allocator = allocator<_ECharT> >
|
||||
basic_string<_ECharT, _Traits, _Allocator>
|
||||
generic_string(const _Allocator& __a = _Allocator()) const {
|
||||
- return string<_ECharT, _Traits, _Allocator>(__a);
|
||||
+ using _Str = basic_string<_ECharT, _Traits, _Allocator>;
|
||||
+ _Str __s = string<_ECharT, _Traits, _Allocator>(__a);
|
||||
+ // Note: This (and generic_u8string below) is slightly suboptimal as
|
||||
+ // it iterates twice over the string; once to convert it to the right
|
||||
+ // character type, and once to replace path delimiters.
|
||||
+ _VSTD::replace(__s.begin(), __s.end(),
|
||||
+ static_cast<_ECharT>('\\'), static_cast<_ECharT>('/'));
|
||||
+ return __s;
|
||||
}
|
||||
|
||||
_VSTD::string generic_string() const { return generic_string<char>(); }
|
||||
_VSTD::u16string generic_u16string() const { return generic_string<char16_t>(); }
|
||||
_VSTD::u32string generic_u32string() const { return generic_string<char32_t>(); }
|
||||
- __u8_string generic_u8string() const { return u8string(); }
|
||||
+ __u8_string generic_u8string() const {
|
||||
+ __u8_string __s = u8string();
|
||||
+ _VSTD::replace(__s.begin(), __s.end(), '\\', '/');
|
||||
+ return __s;
|
||||
+ }
|
||||
#endif /* !_LIBCPP_HAS_NO_LOCALIZATION */
|
||||
#else /* _LIBCPP_WIN32API */
|
||||
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
|
||||
index 58c07e2feb70..d8991592efcf 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp
|
||||
@@ -32,17 +32,24 @@
|
||||
#include "min_allocator.h"
|
||||
#include "filesystem_test_helper.h"
|
||||
|
||||
-MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
+MultiStringType input = MKSTR("c:\\foo\\bar");
|
||||
+#ifdef _WIN32
|
||||
+// On windows, the generic_* accessors return a path with forward slashes
|
||||
+MultiStringType ref = MKSTR("c:/foo/bar");
|
||||
+#else
|
||||
+// On posix, the input string is returned as-is
|
||||
+MultiStringType ref = MKSTR("c:\\foo\\bar");
|
||||
+#endif
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using namespace fs;
|
||||
- auto const& MS = longString;
|
||||
- const char* value = longString;
|
||||
+ auto const& MS = ref;
|
||||
+ const char* value = input;
|
||||
const path p(value);
|
||||
{
|
||||
std::string s = p.generic_string();
|
||||
- assert(s == value);
|
||||
+ assert(s == (const char*)MS);
|
||||
}
|
||||
{
|
||||
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
From c8c08547b2d1e87391213846c7e17f5426a3dd48 Mon Sep 17 00:00:00 2001
|
||||
From: Zbigniew Sarbinowski <zibi@ca.ibm.com>
|
||||
Date: Thu, 18 Feb 2021 14:49:46 +0000
|
||||
Subject: [PATCH 17/25] [SystemZ][ZOS] Guard using declaration for ::fchmodat
|
||||
|
||||
The use of fchmodat() is beeing guarded but its using declaration is not. Let's use the same guard in both places to avoid compiler errors on platforms where `fchmodat` does not exist.
|
||||
|
||||
Reviewed By: #libc, ldionne
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D96303
|
||||
|
||||
(cherry picked from commit 25aa0d12445eed6e278489546d18fcb7a33cfaa6)
|
||||
---
|
||||
libcxx/src/filesystem/posix_compat.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
|
||||
index 8062bd65ce00..f5c8ec39df2b 100644
|
||||
--- a/libcxx/src/filesystem/posix_compat.h
|
||||
+++ b/libcxx/src/filesystem/posix_compat.h
|
||||
@@ -487,7 +487,9 @@ int symlink_dir(const char *oldname, const char *newname) {
|
||||
using ::chdir;
|
||||
using ::close;
|
||||
using ::fchmod;
|
||||
+#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
|
||||
using ::fchmodat;
|
||||
+#endif
|
||||
using ::fstat;
|
||||
using ::ftruncate;
|
||||
using ::getcwd;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
From ff2e16fe051405232fbd9a09c406767b229d27ec Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Thu, 5 Nov 2020 00:13:22 +0200
|
||||
Subject: [PATCH 18/25] [libcxx] Enable filesystem by default for mingw targets
|
||||
|
||||
This feature can be built successfully for windows now. However,
|
||||
the helper functions for __int128_t aren't available in MSVC
|
||||
configurations, so don't enable it by default there yet. (See
|
||||
https://reviews.llvm.org/D91139 for discussion on how to proceed
|
||||
with things in MSVC environments.)
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D97075
|
||||
|
||||
(cherry picked from commit 99fc4a65847a7020ae328e42a67e80cc29c1e762)
|
||||
---
|
||||
libcxx/CMakeLists.txt | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
|
||||
index 9bf1a02f0908..b8716a34a325 100644
|
||||
--- a/libcxx/CMakeLists.txt
|
||||
+++ b/libcxx/CMakeLists.txt
|
||||
@@ -90,7 +90,11 @@ option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
|
||||
option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
|
||||
option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
|
||||
set(ENABLE_FILESYSTEM_DEFAULT ON)
|
||||
-if (WIN32)
|
||||
+if (WIN32 AND NOT MINGW)
|
||||
+ # Filesystem is buildable for windows, but it requires __int128 helper
|
||||
+ # functions, that currently are provided by libgcc or compiler_rt builtins.
|
||||
+ # These are available in MinGW environments, but not currently in MSVC
|
||||
+ # environments.
|
||||
set(ENABLE_FILESYSTEM_DEFAULT OFF)
|
||||
endif()
|
||||
option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of the main libc++ library"
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From 69856f3e59b210249020504329e016c691f138e9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Fri, 18 Dec 2020 13:34:35 +0200
|
||||
Subject: [PATCH 19/25] [libcxx] Explicitly return the expected error code in
|
||||
create_directories if the parent isn't a directory
|
||||
|
||||
On windows, going ahead and actually trying to create the directory
|
||||
doesn't return an error code that maps to
|
||||
std::errc::not_a_directory in this case.
|
||||
|
||||
This fixes two cases of
|
||||
TEST_CHECK(ErrorIs(ec, std::errc::not_a_directory))
|
||||
in filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp
|
||||
for windows (in testcases added in 59c72a70121567f7aee347e96b4ac8f3cfe9f4b2).
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D97090
|
||||
|
||||
(cherry picked from commit c5e8f024dca9ddf6d14253fe2fcc5c4956de2d3c)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index a3b93b594a07..bfc6c44d4ce4 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1022,7 +1022,8 @@ bool __create_directories(const path& p, error_code* ec) {
|
||||
if (ec && *ec) {
|
||||
return false;
|
||||
}
|
||||
- }
|
||||
+ } else if (not is_directory(parent_st))
|
||||
+ return err.report(errc::not_a_directory);
|
||||
}
|
||||
return __create_directory(p, ec);
|
||||
}
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
From 6c968da9f1e9281055d31f66c292f81de204924d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Sat, 27 Feb 2021 19:12:25 +0200
|
||||
Subject: [PATCH 20/25] [libcxx] Avoid infinite recursion in
|
||||
create_directories, if the root directory doesn't exist
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D97618
|
||||
|
||||
(cherry picked from commit 99c7b532946508efcf6cd978d86ee24b2a66d096)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 2 ++
|
||||
.../create_directories.pass.cpp | 14 ++++++++++++++
|
||||
2 files changed, 16 insertions(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index bfc6c44d4ce4..7c77660538b5 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -1018,6 +1018,8 @@ bool __create_directories(const path& p, error_code* ec) {
|
||||
if (not status_known(parent_st))
|
||||
return err.report(m_ec);
|
||||
if (not exists(parent_st)) {
|
||||
+ if (parent == p)
|
||||
+ return err.report(errc::invalid_argument);
|
||||
__create_directories(parent, ec);
|
||||
if (ec && *ec) {
|
||||
return false;
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp
|
||||
index 9ce450a0e48d..54820cad0f55 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp
|
||||
@@ -138,4 +138,18 @@ TEST_CASE(dest_final_part_is_file)
|
||||
TEST_CHECK(!exists(dir));
|
||||
}
|
||||
|
||||
+#ifdef _WIN32
|
||||
+TEST_CASE(nonexistent_root)
|
||||
+{
|
||||
+ std::error_code ec = GetTestEC();
|
||||
+ // If Q:\ doesn't exist, create_directories would try to recurse upwards
|
||||
+ // to parent_path() until it finds a directory that does exist. As the
|
||||
+ // whole path is the root name, parent_path() returns itself, and it
|
||||
+ // would recurse indefinitely, unless the recursion is broken.
|
||||
+ if (!exists("Q:\\"))
|
||||
+ TEST_CHECK(fs::create_directories("Q:\\", ec) == false);
|
||||
+ TEST_CHECK(fs::create_directories("\\\\nonexistentserver", ec) == false);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
TEST_SUITE_END()
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
From cd87c3f6b36fd6cd991b8e3a3ac85dc208d55ea1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Sat, 27 Feb 2021 16:09:49 +0200
|
||||
Subject: [PATCH 21/25] [libcxx] Map ERROR_BAD_PATHNAME to
|
||||
errc::no_such_file_or_directory on windows
|
||||
|
||||
Opening a path like \\server (without a trailing share name and
|
||||
path) produces this error, while opening e.g. \\server\share
|
||||
(for a nonexistent server/share) produces ERROR_BAD_NETPATH (which
|
||||
already is mapped).
|
||||
|
||||
This happens in some testcases (in fs.op.proximate); as proximate()
|
||||
calls weakly_canonical() on the inputs, weakly_canonical() checks
|
||||
whether the path exists or not. When the error code wasn't recognized
|
||||
(it mapped to errc::invalid_argument), the stat operation wasn't
|
||||
conclusive and weakly_canonical() errored out. With the proper error
|
||||
code mapping, this isn't considered an error, just a nonexistent
|
||||
path, and weakly_canonical() can proceed.
|
||||
|
||||
This roughly matches what MS STL does - it doesn't have
|
||||
ERROR_BAD_PATHNAME in its error code mapping table, but it
|
||||
checks for this error code specifically in the return of their
|
||||
correspondence of the stat function.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D97619
|
||||
|
||||
(cherry picked from commit 29012ce986fcb24175f19317b4e2d119cd8cdbb2)
|
||||
---
|
||||
libcxx/src/filesystem/operations.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 7c77660538b5..360643d4c241 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -411,6 +411,7 @@ errc __win_err_to_errc(int err) {
|
||||
{ERROR_ACCESS_DENIED, errc::permission_denied},
|
||||
{ERROR_ALREADY_EXISTS, errc::file_exists},
|
||||
{ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
|
||||
+ {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
|
||||
{ERROR_BAD_UNIT, errc::no_such_device},
|
||||
{ERROR_BROKEN_PIPE, errc::broken_pipe},
|
||||
{ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
From 497842a9ebb0ca1a6f871a07c0f4b4f1c700a798 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Thu, 11 Mar 2021 13:06:08 +0200
|
||||
Subject: [PATCH 22/25] [libcxx] Avoid intermediate string objects for
|
||||
substrings in windows operator/=
|
||||
|
||||
Check that appends with a path object doesn't do allocations, even
|
||||
on windows.
|
||||
|
||||
Suggested by Marek in D98398. The patch might apply without D98398
|
||||
(depending on how much of the diff context has to match), but doesn't
|
||||
make much sense until after that patch has landed.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D98412
|
||||
|
||||
(cherry picked from commit 49173ca4db21e4d1576c2440b79ebff48c6c4156)
|
||||
---
|
||||
libcxx/include/filesystem | 4 ++--
|
||||
.../class.path/path.member/path.append.pass.cpp | 9 +++++++++
|
||||
2 files changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
|
||||
index 19efca2d8fc2..2fc110715559 100644
|
||||
--- a/libcxx/include/filesystem
|
||||
+++ b/libcxx/include/filesystem
|
||||
@@ -1020,12 +1020,12 @@ public:
|
||||
if (__p.has_root_directory()) {
|
||||
path __root_name_str = root_name();
|
||||
__pn_ = __root_name_str.native();
|
||||
- __pn_ += __p.__pn_.substr(__p_root_name_size);
|
||||
+ __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);
|
||||
return *this;
|
||||
}
|
||||
if (has_filename() || (!has_root_directory() && is_absolute()))
|
||||
__pn_ += preferred_separator;
|
||||
- __pn_ += __p.__pn_.substr(__p_root_name_size);
|
||||
+ __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);
|
||||
return *this;
|
||||
}
|
||||
template <class _Source>
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
index ad9d06eb9849..834d5e999abb 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
|
||||
@@ -189,6 +189,15 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
|
||||
}
|
||||
assert(PathEq(LHS, E));
|
||||
}
|
||||
+ {
|
||||
+ path LHS(L); PathReserve(LHS, ReserveSize);
|
||||
+ path RHS(R);
|
||||
+ {
|
||||
+ DisableAllocationGuard g;
|
||||
+ LHS /= RHS;
|
||||
+ }
|
||||
+ assert(PathEq(LHS, E));
|
||||
+ }
|
||||
// input iterator - For non-native char types, appends needs to copy the
|
||||
// iterator range into a contiguous block of memory before it can perform the
|
||||
// code_cvt conversions.
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
From 9a1bb266e38b31c78de03abc2d41cdd3245595d0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Mon, 8 Mar 2021 12:03:30 +0200
|
||||
Subject: [PATCH 23/25] [libcxx] Test accessing a directory on windows that
|
||||
gives "access denied" errors
|
||||
|
||||
Fix handling of skip_permission_denied on windows; after converting
|
||||
the return value of GetLastError() to a standard error_code, ec.value()
|
||||
is in the standard errc range, not a native windows error code. This
|
||||
was missed in 156180727d6c347eda3ba749730707acb8a48093.
|
||||
|
||||
The directory "C:\System Volume Information" does seem to exist and
|
||||
have these properties on most relevant contempory setups.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D98166
|
||||
|
||||
(cherry picked from commit e69c65d5c45557e140b13237448581d28bbd5846)
|
||||
---
|
||||
libcxx/src/filesystem/directory_iterator.cpp | 3 ++-
|
||||
.../directory_entry.cons/path.pass.cpp | 18 +++++++++++++
|
||||
.../directory_iterator.members/ctor.pass.cpp | 8 ++++++
|
||||
.../rec.dir.itr.members/ctor.pass.cpp | 8 ++++++
|
||||
.../fs.op.funcs/fs.op.exists/exists.pass.cpp | 14 ++++++++---
|
||||
libcxx/test/support/filesystem_test_helper.h | 25 +++++++++++++++++++
|
||||
6 files changed, 72 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp
|
||||
index 2721dea5c98f..bb3653076bfc 100644
|
||||
--- a/libcxx/src/filesystem/directory_iterator.cpp
|
||||
+++ b/libcxx/src/filesystem/directory_iterator.cpp
|
||||
@@ -124,7 +124,8 @@ public:
|
||||
ec = detail::make_windows_error(GetLastError());
|
||||
const bool ignore_permission_denied =
|
||||
bool(opts & directory_options::skip_permission_denied);
|
||||
- if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
|
||||
+ if (ignore_permission_denied &&
|
||||
+ ec.value() == static_cast<int>(errc::permission_denied))
|
||||
ec.clear();
|
||||
return;
|
||||
}
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp
|
||||
index e3759e22b0ba..a118fae4d54b 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp
|
||||
@@ -148,6 +148,23 @@ TEST_CASE(path_ctor_dne) {
|
||||
|
||||
TEST_CASE(path_ctor_cannot_resolve) {
|
||||
using namespace fs;
|
||||
+#ifdef _WIN32
|
||||
+ // Windows doesn't support setting perms::none to trigger failures
|
||||
+ // reading directories; test using a special inaccessible directory
|
||||
+ // instead.
|
||||
+ const path dir = GetWindowsInaccessibleDir();
|
||||
+ TEST_REQUIRE(!dir.empty());
|
||||
+ const path file = dir / "file";
|
||||
+ {
|
||||
+ std::error_code ec = GetTestEC();
|
||||
+ directory_entry ent(file, ec);
|
||||
+ TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
|
||||
+ TEST_CHECK(ent.path() == file);
|
||||
+ }
|
||||
+ {
|
||||
+ TEST_CHECK_NO_THROW(directory_entry(file));
|
||||
+ }
|
||||
+#else
|
||||
scoped_test_env env;
|
||||
const path dir = env.create_dir("dir");
|
||||
const path file = env.create_file("dir/file", 42);
|
||||
@@ -179,6 +196,7 @@ TEST_CASE(path_ctor_cannot_resolve) {
|
||||
TEST_CHECK_NO_THROW(directory_entry(sym_in_dir));
|
||||
TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir));
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
TEST_SUITE_END()
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp
|
||||
index 48cf72a77b05..fae696613c75 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp
|
||||
@@ -87,6 +87,13 @@ TEST_CASE(test_construction_from_bad_path)
|
||||
TEST_CASE(access_denied_test_case)
|
||||
{
|
||||
using namespace fs;
|
||||
+#ifdef _WIN32
|
||||
+ // Windows doesn't support setting perms::none to trigger failures
|
||||
+ // reading directories; test using a special inaccessible directory
|
||||
+ // instead.
|
||||
+ const path testDir = GetWindowsInaccessibleDir();
|
||||
+ TEST_REQUIRE(!testDir.empty());
|
||||
+#else
|
||||
scoped_test_env env;
|
||||
path const testDir = env.make_env_path("dir1");
|
||||
path const testFile = testDir / "testFile";
|
||||
@@ -100,6 +107,7 @@ TEST_CASE(access_denied_test_case)
|
||||
}
|
||||
// Change the permissions so we can no longer iterate
|
||||
permissions(testDir, perms::none);
|
||||
+#endif
|
||||
|
||||
// Check that the construction fails when skip_permissions_denied is
|
||||
// not given.
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp
|
||||
index ddffaca39335..53ca5737ba31 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp
|
||||
@@ -88,6 +88,13 @@ TEST_CASE(test_construction_from_bad_path)
|
||||
TEST_CASE(access_denied_test_case)
|
||||
{
|
||||
using namespace fs;
|
||||
+#ifdef _WIN32
|
||||
+ // Windows doesn't support setting perms::none to trigger failures
|
||||
+ // reading directories; test using a special inaccessible directory
|
||||
+ // instead.
|
||||
+ const path testDir = GetWindowsInaccessibleDir();
|
||||
+ TEST_REQUIRE(!testDir.empty());
|
||||
+#else
|
||||
scoped_test_env env;
|
||||
path const testDir = env.make_env_path("dir1");
|
||||
path const testFile = testDir / "testFile";
|
||||
@@ -102,6 +109,7 @@ TEST_CASE(access_denied_test_case)
|
||||
|
||||
// Change the permissions so we can no longer iterate
|
||||
permissions(testDir, perms::none);
|
||||
+#endif
|
||||
|
||||
// Check that the construction fails when skip_permissions_denied is
|
||||
// not given.
|
||||
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp
|
||||
index 581d9fe041a9..1b7131bbadff 100644
|
||||
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp
|
||||
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp
|
||||
@@ -73,16 +73,24 @@ TEST_CASE(test_exist_not_found)
|
||||
|
||||
TEST_CASE(test_exists_fails)
|
||||
{
|
||||
+#ifdef _WIN32
|
||||
+ // Windows doesn't support setting perms::none to trigger failures
|
||||
+ // reading directories; test using a special inaccessible directory
|
||||
+ // instead.
|
||||
+ const path p = GetWindowsInaccessibleDir();
|
||||
+ TEST_REQUIRE(!p.empty());
|
||||
+#else
|
||||
scoped_test_env env;
|
||||
const path dir = env.create_dir("dir");
|
||||
- const path file = env.create_file("dir/file", 42);
|
||||
+ const path p = env.create_file("dir/file", 42);
|
||||
permissions(dir, perms::none);
|
||||
+#endif
|
||||
|
||||
std::error_code ec;
|
||||
- TEST_CHECK(exists(file, ec) == false);
|
||||
+ TEST_CHECK(exists(p, ec) == false);
|
||||
TEST_CHECK(ec);
|
||||
|
||||
- TEST_CHECK_THROW(filesystem_error, exists(file));
|
||||
+ TEST_CHECK_THROW(filesystem_error, exists(p));
|
||||
}
|
||||
|
||||
TEST_CASE(test_name_too_long) {
|
||||
diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
|
||||
index eeee3e935b8a..92c017f610fe 100644
|
||||
--- a/libcxx/test/support/filesystem_test_helper.h
|
||||
+++ b/libcxx/test/support/filesystem_test_helper.h
|
||||
@@ -690,4 +690,29 @@ struct ExceptionChecker {
|
||||
|
||||
};
|
||||
|
||||
+inline fs::path GetWindowsInaccessibleDir() {
|
||||
+ // Only makes sense on windows, but the code can be compiled for
|
||||
+ // any platform.
|
||||
+ const fs::path dir("C:\\System Volume Information");
|
||||
+ std::error_code ec;
|
||||
+ const fs::path root("C:\\");
|
||||
+ fs::directory_iterator it(root, ec);
|
||||
+ if (ec)
|
||||
+ return fs::path();
|
||||
+ const fs::directory_iterator endIt{};
|
||||
+ while (it != endIt) {
|
||||
+ const fs::directory_entry &ent = *it;
|
||||
+ if (ent == dir) {
|
||||
+ // Basic sanity checks on the directory_entry
|
||||
+ if (!ent.exists())
|
||||
+ return fs::path();
|
||||
+ if (!ent.is_directory())
|
||||
+ return fs::path();
|
||||
+ return ent;
|
||||
+ }
|
||||
+ ++it;
|
||||
+ }
|
||||
+ return fs::path();
|
||||
+}
|
||||
+
|
||||
#endif /* FILESYSTEM_TEST_HELPER_HPP */
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
From 7a94808f488301270f4a55ff7a17a8ebff3d388c Mon Sep 17 00:00:00 2001
|
||||
From: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
|
||||
Date: Fri, 5 Mar 2021 20:13:35 -0500
|
||||
Subject: [PATCH 24/25] [libc++] Improve src/filesystem's formatting of paths.
|
||||
|
||||
This is my attempt to merge D98077 (bugfix the format strings for
|
||||
Windows paths, which use wchar_t not char)
|
||||
and D96986 (replace C++ variadic templates with C-style varargs so that
|
||||
`__attribute__((format(printf)))` can be applied, for better safety)
|
||||
and D98065 (remove an unused function overload).
|
||||
|
||||
The one intentional functional change here is in `__create_what`.
|
||||
It now prints path1 and path2 in square-brackets _and_ double-quotes,
|
||||
rather than just square-brackets. Prior to this patch, it would
|
||||
print either path double-quoted if-and-only-if it was the empty
|
||||
string. Now the double-quotes are always present. I doubt anybody's
|
||||
code is relying on the current format, right?
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D98097
|
||||
---
|
||||
libcxx/include/__config | 7 +
|
||||
libcxx/src/filesystem/directory_iterator.cpp | 7 +-
|
||||
libcxx/src/filesystem/filesystem_common.h | 146 ++++++++++---------
|
||||
libcxx/src/filesystem/operations.cpp | 25 ++--
|
||||
libcxx/test/support/filesystem_test_helper.h | 4 +-
|
||||
5 files changed, 101 insertions(+), 88 deletions(-)
|
||||
|
||||
diff --git a/libcxx/include/__config b/libcxx/include/__config
|
||||
index a3838c89e8e1..89838ca76c8c 100644
|
||||
--- a/libcxx/include/__config
|
||||
+++ b/libcxx/include/__config
|
||||
@@ -1445,6 +1445,13 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
|
||||
# define _LIBCPP_INIT_PRIORITY_MAX
|
||||
#endif
|
||||
|
||||
+#if defined(__GNUC__) || defined(__clang__)
|
||||
+#define _LIBCPP_FORMAT_PRINTF(a, b) \
|
||||
+ __attribute__((__format__(__printf__, a, b)))
|
||||
+#else
|
||||
+#define _LIBCPP_FORMAT_PRINTF(a, b)
|
||||
+#endif
|
||||
+
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _LIBCPP_CONFIG
|
||||
diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp
|
||||
index bb3653076bfc..7b83ba9ff123 100644
|
||||
--- a/libcxx/src/filesystem/directory_iterator.cpp
|
||||
+++ b/libcxx/src/filesystem/directory_iterator.cpp
|
||||
@@ -273,7 +273,7 @@ directory_iterator& directory_iterator::__increment(error_code* ec) {
|
||||
path root = move(__imp_->__root_);
|
||||
__imp_.reset();
|
||||
if (m_ec)
|
||||
- err.report(m_ec, "at root \"%s\"", root);
|
||||
+ err.report(m_ec, "at root " PATH_CSTR_FMT, root.c_str());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ void recursive_directory_iterator::__advance(error_code* ec) {
|
||||
if (m_ec) {
|
||||
path root = move(stack.top().__root_);
|
||||
__imp_.reset();
|
||||
- err.report(m_ec, "at root \"%s\"", root);
|
||||
+ err.report(m_ec, "at root " PATH_CSTR_FMT, root.c_str());
|
||||
} else {
|
||||
__imp_.reset();
|
||||
}
|
||||
@@ -405,7 +405,8 @@ bool recursive_directory_iterator::__try_recursion(error_code* ec) {
|
||||
} else {
|
||||
path at_ent = move(curr_it.__entry_.__p_);
|
||||
__imp_.reset();
|
||||
- err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
|
||||
+ err.report(m_ec, "attempting recursion into " PATH_CSTR_FMT,
|
||||
+ at_ent.c_str());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h
|
||||
index a4505171c3eb..df50a7de1059 100644
|
||||
--- a/libcxx/src/filesystem/filesystem_common.h
|
||||
+++ b/libcxx/src/filesystem/filesystem_common.h
|
||||
@@ -42,8 +42,10 @@
|
||||
|
||||
#if defined(_LIBCPP_WIN32API)
|
||||
#define PS(x) (L##x)
|
||||
+#define PATH_CSTR_FMT "\"%ls\""
|
||||
#else
|
||||
#define PS(x) (x)
|
||||
+#define PATH_CSTR_FMT "\"%s\""
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
|
||||
@@ -57,68 +59,47 @@ errc __win_err_to_errc(int err);
|
||||
|
||||
namespace {
|
||||
|
||||
-static string format_string_imp(const char* msg, ...) {
|
||||
- // we might need a second shot at this, so pre-emptivly make a copy
|
||||
- struct GuardVAList {
|
||||
- va_list& target;
|
||||
- bool active = true;
|
||||
- GuardVAList(va_list& tgt) : target(tgt), active(true) {}
|
||||
- void clear() {
|
||||
- if (active)
|
||||
- va_end(target);
|
||||
- active = false;
|
||||
- }
|
||||
- ~GuardVAList() {
|
||||
- if (active)
|
||||
- va_end(target);
|
||||
- }
|
||||
- };
|
||||
- va_list args;
|
||||
- va_start(args, msg);
|
||||
- GuardVAList args_guard(args);
|
||||
-
|
||||
- va_list args_cp;
|
||||
- va_copy(args_cp, args);
|
||||
- GuardVAList args_copy_guard(args_cp);
|
||||
-
|
||||
- std::string result;
|
||||
-
|
||||
- array<char, 256> local_buff;
|
||||
- size_t size_with_null = local_buff.size();
|
||||
- auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
|
||||
-
|
||||
- args_copy_guard.clear();
|
||||
-
|
||||
- // handle empty expansion
|
||||
- if (ret == 0)
|
||||
- return result;
|
||||
- if (static_cast<size_t>(ret) < size_with_null) {
|
||||
- result.assign(local_buff.data(), static_cast<size_t>(ret));
|
||||
- return result;
|
||||
+static _LIBCPP_FORMAT_PRINTF(1, 0) string
|
||||
+format_string_impl(const char* msg, va_list ap) {
|
||||
+ array<char, 256> buf;
|
||||
+
|
||||
+ va_list apcopy;
|
||||
+ va_copy(apcopy, ap);
|
||||
+ int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy);
|
||||
+ va_end(apcopy);
|
||||
+
|
||||
+ string result;
|
||||
+ if (static_cast<size_t>(ret) < buf.size()) {
|
||||
+ result.assign(buf.data(), static_cast<size_t>(ret));
|
||||
+ } else {
|
||||
+ // we did not provide a long enough buffer on our first attempt. The
|
||||
+ // return value is the number of bytes (excluding the null byte) that are
|
||||
+ // needed for formatting.
|
||||
+ size_t size_with_null = static_cast<size_t>(ret) + 1;
|
||||
+ result.__resize_default_init(size_with_null - 1);
|
||||
+ ret = ::vsnprintf(&result[0], size_with_null, msg, ap);
|
||||
+ _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
|
||||
}
|
||||
-
|
||||
- // we did not provide a long enough buffer on our first attempt. The
|
||||
- // return value is the number of bytes (excluding the null byte) that are
|
||||
- // needed for formatting.
|
||||
- size_with_null = static_cast<size_t>(ret) + 1;
|
||||
- result.__resize_default_init(size_with_null - 1);
|
||||
- ret = ::vsnprintf(&result[0], size_with_null, msg, args);
|
||||
- _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
|
||||
-
|
||||
return result;
|
||||
}
|
||||
|
||||
-const path::value_type* unwrap(path::string_type const& s) { return s.c_str(); }
|
||||
-const path::value_type* unwrap(path const& p) { return p.native().c_str(); }
|
||||
-template <class Arg>
|
||||
-Arg const& unwrap(Arg const& a) {
|
||||
- static_assert(!is_class<Arg>::value, "cannot pass class here");
|
||||
- return a;
|
||||
-}
|
||||
-
|
||||
-template <class... Args>
|
||||
-string format_string(const char* fmt, Args const&... args) {
|
||||
- return format_string_imp(fmt, unwrap(args)...);
|
||||
+static _LIBCPP_FORMAT_PRINTF(1, 2) string
|
||||
+format_string(const char* msg, ...) {
|
||||
+ string ret;
|
||||
+ va_list ap;
|
||||
+ va_start(ap, msg);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ try {
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ ret = format_string_impl(msg, ap);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ } catch (...) {
|
||||
+ va_end(ap);
|
||||
+ throw;
|
||||
+ }
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ va_end(ap);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
error_code capture_errno() {
|
||||
@@ -190,14 +171,14 @@ struct ErrorHandler {
|
||||
_LIBCPP_UNREACHABLE();
|
||||
}
|
||||
|
||||
- template <class... Args>
|
||||
- T report(const error_code& ec, const char* msg, Args const&... args) const {
|
||||
+ _LIBCPP_FORMAT_PRINTF(3, 0)
|
||||
+ void report_impl(const error_code& ec, const char* msg, va_list ap) const {
|
||||
if (ec_) {
|
||||
*ec_ = ec;
|
||||
- return error_value<T>();
|
||||
+ return;
|
||||
}
|
||||
string what =
|
||||
- string("in ") + func_name_ + ": " + format_string(msg, args...);
|
||||
+ string("in ") + func_name_ + ": " + format_string_impl(msg, ap);
|
||||
switch (bool(p1_) + bool(p2_)) {
|
||||
case 0:
|
||||
__throw_filesystem_error(what, ec);
|
||||
@@ -209,11 +190,44 @@ struct ErrorHandler {
|
||||
_LIBCPP_UNREACHABLE();
|
||||
}
|
||||
|
||||
- T report(errc const& err) const { return report(make_error_code(err)); }
|
||||
+ _LIBCPP_FORMAT_PRINTF(3, 4)
|
||||
+ T report(const error_code& ec, const char* msg, ...) const {
|
||||
+ va_list ap;
|
||||
+ va_start(ap, msg);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ try {
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ report_impl(ec, msg, ap);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ } catch (...) {
|
||||
+ va_end(ap);
|
||||
+ throw;
|
||||
+ }
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ va_end(ap);
|
||||
+ return error_value<T>();
|
||||
+ }
|
||||
+
|
||||
+ T report(errc const& err) const {
|
||||
+ return report(make_error_code(err));
|
||||
+ }
|
||||
|
||||
- template <class... Args>
|
||||
- T report(errc const& err, const char* msg, Args const&... args) const {
|
||||
- return report(make_error_code(err), msg, args...);
|
||||
+ _LIBCPP_FORMAT_PRINTF(3, 4)
|
||||
+ T report(errc const& err, const char* msg, ...) const {
|
||||
+ va_list ap;
|
||||
+ va_start(ap, msg);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ try {
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ report_impl(make_error_code(err), msg, ap);
|
||||
+#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
+ } catch (...) {
|
||||
+ va_end(ap);
|
||||
+ throw;
|
||||
+ }
|
||||
+#endif // _LIBCPP_NO_EXCEPTIONS
|
||||
+ va_end(ap);
|
||||
+ return error_value<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
|
||||
index 360643d4c241..0cc4bad34c72 100644
|
||||
--- a/libcxx/src/filesystem/operations.cpp
|
||||
+++ b/libcxx/src/filesystem/operations.cpp
|
||||
@@ -666,27 +666,20 @@ _FilesystemClock::time_point _FilesystemClock::now() noexcept {
|
||||
|
||||
filesystem_error::~filesystem_error() {}
|
||||
|
||||
-#if defined(_LIBCPP_WIN32API)
|
||||
-#define PS_FMT "%ls"
|
||||
-#else
|
||||
-#define PS_FMT "%s"
|
||||
-#endif
|
||||
-
|
||||
void filesystem_error::__create_what(int __num_paths) {
|
||||
const char* derived_what = system_error::what();
|
||||
__storage_->__what_ = [&]() -> string {
|
||||
- const path::value_type* p1 = path1().native().empty() ? PS("\"\"") : path1().c_str();
|
||||
- const path::value_type* p2 = path2().native().empty() ? PS("\"\"") : path2().c_str();
|
||||
switch (__num_paths) {
|
||||
- default:
|
||||
+ case 0:
|
||||
return detail::format_string("filesystem error: %s", derived_what);
|
||||
case 1:
|
||||
- return detail::format_string("filesystem error: %s [" PS_FMT "]", derived_what,
|
||||
- p1);
|
||||
+ return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "]",
|
||||
+ derived_what, path1().c_str());
|
||||
case 2:
|
||||
- return detail::format_string("filesystem error: %s [" PS_FMT "] [" PS_FMT "]",
|
||||
- derived_what, p1, p2);
|
||||
+ return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "] [" PATH_CSTR_FMT "]",
|
||||
+ derived_what, path1().c_str(), path2().c_str());
|
||||
}
|
||||
+ _LIBCPP_UNREACHABLE();
|
||||
}();
|
||||
}
|
||||
|
||||
@@ -1456,11 +1449,11 @@ path __temp_directory_path(error_code* ec) {
|
||||
error_code m_ec;
|
||||
file_status st = detail::posix_stat(p, &m_ec);
|
||||
if (!status_known(st))
|
||||
- return err.report(m_ec, "cannot access path \"" PS_FMT "\"", p);
|
||||
+ return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str());
|
||||
|
||||
if (!exists(st) || !is_directory(st))
|
||||
- return err.report(errc::not_a_directory, "path \"" PS_FMT "\" is not a directory",
|
||||
- p);
|
||||
+ return err.report(errc::not_a_directory,
|
||||
+ "path " PATH_CSTR_FMT " is not a directory", p.c_str());
|
||||
|
||||
return p;
|
||||
}
|
||||
diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
|
||||
index 92c017f610fe..9d4062a987eb 100644
|
||||
--- a/libcxx/test/support/filesystem_test_helper.h
|
||||
+++ b/libcxx/test/support/filesystem_test_helper.h
|
||||
@@ -653,9 +653,7 @@ struct ExceptionChecker {
|
||||
additional_msg = opt_message + ": ";
|
||||
}
|
||||
auto transform_path = [](const fs::path& p) {
|
||||
- if (p.native().empty())
|
||||
- return std::string("\"\"");
|
||||
- return p.string();
|
||||
+ return "\"" + p.string() + "\"";
|
||||
};
|
||||
std::string format = [&]() -> std::string {
|
||||
switch (num_paths) {
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
From 138e1609764e2226938df8cd6176303b41e4f325 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Tue, 18 May 2021 14:45:08 +0000
|
||||
Subject: [PATCH 25/25] [libcxx] Make the visibility attributes consistent for
|
||||
__narrow_to_utf8/__widen_from_utf8
|
||||
|
||||
Use the same visiblity attributes as for all other template
|
||||
specializations in the same file; declare the specialization itself
|
||||
using _LIBCPP_TYPE_VIS, and don't use _LIBCPP_EXPORTED_FROM_ABI on
|
||||
the destructor. Methods that are excluded from the ABI are marked
|
||||
with _LIBCPP_INLINE_VISIBILITY.
|
||||
|
||||
This makes the vtable exported from DLL builds of libc++. Practically,
|
||||
it doesn't make any difference for the CI configuration, but it
|
||||
can make a difference in mingw setups.
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D102717
|
||||
|
||||
(cherry picked from commit 3a6be27978aa3e83e9dc2ff2402b2569ce0686fd)
|
||||
---
|
||||
libcxx/include/__locale | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
|
||||
index 77e5faab2676..c2800e88e8d2 100644
|
||||
--- a/libcxx/include/__locale
|
||||
+++ b/libcxx/include/__locale
|
||||
@@ -1484,14 +1484,14 @@ struct __narrow_to_utf8<8>
|
||||
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
template <>
|
||||
-struct _LIBCPP_TEMPLATE_VIS __narrow_to_utf8<16>
|
||||
+struct _LIBCPP_TYPE_VIS __narrow_to_utf8<16>
|
||||
: public codecvt<char16_t, char, mbstate_t>
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__narrow_to_utf8() : codecvt<char16_t, char, mbstate_t>(1) {}
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
- _LIBCPP_EXPORTED_FROM_ABI ~__narrow_to_utf8();
|
||||
+ ~__narrow_to_utf8();
|
||||
|
||||
template <class _OutputIterator, class _CharT>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -1520,14 +1520,14 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
template <>
|
||||
-struct _LIBCPP_TEMPLATE_VIS __narrow_to_utf8<32>
|
||||
+struct _LIBCPP_TYPE_VIS __narrow_to_utf8<32>
|
||||
: public codecvt<char32_t, char, mbstate_t>
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__narrow_to_utf8() : codecvt<char32_t, char, mbstate_t>(1) {}
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
- _LIBCPP_EXPORTED_FROM_ABI ~__narrow_to_utf8();
|
||||
+ ~__narrow_to_utf8();
|
||||
|
||||
template <class _OutputIterator, class _CharT>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -1578,14 +1578,14 @@ struct __widen_from_utf8<8>
|
||||
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
template <>
|
||||
-struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<16>
|
||||
+struct _LIBCPP_TYPE_VIS __widen_from_utf8<16>
|
||||
: public codecvt<char16_t, char, mbstate_t>
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__widen_from_utf8() : codecvt<char16_t, char, mbstate_t>(1) {}
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
- _LIBCPP_EXPORTED_FROM_ABI ~__widen_from_utf8();
|
||||
+ ~__widen_from_utf8();
|
||||
|
||||
template <class _OutputIterator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
@@ -1614,14 +1614,14 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
template <>
|
||||
-struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<32>
|
||||
+struct _LIBCPP_TYPE_VIS __widen_from_utf8<32>
|
||||
: public codecvt<char32_t, char, mbstate_t>
|
||||
{
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
__widen_from_utf8() : codecvt<char32_t, char, mbstate_t>(1) {}
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
|
||||
- _LIBCPP_EXPORTED_FROM_ABI ~__widen_from_utf8();
|
||||
+ ~__widen_from_utf8();
|
||||
|
||||
template <class _OutputIterator>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
--
|
||||
2.25.1
|
||||
|
||||
Reference in new issue
Block a user