Implement <filesystem>
This patch implements the <filesystem> header and uses that
to provide <experimental/filesystem>.
Unlike other standard headers, the symbols needed for <filesystem>
have not yet been placed in libc++.so. Instead they live in the
new libc++fs.a library. Users of filesystem are required to link this
library. (Also note that libc++experimental no longer contains the
definition of <experimental/filesystem>, which now requires linking libc++fs).
The reason for keeping <filesystem> out of the dylib for now is that
it's still somewhat experimental, and the possibility of requiring an
ABI breaking change is very real. In the future the symbols will likely
be moved into the dylib, or the dylib will be made to link libc++fs automagically).
Note that moving the symbols out of libc++experimental may break user builds
until they update to -lc++fs. This should be OK, because the experimental
library provides no stability guarantees. However, I plan on looking into
ways we can force libc++experimental to automagically link libc++fs.
In order to use a single implementation and set of tests for <filesystem>, it
has been placed in a special `__fs` namespace. This namespace is inline in
C++17 onward, but not before that. As such implementation is available
in C++11 onward, but no filesystem namespace is present "directly", and
as such name conflicts shouldn't occur in C++11 or C++14.
llvm-svn: 338093
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 998a5c88312066fcc2b2de1358edc76587611354
diff --git a/src/experimental/filesystem/directory_iterator.cpp b/src/experimental/filesystem/directory_iterator.cpp
deleted file mode 100644
index 7a1ab25..0000000
--- a/src/experimental/filesystem/directory_iterator.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-//===------------------ directory_iterator.cpp ----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "experimental/filesystem"
-#include "__config"
-#if defined(_LIBCPP_WIN32API)
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
-#else
-#include <dirent.h>
-#endif
-#include <errno.h>
-
-#include "filesystem_common.h"
-
-_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
-
-namespace detail {
-namespace {
-
-#if !defined(_LIBCPP_WIN32API)
-template <class DirEntT, class = decltype(DirEntT::d_type)>
-static file_type get_file_type(DirEntT *ent, int) {
- switch (ent->d_type) {
- case DT_BLK:
- return file_type::block;
- case DT_CHR:
- return file_type::character;
- case DT_DIR:
- return file_type::directory;
- case DT_FIFO:
- return file_type::fifo;
- case DT_LNK:
- return file_type::symlink;
- case DT_REG:
- return file_type::regular;
- case DT_SOCK:
- return file_type::socket;
- // Unlike in lstat, hitting "unknown" here simply means that the underlying
- // filesystem doesn't support d_type. Report is as 'none' so we correctly
- // set the cache to empty.
- case DT_UNKNOWN:
- break;
- }
- return file_type::none;
-}
-
-template <class DirEntT>
-static file_type get_file_type(DirEntT *ent, long) {
- return file_type::none;
-}
-
-static pair<string_view, file_type>
-posix_readdir(DIR *dir_stream, error_code& ec) {
- struct dirent* dir_entry_ptr = nullptr;
- errno = 0; // zero errno in order to detect errors
- ec.clear();
- if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
- if (errno)
- ec = capture_errno();
- return {};
- } else {
- return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
- }
-}
-#else
-
-static file_type get_file_type(const WIN32_FIND_DATA& data) {
- //auto attrs = data.dwFileAttributes;
- // FIXME(EricWF)
- return file_type::unknown;
-}
-static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
- return (data.nFileSizeHight * (MAXDWORD+1)) + data.nFileSizeLow;
-}
-static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
- ULARGE_INTEGER tmp;
- FILETIME& time = data.ftLastWriteTime;
- tmp.u.LowPart = time.dwLowDateTime;
- tmp.u.HighPart = time.dwHighDateTime;
- return file_time_type(file_time_type::duration(time.QuadPart));
-}
-
-#endif
-
-} // namespace
-} // namespace detail
-
-using detail::ErrorHandler;
-
-#if defined(_LIBCPP_WIN32API)
-class __dir_stream {
-public:
-
- __dir_stream() = delete;
- __dir_stream& operator=(const __dir_stream&) = delete;
-
- __dir_stream(__dir_stream&& __ds) noexcept
- : __stream_(__ds.__stream_), __root_(move(__ds.__root_)),
- __entry_(move(__ds.__entry_)) {
- __ds.__stream_ = INVALID_HANDLE_VALUE;
- }
-
- __dir_stream(const path& root, directory_options opts, error_code& ec)
- : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
- __stream_ = ::FindFirstFileEx(root.c_str(), &__data_);
- if (__stream_ == INVALID_HANDLE_VALUE) {
- ec = error_code(::GetLastError(), generic_category());
- const bool ignore_permission_denied =
- bool(opts & directory_options::skip_permission_denied);
- if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
- ec.clear();
- return;
- }
- }
-
- ~__dir_stream() noexcept {
- if (__stream_ == INVALID_HANDLE_VALUE)
- return;
- close();
- }
-
- bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
-
- bool advance(error_code& ec) {
- while (::FindNextFile(__stream_, &__data_)) {
- if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
- continue;
- // FIXME: Cache more of this
- //directory_entry::__cached_data cdata;
- //cdata.__type_ = get_file_type(__data_);
- //cdata.__size_ = get_file_size(__data_);
- //cdata.__write_time_ = get_write_time(__data_);
- __entry_.__assign_iter_entry(
- __root_ / __data_.cFileName,
- directory_entry::__create_iter_result(get_file_type(__data)));
- return true;
- }
- ec = error_code(::GetLastError(), generic_category());
- close();
- return false;
- }
-
-private:
- error_code close() noexcept {
- error_code ec;
- if (!::FindClose(__stream_))
- ec = error_code(::GetLastError(), generic_category());
- __stream_ = INVALID_HANDLE_VALUE;
- return ec;
- }
-
- HANDLE __stream_{INVALID_HANDLE_VALUE};
- WIN32_FIND_DATA __data_;
-
-public:
- path __root_;
- directory_entry __entry_;
-};
-#else
-class __dir_stream {
-public:
- __dir_stream() = delete;
- __dir_stream& operator=(const __dir_stream&) = delete;
-
- __dir_stream(__dir_stream&& other) noexcept
- : __stream_(other.__stream_), __root_(move(other.__root_)),
- __entry_(move(other.__entry_))
- {
- other.__stream_ = nullptr;
- }
-
-
- __dir_stream(const path& root, directory_options opts, error_code& ec)
- : __stream_(nullptr),
- __root_(root)
- {
- if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
- ec = detail::capture_errno();
- const bool allow_eacess =
- bool(opts & directory_options::skip_permission_denied);
- if (allow_eacess && ec.value() == EACCES)
- ec.clear();
- return;
- }
- advance(ec);
- }
-
- ~__dir_stream() noexcept
- { if (__stream_) close(); }
-
- bool good() const noexcept { return __stream_ != nullptr; }
-
- bool advance(error_code &ec) {
- while (true) {
- auto str_type_pair = detail::posix_readdir(__stream_, ec);
- auto& str = str_type_pair.first;
- if (str == "." || str == "..") {
- continue;
- } else if (ec || str.empty()) {
- close();
- return false;
- } else {
- __entry_.__assign_iter_entry(
- __root_ / str,
- directory_entry::__create_iter_result(str_type_pair.second));
- return true;
- }
- }
- }
-private:
- error_code close() noexcept {
- error_code m_ec;
- if (::closedir(__stream_) == -1)
- m_ec = detail::capture_errno();
- __stream_ = nullptr;
- return m_ec;
- }
-
- DIR * __stream_{nullptr};
-public:
- path __root_;
- directory_entry __entry_;
-};
-#endif
-
-// directory_iterator
-
-directory_iterator::directory_iterator(const path& p, error_code *ec,
- directory_options opts)
-{
- ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
-
- error_code m_ec;
- __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
- if (ec)
- *ec = m_ec;
- if (!__imp_->good()) {
- __imp_.reset();
- if (m_ec)
- err.report(m_ec);
- }
-}
-
-directory_iterator& directory_iterator::__increment(error_code *ec)
-{
- _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
- ErrorHandler<void> err("directory_iterator::operator++()", ec);
-
- error_code m_ec;
- if (!__imp_->advance(m_ec)) {
- path root = move(__imp_->__root_);
- __imp_.reset();
- if (m_ec)
- err.report(m_ec, "at root \"%s\"", root);
- }
- return *this;
-
-}
-
-directory_entry const& directory_iterator::__dereference() const {
- _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
- return __imp_->__entry_;
-}
-
-// recursive_directory_iterator
-
-struct recursive_directory_iterator::__shared_imp {
- stack<__dir_stream> __stack_;
- directory_options __options_;
-};
-
-recursive_directory_iterator::recursive_directory_iterator(const path& p,
- directory_options opt, error_code *ec)
- : __imp_(nullptr), __rec_(true)
-{
- ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
-
- error_code m_ec;
- __dir_stream new_s(p, opt, m_ec);
- if (m_ec)
- err.report(m_ec);
- if (m_ec || !new_s.good())
- return;
-
- __imp_ = make_shared<__shared_imp>();
- __imp_->__options_ = opt;
- __imp_->__stack_.push(move(new_s));
-}
-
-void recursive_directory_iterator::__pop(error_code* ec)
-{
- _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
- if (ec) ec->clear();
- __imp_->__stack_.pop();
- if (__imp_->__stack_.size() == 0)
- __imp_.reset();
- else
- __advance(ec);
-}
-
-directory_options recursive_directory_iterator::options() const {
- return __imp_->__options_;
-}
-
-int recursive_directory_iterator::depth() const {
- return __imp_->__stack_.size() - 1;
-}
-
-const directory_entry& recursive_directory_iterator::__dereference() const {
- return __imp_->__stack_.top().__entry_;
-}
-
-recursive_directory_iterator&
-recursive_directory_iterator::__increment(error_code *ec)
-{
- if (ec) ec->clear();
- if (recursion_pending()) {
- if (__try_recursion(ec) || (ec && *ec))
- return *this;
- }
- __rec_ = true;
- __advance(ec);
- return *this;
-}
-
-void recursive_directory_iterator::__advance(error_code* ec) {
- ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
-
- const directory_iterator end_it;
- auto& stack = __imp_->__stack_;
- error_code m_ec;
- while (stack.size() > 0) {
- if (stack.top().advance(m_ec))
- return;
- if (m_ec)
- break;
- stack.pop();
- }
-
- if (m_ec) {
- path root = move(stack.top().__root_);
- __imp_.reset();
- err.report(m_ec, "at root \"%s\"", root);
- } else {
- __imp_.reset();
- }
-}
-
-bool recursive_directory_iterator::__try_recursion(error_code *ec) {
- ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
-
- bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
-
- auto& curr_it = __imp_->__stack_.top();
-
- bool skip_rec = false;
- error_code m_ec;
- if (!rec_sym) {
- file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || is_symlink(st) || !is_directory(st))
- skip_rec = true;
- } else {
- file_status st(curr_it.__entry_.__get_ft(&m_ec));
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || !is_directory(st))
- skip_rec = true;
- }
-
- if (!skip_rec) {
- __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
- if (new_it.good()) {
- __imp_->__stack_.push(move(new_it));
- return true;
- }
- }
- if (m_ec) {
- const bool allow_eacess = bool(__imp_->__options_
- & directory_options::skip_permission_denied);
- if (m_ec.value() == EACCES && allow_eacess) {
- if (ec) ec->clear();
- } else {
- path at_ent = move(curr_it.__entry_.__p_);
- __imp_.reset();
- err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
- }
- }
- return false;
-}
-
-
-_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
diff --git a/src/filesystem/directory_iterator.cpp b/src/filesystem/directory_iterator.cpp
new file mode 100644
index 0000000..f0d807a
--- /dev/null
+++ b/src/filesystem/directory_iterator.cpp
@@ -0,0 +1,396 @@
+//===------------------ directory_iterator.cpp ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "filesystem"
+#include "__config"
+#if defined(_LIBCPP_WIN32API)
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#else
+#include <dirent.h>
+#endif
+#include <errno.h>
+
+#include "filesystem_common.h"
+
+_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
+
+namespace detail {
+namespace {
+
+#if !defined(_LIBCPP_WIN32API)
+template <class DirEntT, class = decltype(DirEntT::d_type)>
+static file_type get_file_type(DirEntT* ent, int) {
+ switch (ent->d_type) {
+ case DT_BLK:
+ return file_type::block;
+ case DT_CHR:
+ return file_type::character;
+ case DT_DIR:
+ return file_type::directory;
+ case DT_FIFO:
+ return file_type::fifo;
+ case DT_LNK:
+ return file_type::symlink;
+ case DT_REG:
+ return file_type::regular;
+ case DT_SOCK:
+ return file_type::socket;
+ // Unlike in lstat, hitting "unknown" here simply means that the underlying
+ // filesystem doesn't support d_type. Report is as 'none' so we correctly
+ // set the cache to empty.
+ case DT_UNKNOWN:
+ break;
+ }
+ return file_type::none;
+}
+
+template <class DirEntT>
+static file_type get_file_type(DirEntT* ent, long) {
+ return file_type::none;
+}
+
+static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
+ error_code& ec) {
+ struct dirent* dir_entry_ptr = nullptr;
+ errno = 0; // zero errno in order to detect errors
+ ec.clear();
+ if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
+ if (errno)
+ ec = capture_errno();
+ return {};
+ } else {
+ return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
+ }
+}
+#else
+
+static file_type get_file_type(const WIN32_FIND_DATA& data) {
+ //auto attrs = data.dwFileAttributes;
+ // FIXME(EricWF)
+ return file_type::unknown;
+}
+static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
+ return (data.nFileSizeHight * (MAXDWORD + 1)) + data.nFileSizeLow;
+}
+static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
+ ULARGE_INTEGER tmp;
+ FILETIME& time = data.ftLastWriteTime;
+ tmp.u.LowPart = time.dwLowDateTime;
+ tmp.u.HighPart = time.dwHighDateTime;
+ return file_time_type(file_time_type::duration(time.QuadPart));
+}
+
+#endif
+
+} // namespace
+} // namespace detail
+
+using detail::ErrorHandler;
+
+#if defined(_LIBCPP_WIN32API)
+class __dir_stream {
+public:
+ __dir_stream() = delete;
+ __dir_stream& operator=(const __dir_stream&) = delete;
+
+ __dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_),
+ __root_(move(__ds.__root_)),
+ __entry_(move(__ds.__entry_)) {
+ __ds.__stream_ = INVALID_HANDLE_VALUE;
+ }
+
+ __dir_stream(const path& root, directory_options opts, error_code& ec)
+ : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
+ __stream_ = ::FindFirstFileEx(root.c_str(), &__data_);
+ if (__stream_ == INVALID_HANDLE_VALUE) {
+ ec = error_code(::GetLastError(), generic_category());
+ const bool ignore_permission_denied =
+ bool(opts & directory_options::skip_permission_denied);
+ if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
+ ec.clear();
+ return;
+ }
+ }
+
+ ~__dir_stream() noexcept {
+ if (__stream_ == INVALID_HANDLE_VALUE)
+ return;
+ close();
+ }
+
+ bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
+
+ bool advance(error_code& ec) {
+ while (::FindNextFile(__stream_, &__data_)) {
+ if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
+ continue;
+ // FIXME: Cache more of this
+ //directory_entry::__cached_data cdata;
+ //cdata.__type_ = get_file_type(__data_);
+ //cdata.__size_ = get_file_size(__data_);
+ //cdata.__write_time_ = get_write_time(__data_);
+ __entry_.__assign_iter_entry(
+ __root_ / __data_.cFileName,
+ directory_entry::__create_iter_result(get_file_type(__data)));
+ return true;
+ }
+ ec = error_code(::GetLastError(), generic_category());
+ close();
+ return false;
+ }
+
+private:
+ error_code close() noexcept {
+ error_code ec;
+ if (!::FindClose(__stream_))
+ ec = error_code(::GetLastError(), generic_category());
+ __stream_ = INVALID_HANDLE_VALUE;
+ return ec;
+ }
+
+ HANDLE __stream_{INVALID_HANDLE_VALUE};
+ WIN32_FIND_DATA __data_;
+
+public:
+ path __root_;
+ directory_entry __entry_;
+};
+#else
+class __dir_stream {
+public:
+ __dir_stream() = delete;
+ __dir_stream& operator=(const __dir_stream&) = delete;
+
+ __dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_),
+ __root_(move(other.__root_)),
+ __entry_(move(other.__entry_)) {
+ other.__stream_ = nullptr;
+ }
+
+ __dir_stream(const path& root, directory_options opts, error_code& ec)
+ : __stream_(nullptr), __root_(root) {
+ if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
+ ec = detail::capture_errno();
+ const bool allow_eacess =
+ bool(opts & directory_options::skip_permission_denied);
+ if (allow_eacess && ec.value() == EACCES)
+ ec.clear();
+ return;
+ }
+ advance(ec);
+ }
+
+ ~__dir_stream() noexcept {
+ if (__stream_)
+ close();
+ }
+
+ bool good() const noexcept { return __stream_ != nullptr; }
+
+ bool advance(error_code& ec) {
+ while (true) {
+ auto str_type_pair = detail::posix_readdir(__stream_, ec);
+ auto& str = str_type_pair.first;
+ if (str == "." || str == "..") {
+ continue;
+ } else if (ec || str.empty()) {
+ close();
+ return false;
+ } else {
+ __entry_.__assign_iter_entry(
+ __root_ / str,
+ directory_entry::__create_iter_result(str_type_pair.second));
+ return true;
+ }
+ }
+ }
+
+private:
+ error_code close() noexcept {
+ error_code m_ec;
+ if (::closedir(__stream_) == -1)
+ m_ec = detail::capture_errno();
+ __stream_ = nullptr;
+ return m_ec;
+ }
+
+ DIR* __stream_{nullptr};
+
+public:
+ path __root_;
+ directory_entry __entry_;
+};
+#endif
+
+// directory_iterator
+
+directory_iterator::directory_iterator(const path& p, error_code* ec,
+ directory_options opts) {
+ ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
+
+ error_code m_ec;
+ __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
+ if (ec)
+ *ec = m_ec;
+ if (!__imp_->good()) {
+ __imp_.reset();
+ if (m_ec)
+ err.report(m_ec);
+ }
+}
+
+directory_iterator& directory_iterator::__increment(error_code* ec) {
+ _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
+ ErrorHandler<void> err("directory_iterator::operator++()", ec);
+
+ error_code m_ec;
+ if (!__imp_->advance(m_ec)) {
+ path root = move(__imp_->__root_);
+ __imp_.reset();
+ if (m_ec)
+ err.report(m_ec, "at root \"%s\"", root);
+ }
+ return *this;
+}
+
+directory_entry const& directory_iterator::__dereference() const {
+ _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
+ return __imp_->__entry_;
+}
+
+// recursive_directory_iterator
+
+struct recursive_directory_iterator::__shared_imp {
+ stack<__dir_stream> __stack_;
+ directory_options __options_;
+};
+
+recursive_directory_iterator::recursive_directory_iterator(
+ const path& p, directory_options opt, error_code* ec)
+ : __imp_(nullptr), __rec_(true) {
+ ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
+
+ error_code m_ec;
+ __dir_stream new_s(p, opt, m_ec);
+ if (m_ec)
+ err.report(m_ec);
+ if (m_ec || !new_s.good())
+ return;
+
+ __imp_ = make_shared<__shared_imp>();
+ __imp_->__options_ = opt;
+ __imp_->__stack_.push(move(new_s));
+}
+
+void recursive_directory_iterator::__pop(error_code* ec) {
+ _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
+ if (ec)
+ ec->clear();
+ __imp_->__stack_.pop();
+ if (__imp_->__stack_.size() == 0)
+ __imp_.reset();
+ else
+ __advance(ec);
+}
+
+directory_options recursive_directory_iterator::options() const {
+ return __imp_->__options_;
+}
+
+int recursive_directory_iterator::depth() const {
+ return __imp_->__stack_.size() - 1;
+}
+
+const directory_entry& recursive_directory_iterator::__dereference() const {
+ return __imp_->__stack_.top().__entry_;
+}
+
+recursive_directory_iterator&
+recursive_directory_iterator::__increment(error_code* ec) {
+ if (ec)
+ ec->clear();
+ if (recursion_pending()) {
+ if (__try_recursion(ec) || (ec && *ec))
+ return *this;
+ }
+ __rec_ = true;
+ __advance(ec);
+ return *this;
+}
+
+void recursive_directory_iterator::__advance(error_code* ec) {
+ ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
+
+ const directory_iterator end_it;
+ auto& stack = __imp_->__stack_;
+ error_code m_ec;
+ while (stack.size() > 0) {
+ if (stack.top().advance(m_ec))
+ return;
+ if (m_ec)
+ break;
+ stack.pop();
+ }
+
+ if (m_ec) {
+ path root = move(stack.top().__root_);
+ __imp_.reset();
+ err.report(m_ec, "at root \"%s\"", root);
+ } else {
+ __imp_.reset();
+ }
+}
+
+bool recursive_directory_iterator::__try_recursion(error_code* ec) {
+ ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
+
+ bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
+
+ auto& curr_it = __imp_->__stack_.top();
+
+ bool skip_rec = false;
+ error_code m_ec;
+ if (!rec_sym) {
+ file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
+ if (m_ec && status_known(st))
+ m_ec.clear();
+ if (m_ec || is_symlink(st) || !is_directory(st))
+ skip_rec = true;
+ } else {
+ file_status st(curr_it.__entry_.__get_ft(&m_ec));
+ if (m_ec && status_known(st))
+ m_ec.clear();
+ if (m_ec || !is_directory(st))
+ skip_rec = true;
+ }
+
+ if (!skip_rec) {
+ __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
+ if (new_it.good()) {
+ __imp_->__stack_.push(move(new_it));
+ return true;
+ }
+ }
+ if (m_ec) {
+ const bool allow_eacess =
+ bool(__imp_->__options_ & directory_options::skip_permission_denied);
+ if (m_ec.value() == EACCES && allow_eacess) {
+ if (ec)
+ ec->clear();
+ } else {
+ path at_ent = move(curr_it.__entry_.__p_);
+ __imp_.reset();
+ err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
+ }
+ }
+ return false;
+}
+
+_LIBCPP_END_NAMESPACE_FILESYSTEM
diff --git a/src/experimental/filesystem/filesystem_common.h b/src/filesystem/filesystem_common.h
similarity index 95%
rename from src/experimental/filesystem/filesystem_common.h
rename to src/filesystem/filesystem_common.h
index 94f4d41..ed92877 100644
--- a/src/experimental/filesystem/filesystem_common.h
+++ b/src/filesystem/filesystem_common.h
@@ -10,7 +10,8 @@
#ifndef FILESYSTEM_COMMON_H
#define FILESYSTEM_COMMON_H
-#include "experimental/__config"
+#include "__config"
+#include "filesystem"
#include "array"
#include "chrono"
#include "cstdlib"
@@ -20,11 +21,9 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/time.h> // for ::utimes as used in __last_write_time
-#include <fcntl.h> /* values for fchmodat */
+#include <fcntl.h> /* values for fchmodat */
-#include <experimental/filesystem>
-
-#include "../../include/apple_availability.h"
+#include "../include/apple_availability.h"
#if !defined(__APPLE__)
// We can use the presence of UTIME_OMIT to detect platforms that provide
@@ -39,7 +38,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
-_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
namespace detail {
namespace {
@@ -49,7 +48,7 @@
struct GuardVAList {
va_list& target;
bool active = true;
- GuardVAList(va_list &target) : target(target), active(true) {}
+ GuardVAList(va_list& target) : target(target), active(true) {}
void clear() {
if (active)
va_end(target);
@@ -386,10 +385,10 @@
// to use it.
bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
- error_code& ec) {
+ error_code& ec) {
using namespace chrono;
auto Convert = [](long nsec) {
- using int_type = decltype(std::declval<::timeval>().tv_usec);
+ using int_type = decltype(std::declval< ::timeval>().tv_usec);
auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
return static_cast<int_type>(dur);
};
@@ -404,9 +403,8 @@
#if defined(_LIBCPP_USE_UTIMENSAT)
bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
- error_code& ec) {
- if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1)
- {
+ error_code& ec) {
+ if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
ec = capture_errno();
return true;
}
@@ -423,10 +421,9 @@
#endif
}
-
} // namespace
} // end namespace detail
-_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+_LIBCPP_END_NAMESPACE_FILESYSTEM
#endif // FILESYSTEM_COMMON_H
diff --git a/src/experimental/filesystem/int128_builtins.cpp b/src/filesystem/int128_builtins.cpp
similarity index 97%
rename from src/experimental/filesystem/int128_builtins.cpp
rename to src/filesystem/int128_builtins.cpp
index d8f2abb..66adbdd 100644
--- a/src/experimental/filesystem/int128_builtins.cpp
+++ b/src/filesystem/int128_builtins.cpp
@@ -17,7 +17,7 @@
#include "__config"
#include "climits"
-#ifndef _LIBCPP_HAS_NO_INT128
+#if !defined(_LIBCPP_HAS_NO_INT128)
extern "C" __attribute__((no_sanitize("undefined")))
__int128_t __muloti4(__int128_t a, __int128_t b, int* overflow) {
diff --git a/src/experimental/filesystem/operations.cpp b/src/filesystem/operations.cpp
similarity index 76%
rename from src/experimental/filesystem/operations.cpp
rename to src/filesystem/operations.cpp
index 775c178..65a4b31 100644
--- a/src/experimental/filesystem/operations.cpp
+++ b/src/filesystem/operations.cpp
@@ -7,11 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "experimental/filesystem"
+#include "filesystem"
#include "array"
#include "iterator"
#include "fstream"
-#include "random" /* for unique_path */
+#include "random" /* for unique_path */
#include "string_view"
#include "type_traits"
#include "vector"
@@ -24,17 +24,17 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <time.h>
-#include <fcntl.h> /* values for fchmodat */
+#include <fcntl.h> /* values for fchmodat */
#if defined(__linux__)
-# include <linux/version.h>
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
-# include <sys/sendfile.h>
-# define _LIBCPP_USE_SENDFILE
-# endif
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
+#include <sys/sendfile.h>
+#define _LIBCPP_USE_SENDFILE
+#endif
#elif defined(__APPLE__) || __has_include(<copyfile.h>)
#include <copyfile.h>
-# define _LIBCPP_USE_COPYFILE
+#define _LIBCPP_USE_COPYFILE
#endif
#if !defined(__APPLE__)
@@ -51,10 +51,10 @@
#endif
#endif
-_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
-namespace { namespace parser
-{
+namespace {
+namespace parser {
using string_view_t = path::__string_view;
using string_view_pair = pair<string_view_t, string_view_t>;
@@ -76,8 +76,8 @@
ParserState State;
private:
- PathParser(string_view_t P, ParserState State) noexcept
- : Path(P), State(State) {}
+ PathParser(string_view_t P, ParserState State) noexcept : Path(P),
+ State(State) {}
public:
PathParser(string_view_t P, string_view_t E, unsigned char S)
@@ -157,7 +157,8 @@
}
}
case PS_InTrailingSep:
- return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, RStart + 1);
+ return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
+ RStart + 1);
case PS_InFilenames: {
PosPtr SepEnd = consumeSeparator(RStart, REnd);
if (SepEnd == REnd)
@@ -219,13 +220,9 @@
RawEntry = {};
}
- PosPtr getAfterBack() const noexcept {
- return Path.data() + Path.size();
- }
+ PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
- PosPtr getBeforeFront() const noexcept {
- return Path.data() - 1;
- }
+ PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
/// \brief Return a pointer to the first character after the currently
/// lexed element.
@@ -282,24 +279,26 @@
}
};
-string_view_pair separate_filename(string_view_t const & s) {
- if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""};
- auto pos = s.find_last_of('.');
- if (pos == string_view_t::npos || pos == 0)
- return string_view_pair{s, string_view_t{}};
- return string_view_pair{s.substr(0, pos), s.substr(pos)};
+string_view_pair separate_filename(string_view_t const& s) {
+ if (s == "." || s == ".." || s.empty())
+ return string_view_pair{s, ""};
+ auto pos = s.find_last_of('.');
+ if (pos == string_view_t::npos || pos == 0)
+ return string_view_pair{s, string_view_t{}};
+ return string_view_pair{s.substr(0, pos), s.substr(pos)};
}
string_view_t createView(PosPtr S, PosPtr E) noexcept {
return {S, static_cast<size_t>(E - S) + 1};
}
-}} // namespace parser
-
+} // namespace parser
+} // namespace
// POSIX HELPERS
-namespace detail { namespace {
+namespace detail {
+namespace {
using value_type = path::value_type;
using string_type = path::string_type;
@@ -429,8 +428,7 @@
return posix_lstat(p, path_stat, ec);
}
-bool posix_ftruncate(const FileDescriptor& fd, size_t to_size,
- error_code& ec) {
+bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, error_code& ec) {
if (::ftruncate(fd.fd, to_size) == -1) {
ec = capture_errno();
return true;
@@ -462,7 +460,8 @@
m_status = create_file_status(m_ec, name, m_stat, &ec);
return m_status;
}
-}} // end namespace detail
+} // namespace
+} // end namespace detail
using detail::capture_errno;
using detail::ErrorHandler;
@@ -511,37 +510,36 @@
}();
}
-static path __do_absolute(const path& p, path *cwd, error_code *ec) {
- if (ec) ec->clear();
- if (p.is_absolute())
- return p;
- *cwd = __current_path(ec);
- if (ec && *ec)
- return {};
- return (*cwd) / p;
+static path __do_absolute(const path& p, path* cwd, error_code* ec) {
+ if (ec)
+ ec->clear();
+ if (p.is_absolute())
+ return p;
+ *cwd = __current_path(ec);
+ if (ec && *ec)
+ return {};
+ return (*cwd) / p;
}
-path __absolute(const path& p, error_code *ec) {
- path cwd;
- return __do_absolute(p, &cwd, ec);
+path __absolute(const path& p, error_code* ec) {
+ path cwd;
+ return __do_absolute(p, &cwd, ec);
}
-path __canonical(path const & orig_p, error_code *ec)
-{
- path cwd;
- ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
+path __canonical(path const& orig_p, error_code* ec) {
+ path cwd;
+ ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
- path p = __do_absolute(orig_p, &cwd, ec);
- char buff[PATH_MAX + 1];
- char *ret;
- if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
- return err.report(capture_errno());
- return {ret};
+ path p = __do_absolute(orig_p, &cwd, ec);
+ char buff[PATH_MAX + 1];
+ char* ret;
+ if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
+ return err.report(capture_errno());
+ return {ret};
}
void __copy(const path& from, const path& to, copy_options options,
- error_code *ec)
-{
+ error_code* ec) {
ErrorHandler<void> err("copy", ec, &from, &to);
const bool sym_status = bool(
@@ -570,65 +568,65 @@
return err.report(errc::function_not_supported);
}
- if (ec) ec->clear();
+ if (ec)
+ ec->clear();
- if (is_symlink(f)) {
- if (bool(copy_options::skip_symlinks & options)) {
- // do nothing
- } else if (not exists(t)) {
- __copy_symlink(from, to, ec);
- } else {
- return err.report(errc::file_exists);
- }
- return;
+ if (is_symlink(f)) {
+ if (bool(copy_options::skip_symlinks & options)) {
+ // do nothing
+ } else if (not exists(t)) {
+ __copy_symlink(from, to, ec);
+ } else {
+ return err.report(errc::file_exists);
}
- else if (is_regular_file(f)) {
- if (bool(copy_options::directories_only & options)) {
- // do nothing
- }
- else if (bool(copy_options::create_symlinks & options)) {
- __create_symlink(from, to, ec);
- }
- else if (bool(copy_options::create_hard_links & options)) {
- __create_hard_link(from, to, ec);
- }
- else if (is_directory(t)) {
- __copy_file(from, to / from.filename(), options, ec);
- } else {
- __copy_file(from, to, options, ec);
- }
- return;
+ return;
+ } else if (is_regular_file(f)) {
+ if (bool(copy_options::directories_only & options)) {
+ // do nothing
+ } else if (bool(copy_options::create_symlinks & options)) {
+ __create_symlink(from, to, ec);
+ } else if (bool(copy_options::create_hard_links & options)) {
+ __create_hard_link(from, to, ec);
+ } else if (is_directory(t)) {
+ __copy_file(from, to / from.filename(), options, ec);
+ } else {
+ __copy_file(from, to, options, ec);
}
- else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
- return err.report(errc::is_a_directory);
- }
- else if (is_directory(f) && (bool(copy_options::recursive & options) ||
- copy_options::none == options)) {
+ return;
+ } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
+ return err.report(errc::is_a_directory);
+ } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
+ copy_options::none == options)) {
- if (!exists(t)) {
- // create directory to with attributes from 'from'.
- __create_directory(to, from, ec);
- if (ec && *ec) { return; }
- }
- directory_iterator it = ec ? directory_iterator(from, *ec)
- : directory_iterator(from);
- if (ec && *ec) { return; }
- error_code m_ec2;
- for (; it != directory_iterator(); it.increment(m_ec2)) {
- if (m_ec2) {
- return err.report(m_ec2);
- }
- __copy(it->path(), to / it->path().filename(),
- options | copy_options::__in_recursive_copy, ec);
- if (ec && *ec) { return; }
- }
+ if (!exists(t)) {
+ // create directory to with attributes from 'from'.
+ __create_directory(to, from, ec);
+ if (ec && *ec) {
+ return;
+ }
}
+ directory_iterator it =
+ ec ? directory_iterator(from, *ec) : directory_iterator(from);
+ if (ec && *ec) {
+ return;
+ }
+ error_code m_ec2;
+ for (; it != directory_iterator(); it.increment(m_ec2)) {
+ if (m_ec2) {
+ return err.report(m_ec2);
+ }
+ __copy(it->path(), to / it->path().filename(),
+ options | copy_options::__in_recursive_copy, ec);
+ if (ec && *ec) {
+ return;
+ }
+ }
+ }
}
namespace detail {
namespace {
-
#ifdef _LIBCPP_USE_SENDFILE
bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
error_code& ec) {
@@ -721,8 +719,7 @@
} // namespace detail
bool __copy_file(const path& from, const path& to, copy_options options,
- error_code *ec)
-{
+ error_code* ec) {
using detail::FileDescriptor;
ErrorHandler<bool> err("copy_file", ec, &to, &from);
@@ -811,18 +808,18 @@
}
void __copy_symlink(const path& existing_symlink, const path& new_symlink,
- error_code *ec)
-{
- const path real_path(__read_symlink(existing_symlink, ec));
- 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);
+ error_code* ec) {
+ const path real_path(__read_symlink(existing_symlink, ec));
+ 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);
}
-bool __create_directories(const path& p, error_code *ec)
-{
+bool __create_directories(const path& p, error_code* ec) {
ErrorHandler<bool> err("create_directories", ec, &p);
error_code m_ec;
@@ -846,11 +843,10 @@
}
}
}
- return __create_directory(p, ec);
+ return __create_directory(p, ec);
}
-bool __create_directory(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)
@@ -860,9 +856,7 @@
return false;
}
-bool __create_directory(path const & p, path const & attributes,
- error_code *ec)
-{
+bool __create_directory(path const& p, path const& attributes, error_code* ec) {
ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
StatT attr_stat;
@@ -871,7 +865,8 @@
if (!status_known(st))
return err.report(mec);
if (!is_directory(st))
- return err.report(errc::not_a_directory, "the specified attribute path is invalid");
+ return err.report(errc::not_a_directory,
+ "the specified attribute path is invalid");
if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
return true;
@@ -887,19 +882,19 @@
return err.report(capture_errno());
}
-void __create_hard_link(const path& from, const path& to, error_code *ec){
+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)
return err.report(capture_errno());
}
-void __create_symlink(path const & from, path const & to, error_code *ec) {
+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)
return err.report(capture_errno());
}
-path __current_path(error_code *ec) {
+path __current_path(error_code* ec) {
ErrorHandler<path> err("current_path", ec);
auto size = ::pathconf(".", _PC_PATH_MAX);
@@ -913,14 +908,13 @@
return {buff.get()};
}
-void __current_path(const path& p, 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)
err.report(capture_errno());
}
-bool __equivalent(const path& p1, const path& p2, error_code *ec)
-{
+bool __equivalent(const path& p1, const path& p2, error_code* ec) {
ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
error_code ec1, ec2;
@@ -935,9 +929,7 @@
return detail::stat_equivalent(st1, st2);
}
-
-uintmax_t __file_size(const path& p, error_code *ec)
-{
+uintmax_t __file_size(const path& p, error_code* ec) {
ErrorHandler<uintmax_t> err("file_size", ec, &p);
error_code m_ec;
@@ -950,12 +942,11 @@
m_ec = make_error_code(error_kind);
return err.report(m_ec);
}
- // is_regular_file(p) == true
- return static_cast<uintmax_t>(st.st_size);
+ // is_regular_file(p) == true
+ return static_cast<uintmax_t>(st.st_size);
}
-uintmax_t __hard_link_count(const path& p, error_code *ec)
-{
+uintmax_t __hard_link_count(const path& p, error_code* ec) {
ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
error_code m_ec;
@@ -966,9 +957,7 @@
return static_cast<uintmax_t>(st.st_nlink);
}
-
-bool __fs_is_empty(const path& p, error_code *ec)
-{
+bool __fs_is_empty(const path& p, error_code* ec) {
ErrorHandler<bool> err("is_empty", ec, &p);
error_code m_ec;
@@ -1001,52 +990,47 @@
return fs_time::convert_from_timespec(ts);
}
-file_time_type __last_write_time(const path& p, error_code *ec)
-{
- using namespace chrono;
- ErrorHandler<file_time_type> err("last_write_time", ec, &p);
+file_time_type __last_write_time(const path& p, error_code* ec) {
+ using namespace chrono;
+ ErrorHandler<file_time_type> err("last_write_time", ec, &p);
- error_code m_ec;
- StatT st;
- detail::posix_stat(p, st, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- return __extract_last_write_time(p, st, ec);
+ error_code m_ec;
+ StatT st;
+ detail::posix_stat(p, st, &m_ec);
+ if (m_ec)
+ return err.report(m_ec);
+ return __extract_last_write_time(p, st, ec);
}
-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);
+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);
- error_code m_ec;
- array<TimeSpec, 2> tbuf;
+ error_code m_ec;
+ array<TimeSpec, 2> tbuf;
#if !defined(_LIBCPP_USE_UTIMENSAT)
- // This implementation has a race condition between determining the
- // last access time and attempting to set it to the same value using
- // ::utimes
- StatT st;
- file_status fst = detail::posix_stat(p, st, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- tbuf[0] = detail::extract_atime(st);
+ // This implementation has a race condition between determining the
+ // last access time and attempting to set it to the same value using
+ // ::utimes
+ StatT st;
+ file_status fst = detail::posix_stat(p, st, &m_ec);
+ if (m_ec)
+ return err.report(m_ec);
+ tbuf[0] = detail::extract_atime(st);
#else
- tbuf[0].tv_sec = 0;
- tbuf[0].tv_nsec = UTIME_OMIT;
+ tbuf[0].tv_sec = 0;
+ tbuf[0].tv_nsec = UTIME_OMIT;
#endif
- if (!fs_time::convert_to_timespec(tbuf[1], new_time))
- return err.report(errc::value_too_large);
+ if (!fs_time::convert_to_timespec(tbuf[1], new_time))
+ return err.report(errc::value_too_large);
- detail::set_file_times(p, tbuf, m_ec);
- if (m_ec)
- return err.report(m_ec);
+ detail::set_file_times(p, tbuf, m_ec);
+ if (m_ec)
+ return err.report(m_ec);
}
-
void __permissions(const path& p, perms prms, perm_options opts,
- error_code *ec)
-{
+ error_code* ec) {
ErrorHandler<void> err("permissions", ec, &p);
auto has_opt = [&](perm_options o) { return bool(o & opts); };
@@ -1074,24 +1058,23 @@
else if (remove_perms)
prms = st.permissions() & ~prms;
}
- const auto real_perms = detail::posix_convert_perms(prms);
+ const auto real_perms = detail::posix_convert_perms(prms);
-# 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) {
- return err.report(capture_errno());
- }
-# else
- if (set_sym_perms)
- return err.report(errc::operation_not_supported);
- if (::chmod(p.c_str(), real_perms) == -1) {
- return err.report(capture_errno());
- }
-# endif
+#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) {
+ return err.report(capture_errno());
+ }
+#else
+ if (set_sym_perms)
+ return err.report(errc::operation_not_supported);
+ if (::chmod(p.c_str(), real_perms) == -1) {
+ return err.report(capture_errno());
+ }
+#endif
}
-
-path __read_symlink(const path& p, error_code *ec) {
+path __read_symlink(const path& p, error_code* ec) {
ErrorHandler<path> err("read_symlink", ec, &p);
char buff[PATH_MAX + 1];
@@ -1100,47 +1083,49 @@
if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
return err.report(capture_errno());
}
- _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
- _LIBCPP_ASSERT(ret > 0, "TODO");
- buff[ret] = 0;
- return {buff};
+ _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
+ _LIBCPP_ASSERT(ret > 0, "TODO");
+ buff[ret] = 0;
+ return {buff};
}
-
-bool __remove(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 (errno != ENOENT)
err.report(capture_errno());
return false;
}
- return true;
+ return true;
}
namespace {
-uintmax_t remove_all_impl(path const & p, error_code& ec)
-{
- const auto npos = static_cast<uintmax_t>(-1);
- const file_status st = __symlink_status(p, &ec);
- if (ec) return npos;
- uintmax_t count = 1;
- if (is_directory(st)) {
- for (directory_iterator it(p, ec); !ec && it != directory_iterator();
- it.increment(ec)) {
- auto other_count = remove_all_impl(it->path(), ec);
- if (ec) return npos;
- count += other_count;
- }
- if (ec) return npos;
+uintmax_t remove_all_impl(path const& p, error_code& ec) {
+ const auto npos = static_cast<uintmax_t>(-1);
+ const file_status st = __symlink_status(p, &ec);
+ if (ec)
+ return npos;
+ uintmax_t count = 1;
+ if (is_directory(st)) {
+ for (directory_iterator it(p, ec); !ec && it != directory_iterator();
+ it.increment(ec)) {
+ auto other_count = remove_all_impl(it->path(), ec);
+ if (ec)
+ return npos;
+ count += other_count;
}
- if (!__remove(p, &ec)) return npos;
- return count;
+ if (ec)
+ return npos;
+ }
+ if (!__remove(p, &ec))
+ return npos;
+ return count;
}
} // end namespace
-uintmax_t __remove_all(const path& p, error_code *ec) {
+uintmax_t __remove_all(const path& p, error_code* ec) {
ErrorHandler<uintmax_t> err("remove_all", ec, &p);
error_code mec;
@@ -1150,22 +1135,22 @@
return 0;
return err.report(mec);
}
- return count;
+ return count;
}
-void __rename(const path& from, const path& to, 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)
err.report(capture_errno());
}
-void __resize_file(const path& p, uintmax_t size, error_code *ec) {
+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)
return err.report(capture_errno());
}
-space_info __space(const path& p, 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 = {};
@@ -1174,24 +1159,24 @@
si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
return si;
}
- // Multiply with overflow checking.
- auto do_mult = [&](uintmax_t& out, uintmax_t other) {
- out = other * m_svfs.f_frsize;
- if (other == 0 || out / other != m_svfs.f_frsize)
- out = static_cast<uintmax_t>(-1);
- };
- do_mult(si.capacity, m_svfs.f_blocks);
- do_mult(si.free, m_svfs.f_bfree);
- do_mult(si.available, m_svfs.f_bavail);
- return si;
+ // Multiply with overflow checking.
+ auto do_mult = [&](uintmax_t& out, uintmax_t other) {
+ out = other * m_svfs.f_frsize;
+ if (other == 0 || out / other != m_svfs.f_frsize)
+ out = static_cast<uintmax_t>(-1);
+ };
+ do_mult(si.capacity, m_svfs.f_blocks);
+ do_mult(si.free, m_svfs.f_bfree);
+ do_mult(si.available, m_svfs.f_bavail);
+ return si;
}
-file_status __status(const path& p, error_code *ec) {
- return detail::posix_stat(p, ec);
+file_status __status(const path& p, error_code* ec) {
+ return detail::posix_stat(p, ec);
}
-file_status __symlink_status(const path& p, error_code *ec) {
- return detail::posix_lstat(p, ec);
+file_status __symlink_status(const path& p, error_code* ec) {
+ return detail::posix_lstat(p, ec);
}
path __temp_directory_path(error_code* ec) {
@@ -1219,8 +1204,7 @@
return p;
}
-
-path __weakly_canonical(const path& p, error_code *ec) {
+path __weakly_canonical(const path& p, error_code* ec) {
ErrorHandler<path> err("weakly_canonical", ec, &p);
if (p.empty())
@@ -1248,10 +1232,11 @@
}
if (PP.State == PathParser::PS_BeforeBegin)
result = __canonical("", ec);
- if (ec) ec->clear();
+ if (ec)
+ ec->clear();
if (DNEParts.empty())
return result;
- for (auto It=DNEParts.rbegin(); It != DNEParts.rend(); ++It)
+ for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
result /= *It;
return result.lexically_normal();
}
@@ -1262,56 +1247,52 @@
constexpr path::value_type path::preferred_separator;
-path & path::replace_extension(path const & replacement)
-{
- path p = extension();
- if (not p.empty()) {
- __pn_.erase(__pn_.size() - p.native().size());
+path& path::replace_extension(path const& replacement) {
+ path p = extension();
+ if (not p.empty()) {
+ __pn_.erase(__pn_.size() - p.native().size());
+ }
+ if (!replacement.empty()) {
+ if (replacement.native()[0] != '.') {
+ __pn_ += ".";
}
- if (!replacement.empty()) {
- if (replacement.native()[0] != '.') {
- __pn_ += ".";
- }
- __pn_.append(replacement.__pn_);
- }
- return *this;
+ __pn_.append(replacement.__pn_);
+ }
+ return *this;
}
///////////////////////////////////////////////////////////////////////////////
// path.decompose
-string_view_t path::__root_name() const
-{
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName)
- return *PP;
- return {};
+string_view_t path::__root_name() const {
+ auto PP = PathParser::CreateBegin(__pn_);
+ if (PP.State == PathParser::PS_InRootName)
+ return *PP;
+ return {};
}
-string_view_t path::__root_directory() const
-{
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName)
+string_view_t path::__root_directory() const {
+ auto PP = PathParser::CreateBegin(__pn_);
+ if (PP.State == PathParser::PS_InRootName)
+ ++PP;
+ if (PP.State == PathParser::PS_InRootDir)
+ return *PP;
+ return {};
+}
+
+string_view_t path::__root_path_raw() const {
+ auto PP = PathParser::CreateBegin(__pn_);
+ if (PP.State == PathParser::PS_InRootName) {
+ auto NextCh = PP.peek();
+ if (NextCh && *NextCh == '/') {
++PP;
- if (PP.State == PathParser::PS_InRootDir)
- return *PP;
- return {};
-}
-
-string_view_t path::__root_path_raw() const
-{
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName) {
- auto NextCh = PP.peek();
- if (NextCh && *NextCh == '/') {
- ++PP;
- return createView(__pn_.data(), &PP.RawEntry.back());
- }
- return PP.RawEntry;
+ return createView(__pn_.data(), &PP.RawEntry.back());
}
- if (PP.State == PathParser::PS_InRootDir)
- return *PP;
- return {};
+ return PP.RawEntry;
+ }
+ if (PP.State == PathParser::PS_InRootDir)
+ return *PP;
+ return {};
}
static bool ConsumeRootDir(PathParser* PP) {
@@ -1320,62 +1301,57 @@
return PP->State == PathParser::PS_AtEnd;
}
-string_view_t path::__relative_path() const
-{
+string_view_t path::__relative_path() const {
+ auto PP = PathParser::CreateBegin(__pn_);
+ if (ConsumeRootDir(&PP))
+ return {};
+ return createView(PP.RawEntry.data(), &__pn_.back());
+}
+
+string_view_t path::__parent_path() const {
+ if (empty())
+ return {};
+ // Determine if we have a root path but not a relative path. In that case
+ // return *this.
+ {
auto PP = PathParser::CreateBegin(__pn_);
if (ConsumeRootDir(&PP))
+ return __pn_;
+ }
+ // Otherwise remove a single element from the end of the path, and return
+ // a string representing that path
+ {
+ auto PP = PathParser::CreateEnd(__pn_);
+ --PP;
+ if (PP.RawEntry.data() == __pn_.data())
return {};
- return createView(PP.RawEntry.data(), &__pn_.back());
+ --PP;
+ return createView(__pn_.data(), &PP.RawEntry.back());
+ }
}
-string_view_t path::__parent_path() const
-{
- if (empty())
+string_view_t path::__filename() const {
+ if (empty())
+ return {};
+ {
+ PathParser PP = PathParser::CreateBegin(__pn_);
+ if (ConsumeRootDir(&PP))
return {};
- // Determine if we have a root path but not a relative path. In that case
- // return *this.
- {
- auto PP = PathParser::CreateBegin(__pn_);
- if (ConsumeRootDir(&PP))
- return __pn_;
- }
- // Otherwise remove a single element from the end of the path, and return
- // a string representing that path
- {
- auto PP = PathParser::CreateEnd(__pn_);
- --PP;
- if (PP.RawEntry.data() == __pn_.data())
- return {};
- --PP;
- return createView(__pn_.data(), &PP.RawEntry.back());
- }
+ }
+ return *(--PathParser::CreateEnd(__pn_));
}
-string_view_t path::__filename() const
-{
- if (empty()) return {};
- {
- PathParser PP = PathParser::CreateBegin(__pn_);
- if (ConsumeRootDir(&PP))
- return {};
- }
- return *(--PathParser::CreateEnd(__pn_));
+string_view_t path::__stem() const {
+ return parser::separate_filename(__filename()).first;
}
-string_view_t path::__stem() const
-{
- return parser::separate_filename(__filename()).first;
-}
-
-string_view_t path::__extension() const
-{
- return parser::separate_filename(__filename()).second;
+string_view_t path::__extension() const {
+ return parser::separate_filename(__filename()).second;
}
////////////////////////////////////////////////////////////////////////////
// path.gen
-
enum PathPartKind : unsigned char {
PK_None,
PK_RootSep,
@@ -1456,7 +1432,7 @@
}
// [fs.path.generic]p6.8: If the path is empty, add a dot.
if (Parts.empty())
- return ".";
+ return ".";
// [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
// trailing directory-separator.
@@ -1464,7 +1440,7 @@
path Result;
Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
- for (auto &PK : Parts)
+ for (auto& PK : Parts)
Result /= PK.first;
if (NeedTrailingSep)
@@ -1490,8 +1466,8 @@
auto PP = PathParser::CreateBegin(__pn_);
auto PPBase = PathParser::CreateBegin(base.__pn_);
auto CheckIterMismatchAtBase = [&]() {
- return PP.State != PPBase.State && (
- PP.inRootPath() || PPBase.inRootPath());
+ return PP.State != PPBase.State &&
+ (PP.inRootPath() || PPBase.inRootPath());
};
if (PP.State == PathParser::PS_InRootName &&
PPBase.State == PathParser::PS_InRootName) {
@@ -1500,8 +1476,10 @@
} else if (CheckIterMismatchAtBase())
return {};
- if (PP.inRootPath()) ++PP;
- if (PPBase.inRootPath()) ++PPBase;
+ if (PP.inRootPath())
+ ++PP;
+ if (PPBase.inRootPath())
+ ++PPBase;
if (CheckIterMismatchAtBase())
return {};
}
@@ -1509,8 +1487,7 @@
// Find the first mismatching element
auto PP = PathParser::CreateBegin(__pn_);
auto PPBase = PathParser::CreateBegin(base.__pn_);
- while (PP && PPBase && PP.State == PPBase.State &&
- *PP == *PPBase) {
+ while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
++PP;
++PPBase;
}
@@ -1539,18 +1516,20 @@
////////////////////////////////////////////////////////////////////////////
// path.comparisons
int path::__compare(string_view_t __s) const {
- auto PP = PathParser::CreateBegin(__pn_);
- auto PP2 = PathParser::CreateBegin(__s);
- while (PP && PP2) {
- int res = (*PP).compare(*PP2);
- if (res != 0) return res;
- ++PP; ++PP2;
- }
- if (PP.State == PP2.State && !PP)
- return 0;
- if (!PP)
- return -1;
- return 1;
+ auto PP = PathParser::CreateBegin(__pn_);
+ auto PP2 = PathParser::CreateBegin(__s);
+ while (PP && PP2) {
+ int res = (*PP).compare(*PP2);
+ if (res != 0)
+ return res;
+ ++PP;
+ ++PP2;
+ }
+ if (PP.State == PP2.State && !PP)
+ return 0;
+ if (!PP)
+ return -1;
+ return 1;
}
////////////////////////////////////////////////////////////////////////////
@@ -1568,23 +1547,21 @@
////////////////////////////////////////////////////////////////////////////
// path.itr
-path::iterator path::begin() const
-{
- auto PP = PathParser::CreateBegin(__pn_);
- iterator it;
- it.__path_ptr_ = this;
- it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
- it.__entry_ = PP.RawEntry;
- it.__stashed_elem_.__assign_view(*PP);
- return it;
+path::iterator path::begin() const {
+ auto PP = PathParser::CreateBegin(__pn_);
+ iterator it;
+ it.__path_ptr_ = this;
+ it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
+ it.__entry_ = PP.RawEntry;
+ it.__stashed_elem_.__assign_view(*PP);
+ return it;
}
-path::iterator path::end() const
-{
- iterator it{};
- it.__state_ = path::iterator::_AtEnd;
- it.__path_ptr_ = this;
- return it;
+path::iterator path::end() const {
+ iterator it{};
+ it.__state_ = path::iterator::_AtEnd;
+ it.__path_ptr_ = this;
+ return it;
}
path::iterator& path::iterator::__increment() {
@@ -1706,4 +1683,4 @@
}
#endif
-_LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
+_LIBCPP_END_NAMESPACE_FILESYSTEM