2019-01-06 Jonathan Wakely <jwakely@redhat.com>
+ PR libstdc++/86756
+ * acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for utime and
+ lstat and define _GLIBCXX_USE_UTIME and _GLIBCXX_USE_LSTAT.
+ * config.h.in: Regenerate.
+ * config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Export symbols for
+ remaining std::filesystem types and functions.
+ * configure: Regenerate.
+ * src/c++17/Makefile.am: Add C++17 filesystem sources.
+ * src/c++17/Makefile.in: Regenerate.
+ * src/c++17/cow-fs_dir.cc: Move src/filesystem/cow-std-dir.cc to
+ here, and change name of included file.
+ * src/c++17/cow-fs_ops.cc: Move src/filesystem/cow-std-ops.cc to
+ here, and change name of included file.
+ * src/c++17/fs_dir.cc: Move src/filesystem/std-dir.cc to here. Change
+ path to dir-common.h.
+ * src/c++17/fs_ops.cc: Move src/filesystem/std-ops.cc to here. Change
+ path to ops-common.h. Disable -Wunused-parameter warnings.
+ (internal_file_clock): Define unconditionally.
+ [!_GLIBCXX_HAVE_SYS_STAT_H] (internal_file_clock::from_stat): Do not
+ define.
+ (do_copy_file, do_space): Move definitions to ops.common.h.
+ (copy, file_size, hard_link_count, last_write_time, space): Only
+ perform operation when _GLIBCXX_HAVE_SYS_STAT_H is defined, otherwise
+ report an error.
+ (last_write_time, read_symlink): Remove unused attributes from
+ parameters.
+ * src/filesystem/Makefile.am: Remove C++17 filesystem sources.
+ * src/filesystem/Makefile.in: Regenerate.
+ * src/filesystem/cow-std-dir.cc: Move to src/c++17/cow-fs_dir.cc.
+ * src/filesystem/cow-std-ops.cc: Move to src/c++17/cow-fs_ops.cc.
+ * src/filesystem/std-dir.cc: Move to src/c++17/fs_dir.cc.
+ * src/filesystem/std-ops.cc: Move to src/c++17/fs_ops.cc.
+ * src/filesystem/dir-common.h [!_GLIBCXX_HAVE_DIRENT_H]: Define
+ dummy types and functions instead of using #error.
+ * src/filesystem/dir.cc [!_GLIBCXX_HAVE_DIRENT_H]: Use #error.
+ * src/filesystem/ops-common.h [!_GLIBCXX_USE_LSTAT] (lstat): Define
+ in terms of stat.
+ [!_GLIBCXX_HAVE_UNISTD_H]: Define dummy types and functions.
+ (do_copy_file, do_space): Move definitions here from std-ops.cc.
+ * src/filesystem/ops.cc: Adjust calls to do_copy_file and do_space
+ to account for new namespace.
+ * testsuite/27_io/filesystem/directory_entry/86597.cc: Remove
+ -lstdc++fs from dg-options.
+ * testsuite/27_io/filesystem/directory_entry/lwg3171.cc: Likewise.
+ * testsuite/27_io/filesystem/file_status/1.cc: Likewise.
+ * testsuite/27_io/filesystem/filesystem_error/cons.cc: Likewise.
+ * testsuite/27_io/filesystem/filesystem_error/copy.cc: Likewise.
+ * testsuite/27_io/filesystem/iterators/directory_iterator.cc:
+ Likewise.
+ * testsuite/27_io/filesystem/iterators/pop.cc: Likewise.
+ * testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
+ Likewise.
+ * testsuite/27_io/filesystem/operations/absolute.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/canonical.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/copy.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/copy_file.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/create_directories.cc:
+ Likewise.
+ * testsuite/27_io/filesystem/operations/create_directory.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/create_symlink.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/current_path.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/equivalent.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/exists.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/file_size.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/is_empty.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/last_write_time.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/permissions.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/proximate.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/read_symlink.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/relative.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/remove.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/remove_all.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/space.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/status.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/symlink_status.cc: Likewise.
+ * testsuite/27_io/filesystem/operations/temp_directory_path.cc:
+ Likewise.
+ * testsuite/27_io/filesystem/operations/weakly_canonical.cc: Likewise.
+
+
PR libstdc++/86756
* config/abi/pre/gnu.ver (GLIBCXX_3.4): Make various patterns for
typeinfo and vtables less greedy.
AC_DEFINE(_GLIBCXX_USE_UTIMENSAT, 1, [Define if utimensat and UTIME_OMIT are available in <sys/stat.h> and AT_FDCWD in <fcntl.h>.])
fi
AC_MSG_RESULT($glibcxx_cv_utimensat)
+dnl
+ AC_MSG_CHECKING([for utime])
+ AC_CACHE_VAL(glibcxx_cv_utime, [dnl
+ GCC_TRY_COMPILE_OR_LINK(
+ [
+ #include <utime.h>
+ ],
+ [
+ struct utimbuf t = { 1, 1 };
+ int i = utime("path", &t);
+ ],
+ [glibcxx_cv_utime=yes],
+ [glibcxx_cv_utime=no])
+ ])
+ if test $glibcxx_cv_utime = yes; then
+ AC_DEFINE(_GLIBCXX_USE_UTIME, 1, [Define if utime is available in <utime.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_utime)
+dnl
+ AC_MSG_CHECKING([for lstat])
+ AC_CACHE_VAL(glibcxx_cv_lstat, [dnl
+ GCC_TRY_COMPILE_OR_LINK(
+ [ #include <sys/stat.h> ],
+ [
+ struct stat st;
+ int i = lstat("path", &st);
+ ],
+ [glibcxx_cv_lstat=yes],
+ [glibcxx_cv_lstat=no])
+ ])
+ if test $glibcxx_cv_lstat = yes; then
+ AC_DEFINE(_GLIBCXX_USE_LSTAT, 1, [Define if lstat is available in <sys/stat.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_lstat)
dnl
AC_MSG_CHECKING([for struct stat.st_mtim.tv_nsec])
AC_CACHE_VAL(glibcxx_cv_st_mtim, [dnl
/* Define if code specialized for long long should be used. */
#undef _GLIBCXX_USE_LONG_LONG
+/* Define if lstat is available in <sys/stat.h>. */
+#undef _GLIBCXX_USE_LSTAT
+
/* Defined if nanosleep is available. */
#undef _GLIBCXX_USE_NANOSLEEP
/* Define if obsolescent tmpnam is available in <stdio.h>. */
#undef _GLIBCXX_USE_TMPNAM
+/* Define if utime is available in <utime.h>. */
+#undef _GLIBCXX_USE_UTIME
+
/* Define if utimensat and UTIME_OMIT are available in <sys/stat.h> and
AT_FDCWD in <fcntl.h>. */
#undef _GLIBCXX_USE_UTIMENSAT
_ZNSt10filesystem7__cxx114pathpLERKS1_;
_ZT[IV]NSt10filesystem7__cxx1116filesystem_errorE;
+ _ZNSt10filesystem10equivalent*;
+ _ZNSt10filesystem10remove_all*;
+ _ZNSt10filesystem11permissions*;
+ _ZNSt10filesystem12current_path*;
+ _ZNSt10filesystem12read_symlink*;
+ _ZNSt10filesystem14create_symlink*;
+ _ZNSt10filesystem14symlink_status*;
+ _ZNSt10filesystem15last_write_time*;
+ _ZNSt10filesystem16create_directory*;
+ _ZNSt10filesystem16create_hard_link*;
+ _ZNSt10filesystem16weakly_canonical*;
+ _ZNSt10filesystem18create_directories*;
+ _ZNSt10filesystem19temp_directory_path*;
+ _ZNSt10filesystem24create_directory_symlink*;
+ _ZNSt10filesystem4copy*;
+ _ZNSt10filesystem5space*;
+ _ZNSt10filesystem6remove*;
+ _ZNSt10filesystem6status*;
+ _ZNSt10filesystem8absolute*;
+ _ZNSt10filesystem8is_empty*;
+ _ZNSt10filesystem8relative*;
+ _ZNSt10filesystem9canonical*;
+ _ZNSt10filesystem9copy_file*;
+ _ZNSt10filesystem9file_size*;
+ _ZNSt10filesystem9proximate*;
+
+ _ZNKSt10filesystem18directory_iteratordeEv;
+ _ZNKSt10filesystem28recursive_directory_iterator5depthEv;
+ _ZNKSt10filesystem28recursive_directory_iteratordeEv;
+ _ZNSt10filesystem18directory_iteratorC[12]ERKNS_4pathENS_17directory_optionsEPSt10error_code;
+ _ZNSt10filesystem18directory_iteratorppEv;
+ _ZNSt10filesystem28recursive_directory_iterator3popERSt10error_code;
+ _ZNSt10filesystem28recursive_directory_iterator3popEv;
+ _ZNSt10filesystem28recursive_directory_iterator9incrementERSt10error_code;
+ _ZNSt10filesystem28recursive_directory_iteratorC[12]ERKNS_4pathENS_17directory_optionsEPSt10error_code;
+ _ZNSt10filesystem28recursive_directory_iteratorD[12]Ev;
+ _ZNSt10filesystem28recursive_directory_iteratoraSEOS0_;
+ _ZNSt10filesystem28recursive_directory_iteratorppEv;
+
+ _ZNKSt10filesystem7__cxx1118directory_iteratordeEv;
+ _ZNKSt10filesystem7__cxx1128recursive_directory_iterator5depthEv;
+ _ZNKSt10filesystem7__cxx1128recursive_directory_iteratordeEv;
+ _ZNSt10filesystem7__cxx1118directory_iteratorC[12]ERKNS0_4pathENS_17directory_optionsEPSt10error_code;
+ _ZNSt10filesystem7__cxx1118directory_iteratorppEv;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iterator3popERSt10error_code;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iterator3popEv;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iterator9incrementERSt10error_code;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iteratorC[12]ERKNS0_4pathENS_17directory_optionsEPSt10error_code;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iteratorD[12]Ev;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iteratoraSEOS1_;
+ _ZNSt10filesystem7__cxx1128recursive_directory_iteratorppEv;
+
} GLIBCXX_3.4.25;
# Symbols in the support library (libsupc++) have their own tag.
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_utimensat" >&5
$as_echo "$glibcxx_cv_utimensat" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utime" >&5
+$as_echo_n "checking for utime... " >&6; }
+ if ${glibcxx_cv_utime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test x$gcc_no_link = xyes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <utime.h>
+
+int
+main ()
+{
+
+ struct utimbuf t = { 1, 1 };
+ int i = utime("path", &t);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_utime=yes
+else
+ glibcxx_cv_utime=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ if test x$gcc_no_link = xyes; then
+ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
+fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <utime.h>
+
+int
+main ()
+{
+
+ struct utimbuf t = { 1, 1 };
+ int i = utime("path", &t);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_utime=yes
+else
+ glibcxx_cv_utime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+
+ if test $glibcxx_cv_utime = yes; then
+
+$as_echo "#define _GLIBCXX_USE_UTIME 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_utime" >&5
+$as_echo "$glibcxx_cv_utime" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lstat" >&5
+$as_echo_n "checking for lstat... " >&6; }
+ if ${glibcxx_cv_lstat+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test x$gcc_no_link = xyes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <sys/stat.h>
+int
+main ()
+{
+
+ struct stat st;
+ int i = lstat("path", &st);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_lstat=yes
+else
+ glibcxx_cv_lstat=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ if test x$gcc_no_link = xyes; then
+ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
+fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <sys/stat.h>
+int
+main ()
+{
+
+ struct stat st;
+ int i = lstat("path", &st);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_lstat=yes
+else
+ glibcxx_cv_lstat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+
+ if test $glibcxx_cv_lstat = yes; then
+
+$as_echo "#define _GLIBCXX_USE_LSTAT 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_lstat" >&5
+$as_echo "$glibcxx_cv_lstat" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat.st_mtim.tv_nsec" >&5
$as_echo_n "checking for struct stat.st_mtim.tv_nsec... " >&6; }
if ${glibcxx_cv_st_mtim+:} false; then :
if ENABLE_DUAL_ABI
extra_string_inst_sources = cow-string-inst.cc
-extra_fs_sources = cow-fs_path.cc
+extra_fs_sources = \
+ cow-fs_dir.cc \
+ cow-fs_ops.cc \
+ cow-fs_path.cc
else
extra_string_inst_sources =
extra_fs_sources =
endif
sources = \
+ fs_dir.cc \
+ fs_ops.cc \
fs_path.cc \
memory_resource.cc \
string-inst.cc \
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libc__17convenience_la_LIBADD =
-@ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-fs_path.lo
-am__objects_2 = fs_path.lo memory_resource.lo string-inst.lo \
- $(am__objects_1)
+@ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-fs_dir.lo cow-fs_ops.lo \
+@ENABLE_DUAL_ABI_TRUE@ cow-fs_path.lo
+am__objects_2 = fs_dir.lo fs_ops.lo fs_path.lo memory_resource.lo \
+ string-inst.lo $(am__objects_1)
@ENABLE_DUAL_ABI_TRUE@am__objects_3 = cow-string-inst.lo
@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_4 = $(am__objects_3)
am_libc__17convenience_la_OBJECTS = $(am__objects_2) $(am__objects_4)
@ENABLE_DUAL_ABI_FALSE@extra_string_inst_sources =
@ENABLE_DUAL_ABI_TRUE@extra_string_inst_sources = cow-string-inst.cc
@ENABLE_DUAL_ABI_FALSE@extra_fs_sources =
-@ENABLE_DUAL_ABI_TRUE@extra_fs_sources = cow-fs_path.cc
+@ENABLE_DUAL_ABI_TRUE@extra_fs_sources = \
+@ENABLE_DUAL_ABI_TRUE@ cow-fs_dir.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-fs_ops.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-fs_path.cc
+
# XTEMPLATE_FLAGS =
@ENABLE_EXTERN_TEMPLATE_FALSE@inst_sources =
@ENABLE_EXTERN_TEMPLATE_TRUE@ $(extra_string_inst_sources)
sources = \
+ fs_dir.cc \
+ fs_ops.cc \
fs_path.cc \
memory_resource.cc \
string-inst.cc \
--- /dev/null
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2015-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "fs_dir.cc"
--- /dev/null
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2015-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "fs_ops.cc"
--- /dev/null
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2014-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#include <utility>
+#include <stack>
+#include <string.h>
+#include <errno.h>
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "../filesystem/dir-common.h"
+
+namespace fs = std::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
+
+template class std::__shared_ptr<fs::_Dir>;
+template class std::__shared_ptr<fs::recursive_directory_iterator::_Dir_stack>;
+
+struct fs::_Dir : _Dir_base
+{
+ _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
+ : _Dir_base(p.c_str(), skip_permission_denied, ec)
+ {
+ if (!ec)
+ path = p;
+ }
+
+ _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+
+ _Dir(_Dir&&) = default;
+
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by setting ec.
+ bool advance(bool skip_permission_denied, error_code& ec) noexcept
+ {
+ if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
+ {
+ auto name = path;
+ name /= entp->d_name;
+ entry = fs::directory_entry{std::move(name), get_file_type(*entp)};
+ return true;
+ }
+ else if (!ec)
+ {
+ // reached the end
+ entry = {};
+ }
+ return false;
+ }
+
+ bool advance(error_code& ec) noexcept { return advance(false, ec); }
+
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by throwing.
+ bool advance(bool skip_permission_denied = false)
+ {
+ error_code ec;
+ const bool ok = advance(skip_permission_denied, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "directory iterator cannot advance", ec));
+ return ok;
+ }
+
+ bool should_recurse(bool follow_symlink, error_code& ec) const
+ {
+ file_type type = entry._M_type;
+ if (type == file_type::none || type == file_type::unknown)
+ {
+ type = entry.symlink_status(ec).type();
+ if (ec)
+ return false;
+ }
+
+ if (type == file_type::directory)
+ return true;
+ if (type == file_type::symlink)
+ return follow_symlink && is_directory(entry.status(ec));
+ return false;
+ }
+
+ fs::path path;
+ directory_entry entry;
+};
+
+namespace
+{
+ template<typename Bitmask>
+ inline bool
+ is_set(Bitmask obj, Bitmask bits)
+ {
+ return (obj & bits) != Bitmask::none;
+ }
+}
+
+fs::directory_iterator::
+directory_iterator(const path& p, directory_options options, error_code* ecptr)
+{
+ const bool skip_permission_denied
+ = is_set(options, directory_options::skip_permission_denied);
+
+ error_code ec;
+ _Dir dir(p, skip_permission_denied, ec);
+
+ if (dir.dirp)
+ {
+ auto sp = std::__make_shared<fs::_Dir>(std::move(dir));
+ if (sp->advance(skip_permission_denied, ec))
+ _M_dir.swap(sp);
+ }
+ if (ecptr)
+ *ecptr = ec;
+ else if (ec)
+ _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
+ "directory iterator cannot open directory", p, ec));
+}
+
+const fs::directory_entry&
+fs::directory_iterator::operator*() const
+{
+ if (!_M_dir)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "non-dereferenceable directory iterator",
+ std::make_error_code(errc::invalid_argument)));
+ return _M_dir->entry;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::operator++()
+{
+ if (!_M_dir)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "cannot advance non-dereferenceable directory iterator",
+ std::make_error_code(errc::invalid_argument)));
+ if (!_M_dir->advance())
+ _M_dir.reset();
+ return *this;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::increment(error_code& ec)
+{
+ if (!_M_dir)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return *this;
+ }
+ if (!_M_dir->advance(ec))
+ _M_dir.reset();
+ return *this;
+}
+
+struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
+{
+ void clear() { c.clear(); }
+};
+
+fs::recursive_directory_iterator::
+recursive_directory_iterator(const path& p, directory_options options,
+ error_code* ecptr)
+: _M_options(options), _M_pending(true)
+{
+ if (posix::DIR* dirp = posix::opendir(p.c_str()))
+ {
+ if (ecptr)
+ ecptr->clear();
+ auto sp = std::__make_shared<_Dir_stack>();
+ sp->push(_Dir{ dirp, p });
+ if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance())
+ _M_dirs.swap(sp);
+ }
+ else
+ {
+ const int err = errno;
+ if (err == EACCES
+ && is_set(options, fs::directory_options::skip_permission_denied))
+ {
+ if (ecptr)
+ ecptr->clear();
+ return;
+ }
+
+ if (!ecptr)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "recursive directory iterator cannot open directory", p,
+ std::error_code(err, std::generic_category())));
+
+ ecptr->assign(err, std::generic_category());
+ }
+}
+
+fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
+
+int
+fs::recursive_directory_iterator::depth() const
+{
+ return int(_M_dirs->size()) - 1;
+}
+
+const fs::directory_entry&
+fs::recursive_directory_iterator::operator*() const
+{
+ return _M_dirs->top().entry;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(const recursive_directory_iterator& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(recursive_directory_iterator&& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::operator++()
+{
+ error_code ec;
+ increment(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "cannot increment recursive directory iterator", ec));
+ return *this;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::increment(error_code& ec)
+{
+ if (!_M_dirs)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return *this;
+ }
+
+ const bool follow
+ = is_set(_M_options, directory_options::follow_directory_symlink);
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
+ auto& top = _M_dirs->top();
+
+ if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
+ {
+ _Dir dir(top.entry.path(), skip_permission_denied, ec);
+ if (ec)
+ {
+ _M_dirs.reset();
+ return *this;
+ }
+ if (dir.dirp)
+ _M_dirs->push(std::move(dir));
+ }
+
+ while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
+ {
+ _M_dirs->pop();
+ if (_M_dirs->empty())
+ {
+ _M_dirs.reset();
+ return *this;
+ }
+ }
+ return *this;
+}
+
+void
+fs::recursive_directory_iterator::pop(error_code& ec)
+{
+ if (!_M_dirs)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return;
+ }
+
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
+ do {
+ _M_dirs->pop();
+ if (_M_dirs->empty())
+ {
+ _M_dirs.reset();
+ ec.clear();
+ return;
+ }
+ } while (!_M_dirs->top().advance(skip_permission_denied, ec));
+}
+
+void
+fs::recursive_directory_iterator::pop()
+{
+ error_code ec;
+ pop(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
+ ? "recursive directory iterator cannot pop"
+ : "non-dereferenceable recursive directory iterator cannot pop",
+ ec));
+}
--- /dev/null
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2014-2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+# define NEED_DO_COPY_FILE
+# define NEED_DO_SPACE
+#endif
+
+#include <filesystem>
+#include <functional>
+#include <ostream>
+#include <stack>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h> // PATH_MAX
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+# include <sys/stat.h> // stat, utimensat, fchmodat
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h> // statvfs
+#endif
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
+#endif
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <windows.h>
+#endif
+
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "../filesystem/ops-common.h"
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+namespace fs = std::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
+
+fs::path
+fs::absolute(const path& p)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ error_code ec;
+ path ret = absolute(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
+ ec));
+ return ret;
+#else
+ return current_path() / p;
+#endif
+}
+
+fs::path
+fs::absolute(const path& p, error_code& ec)
+{
+ path ret;
+ if (p.empty())
+ {
+ ec = make_error_code(std::errc::no_such_file_or_directory);
+ return ret;
+ }
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ const wstring& s = p.native();
+ uint32_t len = 1024;
+ wstring buf;
+ do
+ {
+ buf.resize(len);
+ len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr);
+ }
+ while (len > buf.size());
+
+ if (len == 0)
+ ec.assign((int)GetLastError(), std::system_category());
+ else
+ {
+ ec.clear();
+ buf.resize(len);
+ ret = std::move(buf);
+ }
+#else
+ ec.clear();
+ ret = current_path();
+ ret /= p;
+#endif
+ return ret;
+}
+
+namespace
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ inline bool is_dot(wchar_t c) { return c == L'.'; }
+#else
+ inline bool is_dot(char c) { return c == '.'; }
+#endif
+
+ inline bool is_dot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 1 && is_dot(filename[0]);
+ }
+
+ inline bool is_dotdot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
+ }
+
+ struct free_as_in_malloc
+ {
+ void operator()(void* p) const { ::free(p); }
+ };
+
+ using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
+}
+
+fs::path
+fs::canonical(const path& p, error_code& ec)
+{
+ path result;
+ const path pa = absolute(p, ec);
+ if (ec)
+ return result;
+
+#ifdef _GLIBCXX_USE_REALPATH
+ char_ptr buf{ nullptr };
+# if _XOPEN_VERSION < 700
+ // Not safe to call realpath(path, NULL)
+ using char_type = fs::path::value_type;
+ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
+# endif
+ if (char* rp = ::realpath(pa.c_str(), buf.get()))
+ {
+ if (buf == nullptr)
+ buf.reset(rp);
+ result.assign(rp);
+ ec.clear();
+ return result;
+ }
+ if (errno != ENAMETOOLONG)
+ {
+ ec.assign(errno, std::generic_category());
+ return result;
+ }
+#endif
+
+ if (!exists(pa, ec))
+ {
+ if (!ec)
+ ec = make_error_code(std::errc::no_such_file_or_directory);
+ return result;
+ }
+ // else: we know there are (currently) no unresolvable symlink loops
+
+ result = pa.root_path();
+
+ deque<path> cmpts;
+ for (auto& f : pa.relative_path())
+ cmpts.push_back(f);
+
+ int max_allowed_symlinks = 40;
+
+ while (!cmpts.empty() && !ec)
+ {
+ path f = std::move(cmpts.front());
+ cmpts.pop_front();
+
+ if (f.empty())
+ {
+ // ignore empty element
+ }
+ else if (is_dot(f))
+ {
+ if (!is_directory(result, ec) && !ec)
+ ec.assign(ENOTDIR, std::generic_category());
+ }
+ else if (is_dotdot(f))
+ {
+ auto parent = result.parent_path();
+ if (parent.empty())
+ result = pa.root_path();
+ else
+ result.swap(parent);
+ }
+ else
+ {
+ result /= f;
+
+ if (is_symlink(result, ec))
+ {
+ path link = read_symlink(result, ec);
+ if (!ec)
+ {
+ if (--max_allowed_symlinks == 0)
+ ec.assign(ELOOP, std::generic_category());
+ else
+ {
+ if (link.is_absolute())
+ {
+ result = link.root_path();
+ link = link.relative_path();
+ }
+ else
+ result = result.parent_path();
+
+ cmpts.insert(cmpts.begin(), link.begin(), link.end());
+ }
+ }
+ }
+ }
+ }
+
+ if (ec || !exists(result, ec))
+ result.clear();
+
+ return result;
+}
+
+fs::path
+fs::canonical(const path& p)
+{
+ error_code ec;
+ path res = canonical(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
+ p, ec));
+ return res;
+}
+
+void
+fs::copy(const path& from, const path& to, copy_options options)
+{
+ error_code ec;
+ copy(from, to, options, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
+}
+
+namespace std::filesystem
+{
+ // Need this as there's no 'perm_options::none' enumerator.
+ static inline bool is_set(fs::perm_options obj, fs::perm_options bits)
+ {
+ return (obj & bits) != fs::perm_options{};
+ }
+}
+
+namespace
+{
+ struct internal_file_clock : fs::__file_clock
+ {
+ using __file_clock::_S_to_sys;
+ using __file_clock::_S_from_sys;
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ static fs::file_time_type
+ from_stat(const fs::stat_type& st, std::error_code& ec) noexcept
+ {
+ const auto sys_time = fs::file_time(st, ec);
+ if (sys_time == sys_time.min())
+ return fs::file_time_type::min();
+ return _S_from_sys(sys_time);
+ }
+#endif
+ };
+}
+
+void
+fs::copy(const path& from, const path& to, copy_options options,
+ error_code& ec)
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
+ const bool create_symlinks = is_set(options, copy_options::create_symlinks);
+ const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
+ const bool use_lstat = create_symlinks || skip_symlinks;
+
+ file_status f, t;
+ stat_type from_st, to_st;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2681. filesystem::copy() cannot copy symlinks
+ if (use_lstat || copy_symlinks
+ ? posix::lstat(from.c_str(), &from_st)
+ : posix::stat(from.c_str(), &from_st))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ if (use_lstat
+ ? posix::lstat(to.c_str(), &to_st)
+ : posix::stat(to.c_str(), &to_st))
+ {
+ if (!is_not_found_errno(errno))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ t = file_status{file_type::not_found};
+ }
+ else
+ t = make_file_status(to_st);
+ f = make_file_status(from_st);
+
+ if (exists(t) && !is_other(t) && !is_other(f)
+ && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return;
+ }
+ if (is_other(f) || is_other(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return;
+ }
+ if (is_directory(f) && is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::is_a_directory);
+ return;
+ }
+
+ if (is_symlink(f))
+ {
+ if (skip_symlinks)
+ ec.clear();
+ else if (!exists(t) && copy_symlinks)
+ copy_symlink(from, to, ec);
+ else
+ // Not clear what should be done here.
+ // "Otherwise report an error as specified in Error reporting (7)."
+ ec = std::make_error_code(std::errc::invalid_argument);
+ }
+ else if (is_regular_file(f))
+ {
+ if (is_set(options, copy_options::directories_only))
+ ec.clear();
+ else if (create_symlinks)
+ create_symlink(from, to, ec);
+ else if (is_set(options, copy_options::create_hard_links))
+ create_hard_link(from, to, ec);
+ else if (is_directory(t))
+ do_copy_file(from.c_str(), (to / from.filename()).c_str(),
+ copy_file_options(options), &from_st, nullptr, ec);
+ else
+ {
+ auto ptr = exists(t) ? &to_st : &from_st;
+ do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ &from_st, ptr, ec);
+ }
+ }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2682. filesystem::copy() won't create a symlink to a directory
+ else if (is_directory(f) && create_symlinks)
+ ec = std::make_error_code(errc::is_a_directory);
+ else if (is_directory(f) && (is_set(options, copy_options::recursive)
+ || options == copy_options::none))
+ {
+ if (!exists(t))
+ if (!create_directory(to, from, ec))
+ return;
+ // set an unused bit in options to disable further recursion
+ if (!is_set(options, copy_options::recursive))
+ options |= static_cast<copy_options>(4096);
+ for (const directory_entry& x : directory_iterator(from))
+ copy(x.path(), to/x.path().filename(), options, ec);
+ }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2683. filesystem::copy() says "no effects"
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options option)
+{
+ error_code ec;
+ bool result = copy_file(from, to, option, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
+ ec));
+ return result;
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options options,
+ error_code& ec)
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ nullptr, nullptr, ec);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+#endif
+}
+
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
+{
+ error_code ec;
+ copy_symlink(existing_symlink, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
+ existing_symlink, new_symlink, ec));
+}
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
+ error_code& ec) noexcept
+{
+ auto p = read_symlink(existing_symlink, ec);
+ if (ec)
+ return;
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (is_directory(p))
+ {
+ create_directory_symlink(p, new_symlink, ec);
+ return;
+ }
+#endif
+ create_symlink(p, new_symlink, ec);
+}
+
+
+bool
+fs::create_directories(const path& p)
+{
+ error_code ec;
+ bool result = create_directories(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directories(const path& p, error_code& ec)
+{
+ if (p.empty())
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return false;
+ }
+
+ file_status st = symlink_status(p, ec);
+ if (is_directory(st))
+ return false;
+ else if (ec && !status_known(st))
+ return false;
+ else if (exists(st))
+ {
+ if (!ec)
+ ec = std::make_error_code(std::errc::not_a_directory);
+ return false;
+ }
+
+ std::stack<path> missing;
+ path pp = p;
+
+ // Strip any trailing slash
+ if (pp.has_relative_path() && !pp.has_filename())
+ pp = pp.parent_path();
+
+ do
+ {
+ const auto& filename = pp.filename();
+ if (is_dot(filename) || is_dotdot(filename))
+ pp = pp.parent_path();
+ else
+ {
+ missing.push(std::move(pp));
+ if (missing.size() > 1000) // sanity check
+ {
+ ec = std::make_error_code(std::errc::filename_too_long);
+ return false;
+ }
+ pp = missing.top().parent_path();
+ }
+
+ if (pp.empty())
+ break;
+
+ st = status(pp, ec);
+ if (exists(st))
+ {
+ if (ec)
+ return false;
+ if (!is_directory(st))
+ {
+ ec = std::make_error_code(std::errc::not_a_directory);
+ return false;
+ }
+ }
+
+ if (ec && exists(st))
+ return false;
+ }
+ while (st.type() == file_type::not_found);
+
+ bool created;
+ do
+ {
+ const path& top = missing.top();
+ created = create_directory(top, ec);
+ if (ec)
+ return false;
+ missing.pop();
+ }
+ while (!missing.empty());
+
+ return created;
+}
+
+namespace
+{
+ bool
+ create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
+ {
+ bool created = false;
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ posix::mode_t mode
+ = static_cast<std::underlying_type_t<fs::perms>>(perm);
+ if (posix::mkdir(p.c_str(), mode))
+ {
+ const int err = errno;
+ if (err != EEXIST || !is_directory(p, ec))
+ ec.assign(err, std::generic_category());
+ }
+ else
+ {
+ ec.clear();
+ created = true;
+ }
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return created;
+ }
+} // namespace
+
+bool
+fs::create_directory(const path& p)
+{
+ error_code ec;
+ bool result = create_directory(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directory(const path& p, error_code& ec) noexcept
+{
+ return create_dir(p, perms::all, ec);
+}
+
+
+bool
+fs::create_directory(const path& p, const path& attributes)
+{
+ error_code ec;
+ bool result = create_directory(p, attributes, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directory(const path& p, const path& attributes,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+ if (posix::stat(attributes.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ return create_dir(p, static_cast<perms>(st.st_mode), ec);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+#endif
+}
+
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink)
+{
+ error_code ec;
+ create_directory_symlink(to, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
+ to, new_symlink, ec));
+}
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(std::errc::not_supported);
+#else
+ create_symlink(to, new_symlink, ec);
+#endif
+}
+
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link)
+{
+ error_code ec;
+ create_hard_link(to, new_hard_link, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
+ to, new_hard_link, ec));
+}
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_LINK
+ if (::link(to.c_str(), new_hard_link.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
+ ec.clear();
+ else
+ ec.assign((int)GetLastError(), generic_category());
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink)
+{
+ error_code ec;
+ create_symlink(to, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
+ to, new_symlink, ec));
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYMLINK
+ if (::symlink(to.c_str(), new_symlink.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::path
+fs::current_path()
+{
+ error_code ec;
+ path p = current_path(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
+ return p;
+}
+
+fs::path
+fs::current_path(error_code& ec)
+{
+ path p;
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
+ {
+ p.assign(cwd.get());
+ ec.clear();
+ }
+ else
+ ec.assign(errno, std::generic_category());
+#else
+#ifdef _PC_PATH_MAX
+ long path_max = pathconf(".", _PC_PATH_MAX);
+ size_t size;
+ if (path_max == -1)
+ size = 1024;
+ else if (path_max > 10240)
+ size = 10240;
+ else
+ size = path_max;
+#elif defined(PATH_MAX)
+ size_t size = PATH_MAX;
+#else
+ size_t size = 1024;
+#endif
+ for (char_ptr buf; p.empty(); size *= 2)
+ {
+ using char_type = fs::path::value_type;
+ buf.reset((char_type*)malloc(size * sizeof(char_type)));
+ if (buf)
+ {
+ if (getcwd(buf.get(), size))
+ {
+ p.assign(buf.get());
+ ec.clear();
+ }
+ else if (errno != ERANGE)
+ {
+ ec.assign(errno, std::generic_category());
+ return {};
+ }
+ }
+ else
+ {
+ ec = std::make_error_code(std::errc::not_enough_memory);
+ return {};
+ }
+ }
+#endif // __GLIBC__
+#else // _GLIBCXX_HAVE_UNISTD_H
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return p;
+}
+
+void
+fs::current_path(const path& p)
+{
+ error_code ec;
+ current_path(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
+}
+
+void
+fs::current_path(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (posix::chdir(p.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2)
+{
+ error_code ec;
+ auto result = equivalent(p1, p2, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
+ p1, p2, ec));
+ return result;
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ int err = 0;
+ file_status s1, s2;
+ stat_type st1, st2;
+ if (posix::stat(p1.c_str(), &st1) == 0)
+ s1 = make_file_status(st1);
+ else if (is_not_found_errno(errno))
+ s1.type(file_type::not_found);
+ else
+ err = errno;
+
+ if (posix::stat(p2.c_str(), &st2) == 0)
+ s2 = make_file_status(st2);
+ else if (is_not_found_errno(errno))
+ s2.type(file_type::not_found);
+ else
+ err = errno;
+
+ if (exists(s1) && exists(s2))
+ {
+ if (is_other(s1) && is_other(s2))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+ ec.clear();
+ if (is_other(s1) || is_other(s2))
+ return false;
+ return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
+ }
+ else if (!exists(s1) && !exists(s2))
+ ec = std::make_error_code(std::errc::no_such_file_or_directory);
+ else if (err)
+ ec.assign(err, std::generic_category());
+ else
+ ec.clear();
+ return false;
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return false;
+}
+
+std::uintmax_t
+fs::file_size(const path& p)
+{
+ error_code ec;
+ auto sz = file_size(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
+ return sz;
+}
+
+namespace
+{
+ template<typename Accessor, typename T>
+ inline T
+ do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
+ {
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ posix::stat_type st;
+ if (posix::stat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return deflt;
+ }
+ ec.clear();
+ return f(st);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return deflt;
+#endif
+ }
+}
+
+std::uintmax_t
+fs::file_size(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ struct S
+ {
+ S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
+ S() : type(file_type::not_found) { }
+ file_type type;
+ size_t size;
+ };
+ auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
+ if (s.type == file_type::regular)
+ return s.size;
+ if (!ec)
+ {
+ if (s.type == file_type::directory)
+ ec = std::make_error_code(std::errc::is_a_directory);
+ else
+ ec = std::make_error_code(std::errc::not_supported);
+ }
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return -1;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p)
+{
+ error_code ec;
+ auto count = hard_link_count(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
+ return count;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
+ static_cast<uintmax_t>(-1));
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return static_cast<uintmax_t>(-1);
+#endif
+}
+
+bool
+fs::is_empty(const path& p)
+{
+ error_code ec;
+ bool e = is_empty(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
+ p, ec));
+ return e;
+}
+
+bool
+fs::is_empty(const path& p, error_code& ec)
+{
+ auto s = status(p, ec);
+ if (ec)
+ return false;
+ bool empty = fs::is_directory(s)
+ ? fs::directory_iterator(p, ec) == fs::directory_iterator()
+ : fs::file_size(p, ec) == 0;
+ return ec ? false : empty;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p)
+{
+ error_code ec;
+ auto t = last_write_time(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
+ return t;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ return do_stat(p, ec,
+ [&ec](const auto& st) {
+ return internal_file_clock::from_stat(st, ec);
+ },
+ file_time_type::min());
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return file_time_type::min();
+#endif
+}
+
+void
+fs::last_write_time(const path& p, file_time_type new_time)
+{
+ error_code ec;
+ last_write_time(p, new_time, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
+}
+
+void
+fs::last_write_time(const path& p,
+ file_time_type new_time, error_code& ec) noexcept
+{
+ auto d = internal_file_clock::_S_to_sys(new_time).time_since_epoch();
+ auto s = chrono::duration_cast<chrono::seconds>(d);
+#if _GLIBCXX_USE_UTIMENSAT
+ auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
+ if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
+ {
+ --s;
+ ns += chrono::seconds(1);
+ }
+ struct ::timespec ts[2];
+ ts[0].tv_sec = 0;
+ ts[0].tv_nsec = UTIME_OMIT;
+ ts[1].tv_sec = static_cast<std::time_t>(s.count());
+ ts[1].tv_nsec = static_cast<long>(ns.count());
+ if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
+ posix::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
+ times.modtime);
+ if (posix::utime(p.c_str(), ×))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts)
+{
+ error_code ec;
+ permissions(p, prms, opts, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts,
+ error_code& ec) noexcept
+{
+ const bool replace = is_set(opts, perm_options::replace);
+ const bool add = is_set(opts, perm_options::add);
+ const bool remove = is_set(opts, perm_options::remove);
+ const bool nofollow = is_set(opts, perm_options::nofollow);
+ if (((int)replace + (int)add + (int)remove) != 1)
+ {
+ ec = std::make_error_code(std::errc::invalid_argument);
+ return;
+ }
+
+ prms &= perms::mask;
+
+ file_status st;
+ if (add || remove || nofollow)
+ {
+ st = nofollow ? symlink_status(p, ec) : status(p, ec);
+ if (ec)
+ return;
+ auto curr = st.permissions();
+ if (add)
+ prms |= curr;
+ else if (remove)
+ prms = curr & ~prms;
+ }
+
+ int err = 0;
+#if _GLIBCXX_USE_FCHMODAT
+ const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
+ if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
+ err = errno;
+#else
+ if (nofollow && is_symlink(st))
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
+ err = errno;
+#endif
+
+ if (err)
+ ec.assign(err, std::generic_category());
+ else
+ ec.clear();
+}
+
+fs::path
+fs::proximate(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
+}
+
+fs::path
+fs::proximate(const path& p, const path& base, error_code& ec)
+{
+ path result;
+ const auto p2 = weakly_canonical(p, ec);
+ if (!ec)
+ {
+ const auto base2 = weakly_canonical(base, ec);
+ if (!ec)
+ result = p2.lexically_proximate(base2);
+ }
+ return result;
+}
+
+fs::path
+fs::read_symlink(const path& p)
+{
+ error_code ec;
+ path tgt = read_symlink(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
+ return tgt;
+}
+
+fs::path fs::read_symlink(const path& p, error_code& ec)
+{
+ path result;
+#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
+ stat_type st;
+ if (::lstat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return result;
+ }
+ std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
+ do
+ {
+ ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
+ if (len == -1)
+ {
+ ec.assign(errno, std::generic_category());
+ return result;
+ }
+ else if (len == (ssize_t)buf.size())
+ {
+ if (buf.size() > 4096)
+ {
+ ec.assign(ENAMETOOLONG, std::generic_category());
+ return result;
+ }
+ buf.resize(buf.size() * 2);
+ }
+ else
+ {
+ buf.resize(len);
+ result.assign(buf);
+ ec.clear();
+ break;
+ }
+ }
+ while (true);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return result;
+}
+
+fs::path
+fs::relative(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_relative(weakly_canonical(base));
+}
+
+fs::path
+fs::relative(const path& p, const path& base, error_code& ec)
+{
+ auto result = weakly_canonical(p, ec);
+ fs::path cbase;
+ if (!ec)
+ cbase = weakly_canonical(base, ec);
+ if (!ec)
+ result = result.lexically_relative(cbase);
+ if (ec)
+ result.clear();
+ return result;
+}
+
+bool
+fs::remove(const path& p)
+{
+ error_code ec;
+ const bool result = fs::remove(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
+ return result;
+}
+
+bool
+fs::remove(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (exists(symlink_status(p, ec)))
+ {
+ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
+ || DeleteFileW(p.c_str()))
+ {
+ ec.clear();
+ return true;
+ }
+ else if (!ec)
+ ec.assign((int)GetLastError(), generic_category());
+ }
+#else
+ if (::remove(p.c_str()) == 0)
+ {
+ ec.clear();
+ return true;
+ }
+ else if (errno == ENOENT)
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
+#endif
+ return false;
+}
+
+
+std::uintmax_t
+fs::remove_all(const path& p)
+{
+ error_code ec;
+ const auto result = remove_all(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
+ return result;
+}
+
+std::uintmax_t
+fs::remove_all(const path& p, error_code& ec)
+{
+ const auto s = symlink_status(p, ec);
+ if (!status_known(s))
+ return -1;
+
+ ec.clear();
+ if (s.type() == file_type::not_found)
+ return 0;
+
+ uintmax_t count = 0;
+ if (s.type() == file_type::directory)
+ {
+ for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
+ count += fs::remove_all(d->path(), ec);
+ if (ec.value() == ENOENT)
+ ec.clear();
+ else if (ec)
+ return -1;
+ }
+
+ if (fs::remove(p, ec))
+ ++count;
+ return ec ? -1 : count;
+}
+
+void
+fs::rename(const path& from, const path& to)
+{
+ error_code ec;
+ rename(from, to, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
+}
+
+void
+fs::rename(const path& from, const path& to, error_code& ec) noexcept
+{
+ if (posix::rename(from.c_str(), to.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size)
+{
+ error_code ec;
+ resize_file(p, size, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
+ ec.assign(EINVAL, std::generic_category());
+ else if (posix::truncate(p.c_str(), size))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::space_info
+fs::space(const path& p)
+{
+ error_code ec;
+ space_info s = space(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
+ return s;
+}
+
+fs::space_info
+fs::space(const path& p, error_code& ec) noexcept
+{
+ space_info info = {
+ static_cast<uintmax_t>(-1),
+ static_cast<uintmax_t>(-1),
+ static_cast<uintmax_t>(-1)
+ };
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ path dir = absolute(p);
+ dir.remove_filename();
+ auto str = dir.c_str();
+#else
+ auto str = p.c_str();
+#endif
+
+ do_space(str, info.capacity, info.free, info.available, ec);
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+ return info;
+}
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+fs::file_status
+fs::status(const fs::path& p, error_code& ec) noexcept
+{
+ file_status status;
+ stat_type st;
+ if (posix::stat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+ if (is_not_found_errno(err))
+ status.type(file_type::not_found);
+#ifdef EOVERFLOW
+ else if (err == EOVERFLOW)
+ status.type(file_type::unknown);
+#endif
+ }
+ else
+ {
+ status = make_file_status(st);
+ ec.clear();
+ }
+ return status;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
+{
+ file_status status;
+ stat_type st;
+ if (posix::lstat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+ if (is_not_found_errno(err))
+ status.type(file_type::not_found);
+ }
+ else
+ {
+ status = make_file_status(st);
+ ec.clear();
+ }
+ return status;
+}
+#endif
+
+fs::file_status
+fs::status(const fs::path& p)
+{
+ std::error_code ec;
+ auto result = status(p, ec);
+ if (result.type() == file_type::none)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
+ return result;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p)
+{
+ std::error_code ec;
+ auto result = symlink_status(p, ec);
+ if (result.type() == file_type::none)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
+ return result;
+}
+
+fs::path fs::temp_directory_path()
+{
+ error_code ec;
+ path tmp = temp_directory_path(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
+ return tmp;
+}
+
+fs::path fs::temp_directory_path(error_code& ec)
+{
+ path p;
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ unsigned len = 1024;
+ std::wstring buf;
+ do
+ {
+ buf.resize(len);
+ len = GetTempPathW(buf.size(), buf.data());
+ } while (len > buf.size());
+
+ if (len == 0)
+ {
+ ec.assign((int)GetLastError(), std::system_category());
+ return p;
+ }
+ buf.resize(len);
+ p = std::move(buf);
+#else
+ const char* tmpdir = nullptr;
+ const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
+ for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
+ tmpdir = ::getenv(*e);
+ p = tmpdir ? tmpdir : "/tmp";
+#endif
+ auto st = status(p, ec);
+ if (ec)
+ p.clear();
+ else if (!is_directory(st))
+ {
+ p.clear();
+ ec = std::make_error_code(std::errc::not_a_directory);
+ }
+ return p;
+}
+
+fs::path
+fs::weakly_canonical(const path& p)
+{
+ path result;
+ if (exists(status(p)))
+ return canonical(p);
+
+ path tmp;
+ auto iter = p.begin(), end = p.end();
+ // find leading elements of p that exist:
+ while (iter != end)
+ {
+ tmp = result / *iter;
+ if (exists(status(tmp)))
+ swap(result, tmp);
+ else
+ break;
+ ++iter;
+ }
+ // canonicalize:
+ if (!result.empty())
+ result = canonical(result);
+ // append the non-existing elements:
+ while (iter != end)
+ result /= *iter++;
+ // normalize:
+ return result.lexically_normal();
+}
+
+fs::path
+fs::weakly_canonical(const path& p, error_code& ec)
+{
+ path result;
+ file_status st = status(p, ec);
+ if (exists(st))
+ return canonical(p, ec);
+ else if (status_known(st))
+ ec.clear();
+ else
+ return result;
+
+ path tmp;
+ auto iter = p.begin(), end = p.end();
+ // find leading elements of p that exist:
+ while (iter != end)
+ {
+ tmp = result / *iter;
+ st = status(tmp, ec);
+ if (exists(st))
+ swap(result, tmp);
+ else
+ {
+ if (status_known(st))
+ ec.clear();
+ break;
+ }
+ ++iter;
+ }
+ // canonicalize:
+ if (!ec && !result.empty())
+ result = canonical(result, ec);
+ if (ec)
+ result.clear();
+ else
+ {
+ // append the non-existing elements:
+ while (iter != end)
+ result /= *iter++;
+ // normalize:
+ result = result.lexically_normal();
+ }
+ return result;
+}
cxx11_abi_sources = \
cow-dir.cc \
cow-ops.cc \
- cow-path.cc \
- cow-std-dir.cc \
- cow-std-ops.cc
+ cow-path.cc
else
cxx11_abi_sources =
endif
dir.cc \
ops.cc \
path.cc \
- std-dir.cc \
- std-ops.cc \
${cxx11_abi_sources}
# vpath % $(top_srcdir)/src/filesystem
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
libstdc__fs_la_LIBADD =
@ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-dir.lo cow-ops.lo \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.lo cow-std-dir.lo \
-@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.lo
-am__objects_2 = dir.lo ops.lo path.lo std-dir.lo std-ops.lo \
- $(am__objects_1)
+@ENABLE_DUAL_ABI_TRUE@ cow-path.lo
+am__objects_2 = dir.lo ops.lo path.lo $(am__objects_1)
am_libstdc__fs_la_OBJECTS = $(am__objects_2)
libstdc__fs_la_OBJECTS = $(am_libstdc__fs_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
@ENABLE_DUAL_ABI_TRUE@cxx11_abi_sources = \
@ENABLE_DUAL_ABI_TRUE@ cow-dir.cc \
@ENABLE_DUAL_ABI_TRUE@ cow-ops.cc \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.cc \
-@ENABLE_DUAL_ABI_TRUE@ cow-std-dir.cc \
-@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.cc
+@ENABLE_DUAL_ABI_TRUE@ cow-path.cc
sources = \
dir.cc \
ops.cc \
path.cc \
- std-dir.cc \
- std-ops.cc \
${cxx11_abi_sources}
+++ /dev/null
-// Class filesystem::directory_entry etc. -*- C++ -*-
-
-// Copyright (C) 2015-2019 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-#define _GLIBCXX_USE_CXX11_ABI 0
-#include "std-dir.cc"
+++ /dev/null
-// Filesystem operations -*- C++ -*-
-
-// Copyright (C) 2015-2019 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-#define _GLIBCXX_USE_CXX11_ABI 0
-#include "std-ops.cc"
#define _GLIBCXX_DIR_COMMON_H 1
#include <string.h> // strcmp
+#include <errno.h>
#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
#include <wchar.h> // wcscmp
#endif
# include <sys/types.h>
# endif
# include <dirent.h>
-#else
-# error "the <dirent.h> header is needed to build the Filesystem TS"
#endif
namespace std _GLIBCXX_VISIBILITY(default)
inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); }
inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); }
inline int closedir(DIR* dir) { return ::_wclosedir(dir); }
-#else
+#elif defined _GLIBCXX_HAVE_DIRENT_H
using char_type = char;
using DIR = ::DIR;
typedef struct ::dirent dirent;
using ::opendir;
using ::readdir;
using ::closedir;
+#else
+using char_type = char;
+struct dirent { const char* d_name; };
+struct DIR { };
+inline DIR* opendir(const char*) { return nullptr; }
+inline dirent* readdir(DIR*) { return nullptr; }
+inline int closedir(DIR*) { return -1; }
#endif
} // namespace __gnu_posix
#endif
#include <experimental/filesystem>
+
+#ifndef _GLIBCXX_HAVE_DIRENT_H
+# error "the <dirent.h> header is needed to build the Filesystem TS"
+#endif
+
#include <utility>
#include <stack>
#include <string.h>
# include <wchar.h>
#endif
+#ifdef NEED_DO_COPY_FILE
+# include <filesystem>
+# include <ext/stdio_filebuf.h>
+# ifdef _GLIBCXX_USE_SENDFILE
+# include <sys/sendfile.h> // sendfile
+# endif
+#endif
+
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
return ret;
}
using char_type = wchar_t;
-#else // _GLIBCXX_FILESYSTEM_IS_WINDOWS
+#elif defined _GLIBCXX_HAVE_UNISTD_H
using ::open;
using ::close;
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+# ifdef _GLIBCXX_HAVE_SYS_STAT_H
typedef struct ::stat stat_type;
using ::stat;
+# ifdef _GLIBCXX_USE_LSTAT
using ::lstat;
-#endif
+# else
+ inline int lstat(const char* path, stat_type* buffer)
+ { return stat(path, buffer); }
+# endif
+# endif
using ::mode_t;
using ::chmod;
using ::mkdir;
using ::getcwd;
using ::chdir;
-#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_USE_UTIME
using ::utimbuf;
using ::utime;
-#endif
+# endif
using ::rename;
using ::truncate;
using char_type = char;
+#else // ! _GLIBCXX_FILESYSTEM_IS_WINDOWS && ! _GLIBCXX_HAVE_UNISTD_H
+ inline int open(const char*, int, ...) { errno = ENOTSUP; return -1; }
+ inline int close(int) { errno = ENOTSUP; return -1; }
+ using mode_t = int;
+ inline int chmod(const char*, mode_t) { errno = ENOTSUP; return -1; }
+ inline int mkdir(const char*, mode_t) { errno = ENOTSUP; return -1; }
+ inline char* getcwd(char*, size_t) { errno = ENOTSUP; return nullptr; }
+ inline int chdir(const char*) { errno = ENOTSUP; return -1; }
+ inline int rename(const char*, const char*) { errno = ENOTSUP; return -1; }
+ inline int truncate(const char*, long) { errno = ENOTSUP; return -1; }
+ using char_type = char;
#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
} // namespace __gnu_posix
bool skip, update, overwrite;
};
- bool
- do_copy_file(const __gnu_posix::char_type* from,
- const __gnu_posix::char_type* to,
- copy_options_existing_file options,
- stat_type* from_st, stat_type* to_st,
- std::error_code& ec) noexcept;
-
- void
- do_space(const __gnu_posix::char_type* pathname,
- uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
- std::error_code&);
-
#endif // _GLIBCXX_HAVE_SYS_STAT_H
} // namespace filesystem
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
using std::filesystem::__gnu_posix::stat_type;
+ using std::filesystem::__gnu_posix::char_type;
+
+ bool
+ do_copy_file(const char_type* from, const char_type* to,
+ std::filesystem::copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept;
+
+ void
+ do_space(const char_type* pathname,
+ uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
+ std::error_code&);
+
inline file_type
make_file_type(const stat_type& st) noexcept
is_set(opt, copy_options::overwrite_existing)
};
}
+
+#ifdef NEED_DO_COPY_FILE
+ bool
+ do_copy_file(const char_type* from, const char_type* to,
+ std::filesystem::copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept
+ {
+ namespace fs = std::filesystem;
+ namespace posix = fs::__gnu_posix;
+
+ stat_type st1, st2;
+ file_status t, f;
+
+ if (to_st == nullptr)
+ {
+ if (posix::stat(to, &st1))
+ {
+ const int err = errno;
+ if (!fs::is_not_found_errno(err))
+ {
+ ec.assign(err, std::generic_category());
+ return false;
+ }
+ }
+ else
+ to_st = &st1;
+ }
+ else if (to_st == from_st)
+ to_st = nullptr;
+
+ if (to_st == nullptr)
+ t = file_status{file_type::not_found};
+ else
+ t = make_file_status(*to_st);
+
+ if (from_st == nullptr)
+ {
+ if (posix::stat(from, &st2))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ else
+ from_st = &st2;
+ }
+ f = make_file_status(*from_st);
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2712. copy_file() has a number of unspecified error conditions
+ if (!is_regular_file(f))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+
+ if (exists(t))
+ {
+ if (!is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+
+ if (to_st->st_dev == from_st->st_dev
+ && to_st->st_ino == from_st->st_ino)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return false;
+ }
+
+ if (options.skip)
+ {
+ ec.clear();
+ return false;
+ }
+ else if (options.update)
+ {
+ const auto from_mtime = fs::file_time(*from_st, ec);
+ if (ec)
+ return false;
+ if ((from_mtime <= fs::file_time(*to_st, ec)) || ec)
+ return false;
+ }
+ else if (!options.overwrite)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return false;
+ }
+ else if (!is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+ }
+
+ struct CloseFD {
+ ~CloseFD() { if (fd != -1) posix::close(fd); }
+ bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
+ int fd;
+ };
+
+ CloseFD in = { posix::open(from, O_RDONLY) };
+ if (in.fd == -1)
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ int oflag = O_WRONLY|O_CREAT;
+ if (options.overwrite || options.update)
+ oflag |= O_TRUNC;
+ else
+ oflag |= O_EXCL;
+ CloseFD out = { posix::open(to, oflag, S_IWUSR) };
+ if (out.fd == -1)
+ {
+ if (errno == EEXIST && options.skip)
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+#if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (::fchmod(out.fd, from_st->st_mode))
+#elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
+#else
+ if (posix::chmod(to, from_st->st_mode))
+#endif
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+ size_t count = from_st->st_size;
+#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ off_t offset = 0;
+ ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
+ if (n < 0 && errno != ENOSYS && errno != EINVAL)
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ if ((size_t)n == count)
+ {
+ if (!out.close() || !in.close())
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ ec.clear();
+ return true;
+ }
+ else if (n > 0)
+ count -= n;
+#endif // _GLIBCXX_USE_SENDFILE
+
+ using std::ios;
+ __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
+ __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
+
+ if (sbin.is_open())
+ in.fd = -1;
+ if (sbout.is_open())
+ out.fd = -1;
+
+#ifdef _GLIBCXX_USE_SENDFILE
+ if (n != 0)
+ {
+ if (n < 0)
+ n = 0;
+
+ const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in);
+ const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out);
+
+ const std::streampos errpos(std::streamoff(-1));
+ if (p1 == errpos || p2 == errpos)
+ {
+ ec = std::make_error_code(std::errc::io_error);
+ return false;
+ }
+ }
+#endif
+
+ if (count && !(std::ostream(&sbout) << &sbin))
+ {
+ ec = std::make_error_code(std::errc::io_error);
+ return false;
+ }
+ if (!sbout.close() || !sbin.close())
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ ec.clear();
+ return true;
+ }
+#endif // NEED_DO_COPY_FILE
+
+#ifdef NEED_DO_SPACE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+ void
+ do_space(const char_type* pathname,
+ uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
+ std::error_code& ec)
+ {
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+ struct ::statvfs f;
+ if (::statvfs(pathname, &f))
+ ec.assign(errno, std::generic_category());
+ else
+ {
+ if (f.f_frsize != (unsigned long)-1)
+ {
+ const uintmax_t fragment_size = f.f_frsize;
+ const fsblkcnt_t unknown = -1;
+ if (f.f_blocks != unknown)
+ capacity = f.f_blocks * fragment_size;
+ if (f.f_bfree != unknown)
+ free = f.f_bfree * fragment_size;
+ if (f.f_bavail != unknown)
+ available = f.f_bavail * fragment_size;
+ }
+ ec.clear();
+ }
+#elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
+ if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
+ {
+ if (bytes_total.QuadPart != 0)
+ capacity = bytes_total.QuadPart;
+ if (bytes_free.QuadPart != 0)
+ free = bytes_free.QuadPart;
+ if (bytes_avail.QuadPart != 0)
+ available = bytes_avail.QuadPart;
+ ec.clear();
+ }
+ else
+ ec.assign((int)GetLastError(), std::system_category());
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ }
+#pragma GCC diagnostic pop
+#endif // NEED_DO_SPACE
+
#endif // _GLIBCXX_HAVE_SYS_STAT_H
_GLIBCXX_END_NAMESPACE_FILESYSTEM
#ifndef _GLIBCXX_USE_CXX11_ABI
# define _GLIBCXX_USE_CXX11_ABI 1
+# define NEED_DO_COPY_FILE
+# define NEED_DO_SPACE
#endif
#include <experimental/filesystem>
using std::filesystem::is_not_found_errno;
using std::filesystem::file_time;
- using std::filesystem::do_copy_file;
#endif // _GLIBCXX_HAVE_SYS_STAT_H
} // namespace
#else
auto str = p.c_str();
#endif
- std::filesystem::do_space(str, info.capacity, info.free, info.available, ec);
+ fs::do_space(str, info.capacity, info.free, info.available, ec);
return info;
}
+++ /dev/null
-// Class filesystem::directory_entry etc. -*- C++ -*-
-
-// Copyright (C) 2014-2019 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-#ifndef _GLIBCXX_USE_CXX11_ABI
-# define _GLIBCXX_USE_CXX11_ABI 1
-#endif
-
-#include <filesystem>
-#include <experimental/filesystem>
-#include <utility>
-#include <stack>
-#include <string.h>
-#include <errno.h>
-#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
-#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
-#include "dir-common.h"
-
-namespace fs = std::filesystem;
-namespace posix = std::filesystem::__gnu_posix;
-
-template class std::__shared_ptr<fs::_Dir>;
-template class std::__shared_ptr<fs::recursive_directory_iterator::_Dir_stack>;
-
-struct fs::_Dir : _Dir_base
-{
- _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
- : _Dir_base(p.c_str(), skip_permission_denied, ec)
- {
- if (!ec)
- path = p;
- }
-
- _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
-
- _Dir(_Dir&&) = default;
-
- // Returns false when the end of the directory entries is reached.
- // Reports errors by setting ec.
- bool advance(bool skip_permission_denied, error_code& ec) noexcept
- {
- if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
- {
- auto name = path;
- name /= entp->d_name;
- entry = fs::directory_entry{std::move(name), get_file_type(*entp)};
- return true;
- }
- else if (!ec)
- {
- // reached the end
- entry = {};
- }
- return false;
- }
-
- bool advance(error_code& ec) noexcept { return advance(false, ec); }
-
- // Returns false when the end of the directory entries is reached.
- // Reports errors by throwing.
- bool advance(bool skip_permission_denied = false)
- {
- error_code ec;
- const bool ok = advance(skip_permission_denied, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "directory iterator cannot advance", ec));
- return ok;
- }
-
- bool should_recurse(bool follow_symlink, error_code& ec) const
- {
- file_type type = entry._M_type;
- if (type == file_type::none || type == file_type::unknown)
- {
- type = entry.symlink_status(ec).type();
- if (ec)
- return false;
- }
-
- if (type == file_type::directory)
- return true;
- if (type == file_type::symlink)
- return follow_symlink && is_directory(entry.status(ec));
- return false;
- }
-
- fs::path path;
- directory_entry entry;
-};
-
-namespace
-{
- template<typename Bitmask>
- inline bool
- is_set(Bitmask obj, Bitmask bits)
- {
- return (obj & bits) != Bitmask::none;
- }
-}
-
-fs::directory_iterator::
-directory_iterator(const path& p, directory_options options, error_code* ecptr)
-{
- const bool skip_permission_denied
- = is_set(options, directory_options::skip_permission_denied);
-
- error_code ec;
- _Dir dir(p, skip_permission_denied, ec);
-
- if (dir.dirp)
- {
- auto sp = std::__make_shared<fs::_Dir>(std::move(dir));
- if (sp->advance(skip_permission_denied, ec))
- _M_dir.swap(sp);
- }
- if (ecptr)
- *ecptr = ec;
- else if (ec)
- _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
- "directory iterator cannot open directory", p, ec));
-}
-
-const fs::directory_entry&
-fs::directory_iterator::operator*() const
-{
- if (!_M_dir)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "non-dereferenceable directory iterator",
- std::make_error_code(errc::invalid_argument)));
- return _M_dir->entry;
-}
-
-fs::directory_iterator&
-fs::directory_iterator::operator++()
-{
- if (!_M_dir)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "cannot advance non-dereferenceable directory iterator",
- std::make_error_code(errc::invalid_argument)));
- if (!_M_dir->advance())
- _M_dir.reset();
- return *this;
-}
-
-fs::directory_iterator&
-fs::directory_iterator::increment(error_code& ec)
-{
- if (!_M_dir)
- {
- ec = std::make_error_code(errc::invalid_argument);
- return *this;
- }
- if (!_M_dir->advance(ec))
- _M_dir.reset();
- return *this;
-}
-
-struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
-{
- void clear() { c.clear(); }
-};
-
-fs::recursive_directory_iterator::
-recursive_directory_iterator(const path& p, directory_options options,
- error_code* ecptr)
-: _M_options(options), _M_pending(true)
-{
- if (posix::DIR* dirp = posix::opendir(p.c_str()))
- {
- if (ecptr)
- ecptr->clear();
- auto sp = std::__make_shared<_Dir_stack>();
- sp->push(_Dir{ dirp, p });
- if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance())
- _M_dirs.swap(sp);
- }
- else
- {
- const int err = errno;
- if (err == EACCES
- && is_set(options, fs::directory_options::skip_permission_denied))
- {
- if (ecptr)
- ecptr->clear();
- return;
- }
-
- if (!ecptr)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "recursive directory iterator cannot open directory", p,
- std::error_code(err, std::generic_category())));
-
- ecptr->assign(err, std::generic_category());
- }
-}
-
-fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
-
-int
-fs::recursive_directory_iterator::depth() const
-{
- return int(_M_dirs->size()) - 1;
-}
-
-const fs::directory_entry&
-fs::recursive_directory_iterator::operator*() const
-{
- return _M_dirs->top().entry;
-}
-
-fs::recursive_directory_iterator&
-fs::recursive_directory_iterator::
-operator=(const recursive_directory_iterator& other) noexcept = default;
-
-fs::recursive_directory_iterator&
-fs::recursive_directory_iterator::
-operator=(recursive_directory_iterator&& other) noexcept = default;
-
-fs::recursive_directory_iterator&
-fs::recursive_directory_iterator::operator++()
-{
- error_code ec;
- increment(ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "cannot increment recursive directory iterator", ec));
- return *this;
-}
-
-fs::recursive_directory_iterator&
-fs::recursive_directory_iterator::increment(error_code& ec)
-{
- if (!_M_dirs)
- {
- ec = std::make_error_code(errc::invalid_argument);
- return *this;
- }
-
- const bool follow
- = is_set(_M_options, directory_options::follow_directory_symlink);
- const bool skip_permission_denied
- = is_set(_M_options, directory_options::skip_permission_denied);
-
- auto& top = _M_dirs->top();
-
- if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
- {
- _Dir dir(top.entry.path(), skip_permission_denied, ec);
- if (ec)
- {
- _M_dirs.reset();
- return *this;
- }
- if (dir.dirp)
- _M_dirs->push(std::move(dir));
- }
-
- while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
- {
- _M_dirs->pop();
- if (_M_dirs->empty())
- {
- _M_dirs.reset();
- return *this;
- }
- }
- return *this;
-}
-
-void
-fs::recursive_directory_iterator::pop(error_code& ec)
-{
- if (!_M_dirs)
- {
- ec = std::make_error_code(errc::invalid_argument);
- return;
- }
-
- const bool skip_permission_denied
- = is_set(_M_options, directory_options::skip_permission_denied);
-
- do {
- _M_dirs->pop();
- if (_M_dirs->empty())
- {
- _M_dirs.reset();
- ec.clear();
- return;
- }
- } while (!_M_dirs->top().advance(skip_permission_denied, ec));
-}
-
-void
-fs::recursive_directory_iterator::pop()
-{
- error_code ec;
- pop(ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
- ? "recursive directory iterator cannot pop"
- : "non-dereferenceable recursive directory iterator cannot pop",
- ec));
-}
+++ /dev/null
-// Filesystem operations -*- C++ -*-
-
-// Copyright (C) 2014-2019 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-#ifndef _GLIBCXX_USE_CXX11_ABI
-# define _GLIBCXX_USE_CXX11_ABI 1
-# define NEED_DO_COPY_FILE
-# define NEED_DO_SPACE
-#endif
-
-#include <filesystem>
-#include <experimental/filesystem>
-#include <functional>
-#include <ostream>
-#include <stack>
-#include <ext/stdio_filebuf.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <limits.h> // PATH_MAX
-#ifdef _GLIBCXX_HAVE_FCNTL_H
-# include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
-#endif
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
-# include <sys/stat.h> // stat, utimensat, fchmodat
-#endif
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
-# include <sys/statvfs.h> // statvfs
-#endif
-#ifdef _GLIBCXX_USE_SENDFILE
-# include <sys/sendfile.h> // sendfile
-#endif
-#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
-# include <utime.h> // utime
-#endif
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# include <windows.h>
-#endif
-
-#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
-#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
-#include "ops-common.h"
-
-namespace fs = std::filesystem;
-namespace posix = std::filesystem::__gnu_posix;
-
-fs::path
-fs::absolute(const path& p)
-{
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- error_code ec;
- path ret = absolute(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
- ec));
- return ret;
-#else
- return current_path() / p;
-#endif
-}
-
-fs::path
-fs::absolute(const path& p, error_code& ec)
-{
- path ret;
- if (p.empty())
- {
- ec = make_error_code(std::errc::no_such_file_or_directory);
- return ret;
- }
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- const wstring& s = p.native();
- uint32_t len = 1024;
- wstring buf;
- do
- {
- buf.resize(len);
- len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr);
- }
- while (len > buf.size());
-
- if (len == 0)
- ec.assign((int)GetLastError(), std::system_category());
- else
- {
- ec.clear();
- buf.resize(len);
- ret = std::move(buf);
- }
-#else
- ec.clear();
- ret = current_path();
- ret /= p;
-#endif
- return ret;
-}
-
-namespace
-{
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- inline bool is_dot(wchar_t c) { return c == L'.'; }
-#else
- inline bool is_dot(char c) { return c == '.'; }
-#endif
-
- inline bool is_dot(const fs::path& path)
- {
- const auto& filename = path.native();
- return filename.size() == 1 && is_dot(filename[0]);
- }
-
- inline bool is_dotdot(const fs::path& path)
- {
- const auto& filename = path.native();
- return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
- }
-
- struct free_as_in_malloc
- {
- void operator()(void* p) const { ::free(p); }
- };
-
- using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
-}
-
-fs::path
-fs::canonical(const path& p, error_code& ec)
-{
- path result;
- const path pa = absolute(p, ec);
- if (ec)
- return result;
-
-#ifdef _GLIBCXX_USE_REALPATH
- char_ptr buf{ nullptr };
-# if _XOPEN_VERSION < 700
- // Not safe to call realpath(path, NULL)
- using char_type = fs::path::value_type;
- buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
-# endif
- if (char* rp = ::realpath(pa.c_str(), buf.get()))
- {
- if (buf == nullptr)
- buf.reset(rp);
- result.assign(rp);
- ec.clear();
- return result;
- }
- if (errno != ENAMETOOLONG)
- {
- ec.assign(errno, std::generic_category());
- return result;
- }
-#endif
-
- if (!exists(pa, ec))
- {
- if (!ec)
- ec = make_error_code(std::errc::no_such_file_or_directory);
- return result;
- }
- // else: we know there are (currently) no unresolvable symlink loops
-
- result = pa.root_path();
-
- deque<path> cmpts;
- for (auto& f : pa.relative_path())
- cmpts.push_back(f);
-
- int max_allowed_symlinks = 40;
-
- while (!cmpts.empty() && !ec)
- {
- path f = std::move(cmpts.front());
- cmpts.pop_front();
-
- if (f.empty())
- {
- // ignore empty element
- }
- else if (is_dot(f))
- {
- if (!is_directory(result, ec) && !ec)
- ec.assign(ENOTDIR, std::generic_category());
- }
- else if (is_dotdot(f))
- {
- auto parent = result.parent_path();
- if (parent.empty())
- result = pa.root_path();
- else
- result.swap(parent);
- }
- else
- {
- result /= f;
-
- if (is_symlink(result, ec))
- {
- path link = read_symlink(result, ec);
- if (!ec)
- {
- if (--max_allowed_symlinks == 0)
- ec.assign(ELOOP, std::generic_category());
- else
- {
- if (link.is_absolute())
- {
- result = link.root_path();
- link = link.relative_path();
- }
- else
- result = result.parent_path();
-
- cmpts.insert(cmpts.begin(), link.begin(), link.end());
- }
- }
- }
- }
- }
-
- if (ec || !exists(result, ec))
- result.clear();
-
- return result;
-}
-
-fs::path
-fs::canonical(const path& p)
-{
- error_code ec;
- path res = canonical(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
- p, ec));
- return res;
-}
-
-void
-fs::copy(const path& from, const path& to, copy_options options)
-{
- error_code ec;
- copy(from, to, options, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
-}
-
-namespace std::filesystem
-{
- // Need this as there's no 'perm_options::none' enumerator.
- static inline bool is_set(fs::perm_options obj, fs::perm_options bits)
- {
- return (obj & bits) != fs::perm_options{};
- }
-}
-
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
-
-namespace
-{
- struct internal_file_clock : fs::__file_clock
- {
- using __file_clock::_S_to_sys;
- using __file_clock::_S_from_sys;
-
- static fs::file_time_type
- from_stat(const fs::stat_type& st, std::error_code& ec) noexcept
- {
- const auto sys_time = fs::file_time(st, ec);
- if (sys_time == sys_time.min())
- return fs::file_time_type::min();
- return _S_from_sys(sys_time);
- }
- };
-}
-
-#ifdef NEED_DO_COPY_FILE
-bool
-fs::do_copy_file(const path::value_type* from, const path::value_type* to,
- copy_options_existing_file options,
- stat_type* from_st, stat_type* to_st,
- std::error_code& ec) noexcept
-{
- stat_type st1, st2;
- fs::file_status t, f;
-
- if (to_st == nullptr)
- {
- if (posix::stat(to, &st1))
- {
- const int err = errno;
- if (!is_not_found_errno(err))
- {
- ec.assign(err, std::generic_category());
- return false;
- }
- }
- else
- to_st = &st1;
- }
- else if (to_st == from_st)
- to_st = nullptr;
-
- if (to_st == nullptr)
- t = fs::file_status{fs::file_type::not_found};
- else
- t = make_file_status(*to_st);
-
- if (from_st == nullptr)
- {
- if (posix::stat(from, &st2))
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- else
- from_st = &st2;
- }
- f = make_file_status(*from_st);
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2712. copy_file() has a number of unspecified error conditions
- if (!is_regular_file(f))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
-
- if (exists(t))
- {
- if (!is_regular_file(t))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
-
- if (to_st->st_dev == from_st->st_dev
- && to_st->st_ino == from_st->st_ino)
- {
- ec = std::make_error_code(std::errc::file_exists);
- return false;
- }
-
- if (options.skip)
- {
- ec.clear();
- return false;
- }
- else if (options.update)
- {
- const auto from_mtime = internal_file_clock::from_stat(*from_st, ec);
- if (ec)
- return false;
- if ((from_mtime <= internal_file_clock::from_stat(*to_st, ec)) || ec)
- return false;
- }
- else if (!options.overwrite)
- {
- ec = std::make_error_code(std::errc::file_exists);
- return false;
- }
- else if (!is_regular_file(t))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
- }
-
- struct CloseFD {
- ~CloseFD() { if (fd != -1) posix::close(fd); }
- bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
- int fd;
- };
-
- CloseFD in = { posix::open(from, O_RDONLY) };
- if (in.fd == -1)
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- int oflag = O_WRONLY|O_CREAT;
- if (options.overwrite || options.update)
- oflag |= O_TRUNC;
- else
- oflag |= O_EXCL;
- CloseFD out = { posix::open(to, oflag, S_IWUSR) };
- if (out.fd == -1)
- {
- if (errno == EEXIST && options.skip)
- ec.clear();
- else
- ec.assign(errno, std::generic_category());
- return false;
- }
-
-#if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (::fchmod(out.fd, from_st->st_mode))
-#elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
-#else
- if (posix::chmod(to, from_st->st_mode))
-#endif
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
-
- size_t count = from_st->st_size;
-#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
- off_t offset = 0;
- ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
- if (n < 0 && errno != ENOSYS && errno != EINVAL)
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- if ((size_t)n == count)
- {
- if (!out.close() || !in.close())
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- ec.clear();
- return true;
- }
- else if (n > 0)
- count -= n;
-#endif // _GLIBCXX_USE_SENDFILE
-
- using std::ios;
- __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
- __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
-
- if (sbin.is_open())
- in.fd = -1;
- if (sbout.is_open())
- out.fd = -1;
-
-#ifdef _GLIBCXX_USE_SENDFILE
- if (n != 0)
- {
- if (n < 0)
- n = 0;
-
- const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in);
- const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out);
-
- const std::streampos errpos(std::streamoff(-1));
- if (p1 == errpos || p2 == errpos)
- {
- ec = std::make_error_code(std::errc::io_error);
- return false;
- }
- }
-#endif
-
- if (count && !(std::ostream(&sbout) << &sbin))
- {
- ec = std::make_error_code(std::errc::io_error);
- return false;
- }
- if (!sbout.close() || !sbin.close())
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- ec.clear();
- return true;
-}
-#endif // NEED_DO_COPY_FILE
-#endif // _GLIBCXX_HAVE_SYS_STAT_H
-
-void
-fs::copy(const path& from, const path& to, copy_options options,
- error_code& ec)
-{
- const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
- const bool create_symlinks = is_set(options, copy_options::create_symlinks);
- const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
- const bool use_lstat = create_symlinks || skip_symlinks;
-
- file_status f, t;
- stat_type from_st, to_st;
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2681. filesystem::copy() cannot copy symlinks
- if (use_lstat || copy_symlinks
- ? posix::lstat(from.c_str(), &from_st)
- : posix::stat(from.c_str(), &from_st))
- {
- ec.assign(errno, std::generic_category());
- return;
- }
- if (use_lstat
- ? posix::lstat(to.c_str(), &to_st)
- : posix::stat(to.c_str(), &to_st))
- {
- if (!is_not_found_errno(errno))
- {
- ec.assign(errno, std::generic_category());
- return;
- }
- t = file_status{file_type::not_found};
- }
- else
- t = make_file_status(to_st);
- f = make_file_status(from_st);
-
- if (exists(t) && !is_other(t) && !is_other(f)
- && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
- {
- ec = std::make_error_code(std::errc::file_exists);
- return;
- }
- if (is_other(f) || is_other(t))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return;
- }
- if (is_directory(f) && is_regular_file(t))
- {
- ec = std::make_error_code(std::errc::is_a_directory);
- return;
- }
-
- if (is_symlink(f))
- {
- if (skip_symlinks)
- ec.clear();
- else if (!exists(t) && copy_symlinks)
- copy_symlink(from, to, ec);
- else
- // Not clear what should be done here.
- // "Otherwise report an error as specified in Error reporting (7)."
- ec = std::make_error_code(std::errc::invalid_argument);
- }
- else if (is_regular_file(f))
- {
- if (is_set(options, copy_options::directories_only))
- ec.clear();
- else if (create_symlinks)
- create_symlink(from, to, ec);
- else if (is_set(options, copy_options::create_hard_links))
- create_hard_link(from, to, ec);
- else if (is_directory(t))
- do_copy_file(from.c_str(), (to / from.filename()).c_str(),
- copy_file_options(options), &from_st, nullptr, ec);
- else
- {
- auto ptr = exists(t) ? &to_st : &from_st;
- do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
- &from_st, ptr, ec);
- }
- }
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2682. filesystem::copy() won't create a symlink to a directory
- else if (is_directory(f) && create_symlinks)
- ec = std::make_error_code(errc::is_a_directory);
- else if (is_directory(f) && (is_set(options, copy_options::recursive)
- || options == copy_options::none))
- {
- if (!exists(t))
- if (!create_directory(to, from, ec))
- return;
- // set an unused bit in options to disable further recursion
- if (!is_set(options, copy_options::recursive))
- options |= static_cast<copy_options>(4096);
- for (const directory_entry& x : directory_iterator(from))
- copy(x.path(), to/x.path().filename(), options, ec);
- }
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2683. filesystem::copy() says "no effects"
- else
- ec.clear();
-}
-
-bool
-fs::copy_file(const path& from, const path& to, copy_options option)
-{
- error_code ec;
- bool result = copy_file(from, to, option, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
- ec));
- return result;
-}
-
-bool
-fs::copy_file(const path& from, const path& to, copy_options options,
- error_code& ec)
-{
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
- nullptr, nullptr, ec);
-#else
- ec = std::make_error_code(std::errc::not_supported);
- return false;
-#endif
-}
-
-
-void
-fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
-{
- error_code ec;
- copy_symlink(existing_symlink, new_symlink, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
- existing_symlink, new_symlink, ec));
-}
-
-void
-fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
- error_code& ec) noexcept
-{
- auto p = read_symlink(existing_symlink, ec);
- if (ec)
- return;
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (is_directory(p))
- {
- create_directory_symlink(p, new_symlink, ec);
- return;
- }
-#endif
- create_symlink(p, new_symlink, ec);
-}
-
-
-bool
-fs::create_directories(const path& p)
-{
- error_code ec;
- bool result = create_directories(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
- ec));
- return result;
-}
-
-bool
-fs::create_directories(const path& p, error_code& ec)
-{
- if (p.empty())
- {
- ec = std::make_error_code(errc::invalid_argument);
- return false;
- }
-
- file_status st = symlink_status(p, ec);
- if (is_directory(st))
- return false;
- else if (ec && !status_known(st))
- return false;
- else if (exists(st))
- {
- if (!ec)
- ec = std::make_error_code(std::errc::not_a_directory);
- return false;
- }
-
- std::stack<path> missing;
- path pp = p;
-
- // Strip any trailing slash
- if (pp.has_relative_path() && !pp.has_filename())
- pp = pp.parent_path();
-
- do
- {
- const auto& filename = pp.filename();
- if (is_dot(filename) || is_dotdot(filename))
- pp = pp.parent_path();
- else
- {
- missing.push(std::move(pp));
- if (missing.size() > 1000) // sanity check
- {
- ec = std::make_error_code(std::errc::filename_too_long);
- return false;
- }
- pp = missing.top().parent_path();
- }
-
- if (pp.empty())
- break;
-
- st = status(pp, ec);
- if (exists(st))
- {
- if (ec)
- return false;
- if (!is_directory(st))
- {
- ec = std::make_error_code(std::errc::not_a_directory);
- return false;
- }
- }
-
- if (ec && exists(st))
- return false;
- }
- while (st.type() == file_type::not_found);
-
- bool created;
- do
- {
- const path& top = missing.top();
- created = create_directory(top, ec);
- if (ec)
- return false;
- missing.pop();
- }
- while (!missing.empty());
-
- return created;
-}
-
-namespace
-{
- bool
- create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
- {
- bool created = false;
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- posix::mode_t mode
- = static_cast<std::underlying_type_t<fs::perms>>(perm);
- if (posix::mkdir(p.c_str(), mode))
- {
- const int err = errno;
- if (err != EEXIST || !is_directory(p, ec))
- ec.assign(err, std::generic_category());
- }
- else
- {
- ec.clear();
- created = true;
- }
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
- return created;
- }
-} // namespace
-
-bool
-fs::create_directory(const path& p)
-{
- error_code ec;
- bool result = create_directory(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
- ec));
- return result;
-}
-
-bool
-fs::create_directory(const path& p, error_code& ec) noexcept
-{
- return create_dir(p, perms::all, ec);
-}
-
-
-bool
-fs::create_directory(const path& p, const path& attributes)
-{
- error_code ec;
- bool result = create_directory(p, attributes, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
- ec));
- return result;
-}
-
-bool
-fs::create_directory(const path& p, const path& attributes,
- error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- stat_type st;
- if (posix::stat(attributes.c_str(), &st))
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- return create_dir(p, static_cast<perms>(st.st_mode), ec);
-#else
- ec = std::make_error_code(std::errc::not_supported);
- return false;
-#endif
-}
-
-
-void
-fs::create_directory_symlink(const path& to, const path& new_symlink)
-{
- error_code ec;
- create_directory_symlink(to, new_symlink, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
- to, new_symlink, ec));
-}
-
-void
-fs::create_directory_symlink(const path& to, const path& new_symlink,
- error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- ec = std::make_error_code(std::errc::not_supported);
-#else
- create_symlink(to, new_symlink, ec);
-#endif
-}
-
-
-void
-fs::create_hard_link(const path& to, const path& new_hard_link)
-{
- error_code ec;
- create_hard_link(to, new_hard_link, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
- to, new_hard_link, ec));
-}
-
-void
-fs::create_hard_link(const path& to, const path& new_hard_link,
- error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_LINK
- if (::link(to.c_str(), new_hard_link.c_str()))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
- ec.clear();
- else
- ec.assign((int)GetLastError(), generic_category());
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-
-void
-fs::create_symlink(const path& to, const path& new_symlink)
-{
- error_code ec;
- create_symlink(to, new_symlink, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
- to, new_symlink, ec));
-}
-
-void
-fs::create_symlink(const path& to, const path& new_symlink,
- error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_SYMLINK
- if (::symlink(to.c_str(), new_symlink.c_str()))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-
-
-fs::path
-fs::current_path()
-{
- error_code ec;
- path p = current_path(ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
- return p;
-}
-
-fs::path
-fs::current_path(error_code& ec)
-{
- path p;
-#ifdef _GLIBCXX_HAVE_UNISTD_H
-#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
- {
- p.assign(cwd.get());
- ec.clear();
- }
- else
- ec.assign(errno, std::generic_category());
-#else
-#ifdef _PC_PATH_MAX
- long path_max = pathconf(".", _PC_PATH_MAX);
- size_t size;
- if (path_max == -1)
- size = 1024;
- else if (path_max > 10240)
- size = 10240;
- else
- size = path_max;
-#elif defined(PATH_MAX)
- size_t size = PATH_MAX;
-#else
- size_t size = 1024;
-#endif
- for (char_ptr buf; p.empty(); size *= 2)
- {
- using char_type = fs::path::value_type;
- buf.reset((char_type*)malloc(size * sizeof(char_type)));
- if (buf)
- {
- if (getcwd(buf.get(), size))
- {
- p.assign(buf.get());
- ec.clear();
- }
- else if (errno != ERANGE)
- {
- ec.assign(errno, std::generic_category());
- return {};
- }
- }
- else
- {
- ec = std::make_error_code(std::errc::not_enough_memory);
- return {};
- }
- }
-#endif // __GLIBC__
-#else // _GLIBCXX_HAVE_UNISTD_H
- ec = std::make_error_code(std::errc::not_supported);
-#endif
- return p;
-}
-
-void
-fs::current_path(const path& p)
-{
- error_code ec;
- current_path(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
-}
-
-void
-fs::current_path(const path& p, error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
- if (posix::chdir(p.c_str()))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-
-bool
-fs::equivalent(const path& p1, const path& p2)
-{
- error_code ec;
- auto result = equivalent(p1, p2, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
- p1, p2, ec));
- return result;
-}
-
-bool
-fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- int err = 0;
- file_status s1, s2;
- stat_type st1, st2;
- if (posix::stat(p1.c_str(), &st1) == 0)
- s1 = make_file_status(st1);
- else if (is_not_found_errno(errno))
- s1.type(file_type::not_found);
- else
- err = errno;
-
- if (posix::stat(p2.c_str(), &st2) == 0)
- s2 = make_file_status(st2);
- else if (is_not_found_errno(errno))
- s2.type(file_type::not_found);
- else
- err = errno;
-
- if (exists(s1) && exists(s2))
- {
- if (is_other(s1) && is_other(s2))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
- ec.clear();
- if (is_other(s1) || is_other(s2))
- return false;
- return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
- }
- else if (!exists(s1) && !exists(s2))
- ec = std::make_error_code(std::errc::no_such_file_or_directory);
- else if (err)
- ec.assign(err, std::generic_category());
- else
- ec.clear();
- return false;
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
- return false;
-}
-
-std::uintmax_t
-fs::file_size(const path& p)
-{
- error_code ec;
- auto sz = file_size(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
- return sz;
-}
-
-namespace
-{
- template<typename Accessor, typename T>
- inline T
- do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
- {
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- posix::stat_type st;
- if (posix::stat(p.c_str(), &st))
- {
- ec.assign(errno, std::generic_category());
- return deflt;
- }
- ec.clear();
- return f(st);
-#else
- ec = std::make_error_code(std::errc::not_supported);
- return deflt;
-#endif
- }
-}
-
-std::uintmax_t
-fs::file_size(const path& p, error_code& ec) noexcept
-{
- struct S
- {
- S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
- S() : type(file_type::not_found) { }
- file_type type;
- size_t size;
- };
- auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
- if (s.type == file_type::regular)
- return s.size;
- if (!ec)
- {
- if (s.type == file_type::directory)
- ec = std::make_error_code(std::errc::is_a_directory);
- else
- ec = std::make_error_code(std::errc::not_supported);
- }
- return -1;
-}
-
-std::uintmax_t
-fs::hard_link_count(const path& p)
-{
- error_code ec;
- auto count = hard_link_count(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
- return count;
-}
-
-std::uintmax_t
-fs::hard_link_count(const path& p, error_code& ec) noexcept
-{
- return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
- static_cast<uintmax_t>(-1));
-}
-
-bool
-fs::is_empty(const path& p)
-{
- error_code ec;
- bool e = is_empty(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
- p, ec));
- return e;
-}
-
-bool
-fs::is_empty(const path& p, error_code& ec)
-{
- auto s = status(p, ec);
- if (ec)
- return false;
- bool empty = fs::is_directory(s)
- ? fs::directory_iterator(p, ec) == fs::directory_iterator()
- : fs::file_size(p, ec) == 0;
- return ec ? false : empty;
-}
-
-fs::file_time_type
-fs::last_write_time(const path& p)
-{
- error_code ec;
- auto t = last_write_time(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
- return t;
-}
-
-fs::file_time_type
-fs::last_write_time(const path& p, error_code& ec) noexcept
-{
- return do_stat(p, ec,
- [&ec](const auto& st) {
- return internal_file_clock::from_stat(st, ec);
- },
- file_time_type::min());
-}
-
-void
-fs::last_write_time(const path& p, file_time_type new_time)
-{
- error_code ec;
- last_write_time(p, new_time, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
-}
-
-void
-fs::last_write_time(const path& p __attribute__((__unused__)),
- file_time_type new_time, error_code& ec) noexcept
-{
- auto d = internal_file_clock::_S_to_sys(new_time).time_since_epoch();
- auto s = chrono::duration_cast<chrono::seconds>(d);
-#if _GLIBCXX_USE_UTIMENSAT
- auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
- if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
- {
- --s;
- ns += chrono::seconds(1);
- }
- struct ::timespec ts[2];
- ts[0].tv_sec = 0;
- ts[0].tv_nsec = UTIME_OMIT;
- ts[1].tv_sec = static_cast<std::time_t>(s.count());
- ts[1].tv_nsec = static_cast<long>(ns.count());
- if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#elif _GLIBCXX_HAVE_UTIME_H
- posix::utimbuf times;
- times.modtime = s.count();
- times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
- times.modtime);
- if (posix::utime(p.c_str(), ×))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-
-void
-fs::permissions(const path& p, perms prms, perm_options opts)
-{
- error_code ec;
- permissions(p, prms, opts, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
-}
-
-void
-fs::permissions(const path& p, perms prms, perm_options opts,
- error_code& ec) noexcept
-{
- const bool replace = is_set(opts, perm_options::replace);
- const bool add = is_set(opts, perm_options::add);
- const bool remove = is_set(opts, perm_options::remove);
- const bool nofollow = is_set(opts, perm_options::nofollow);
- if (((int)replace + (int)add + (int)remove) != 1)
- {
- ec = std::make_error_code(std::errc::invalid_argument);
- return;
- }
-
- prms &= perms::mask;
-
- file_status st;
- if (add || remove || nofollow)
- {
- st = nofollow ? symlink_status(p, ec) : status(p, ec);
- if (ec)
- return;
- auto curr = st.permissions();
- if (add)
- prms |= curr;
- else if (remove)
- prms = curr & ~prms;
- }
-
- int err = 0;
-#if _GLIBCXX_USE_FCHMODAT
- const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
- if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
- err = errno;
-#else
- if (nofollow && is_symlink(st))
- ec = std::make_error_code(std::errc::operation_not_supported);
- else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
- err = errno;
-#endif
-
- if (err)
- ec.assign(err, std::generic_category());
- else
- ec.clear();
-}
-
-fs::path
-fs::proximate(const path& p, const path& base)
-{
- return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
-}
-
-fs::path
-fs::proximate(const path& p, const path& base, error_code& ec)
-{
- path result;
- const auto p2 = weakly_canonical(p, ec);
- if (!ec)
- {
- const auto base2 = weakly_canonical(base, ec);
- if (!ec)
- result = p2.lexically_proximate(base2);
- }
- return result;
-}
-
-fs::path
-fs::read_symlink(const path& p)
-{
- error_code ec;
- path tgt = read_symlink(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
- return tgt;
-}
-
-fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
-{
- path result;
-#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
- stat_type st;
- if (::lstat(p.c_str(), &st))
- {
- ec.assign(errno, std::generic_category());
- return result;
- }
- std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
- do
- {
- ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
- if (len == -1)
- {
- ec.assign(errno, std::generic_category());
- return result;
- }
- else if (len == (ssize_t)buf.size())
- {
- if (buf.size() > 4096)
- {
- ec.assign(ENAMETOOLONG, std::generic_category());
- return result;
- }
- buf.resize(buf.size() * 2);
- }
- else
- {
- buf.resize(len);
- result.assign(buf);
- ec.clear();
- break;
- }
- }
- while (true);
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
- return result;
-}
-
-fs::path
-fs::relative(const path& p, const path& base)
-{
- return weakly_canonical(p).lexically_relative(weakly_canonical(base));
-}
-
-fs::path
-fs::relative(const path& p, const path& base, error_code& ec)
-{
- auto result = weakly_canonical(p, ec);
- fs::path cbase;
- if (!ec)
- cbase = weakly_canonical(base, ec);
- if (!ec)
- result = result.lexically_relative(cbase);
- if (ec)
- result.clear();
- return result;
-}
-
-bool
-fs::remove(const path& p)
-{
- error_code ec;
- const bool result = fs::remove(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
- return result;
-}
-
-bool
-fs::remove(const path& p, error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- if (exists(symlink_status(p, ec)))
- {
- if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
- || DeleteFileW(p.c_str()))
- {
- ec.clear();
- return true;
- }
- else if (!ec)
- ec.assign((int)GetLastError(), generic_category());
- }
-#else
- if (::remove(p.c_str()) == 0)
- {
- ec.clear();
- return true;
- }
- else if (errno == ENOENT)
- ec.clear();
- else
- ec.assign(errno, std::generic_category());
-#endif
- return false;
-}
-
-
-std::uintmax_t
-fs::remove_all(const path& p)
-{
- error_code ec;
- const auto result = remove_all(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
- return result;
-}
-
-std::uintmax_t
-fs::remove_all(const path& p, error_code& ec)
-{
- const auto s = symlink_status(p, ec);
- if (!status_known(s))
- return -1;
-
- ec.clear();
- if (s.type() == file_type::not_found)
- return 0;
-
- uintmax_t count = 0;
- if (s.type() == file_type::directory)
- {
- for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
- count += fs::remove_all(d->path(), ec);
- if (ec.value() == ENOENT)
- ec.clear();
- else if (ec)
- return -1;
- }
-
- if (fs::remove(p, ec))
- ++count;
- return ec ? -1 : count;
-}
-
-void
-fs::rename(const path& from, const path& to)
-{
- error_code ec;
- rename(from, to, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
-}
-
-void
-fs::rename(const path& from, const path& to, error_code& ec) noexcept
-{
- if (posix::rename(from.c_str(), to.c_str()))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-}
-
-void
-fs::resize_file(const path& p, uintmax_t size)
-{
- error_code ec;
- resize_file(p, size, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
-}
-
-void
-fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
-{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
- if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
- ec.assign(EINVAL, std::generic_category());
- else if (posix::truncate(p.c_str(), size))
- ec.assign(errno, std::generic_category());
- else
- ec.clear();
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-
-
-fs::space_info
-fs::space(const path& p)
-{
- error_code ec;
- space_info s = space(p, ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
- return s;
-}
-
-#ifdef NEED_DO_SPACE
-void
-fs::do_space(const __gnu_posix::char_type* pathname,
- uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
- std::error_code& ec)
-{
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
- struct ::statvfs f;
- if (::statvfs(pathname, &f))
- ec.assign(errno, std::generic_category());
- else
- {
- if (f.f_frsize != (unsigned long)-1)
- {
- const uintmax_t fragment_size = f.f_frsize;
- const fsblkcnt_t unknown = -1;
- if (f.f_blocks != unknown)
- capacity = f.f_blocks * fragment_size;
- if (f.f_bfree != unknown)
- free = f.f_bfree * fragment_size;
- if (f.f_bavail != unknown)
- available = f.f_bavail * fragment_size;
- }
- ec.clear();
- }
-#elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
- ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
- if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
- {
- if (bytes_total.QuadPart != 0)
- capacity = bytes_total.QuadPart;
- if (bytes_free.QuadPart != 0)
- free = bytes_free.QuadPart;
- if (bytes_avail.QuadPart != 0)
- available = bytes_avail.QuadPart;
- ec.clear();
- }
- else
- ec.assign((int)GetLastError(), std::system_category());
-#else
- ec = std::make_error_code(std::errc::not_supported);
-#endif
-}
-#endif // NEED_DO_SPACE
-
-fs::space_info
-fs::space(const path& p, error_code& ec) noexcept
-{
- space_info info = {
- static_cast<uintmax_t>(-1),
- static_cast<uintmax_t>(-1),
- static_cast<uintmax_t>(-1)
- };
-#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
- path dir = absolute(p);
- dir.remove_filename();
- auto str = dir.c_str();
-#else
- auto str = p.c_str();
-#endif
- do_space(str, info.capacity, info.free, info.available, ec);
- return info;
-}
-
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
-fs::file_status
-fs::status(const fs::path& p, error_code& ec) noexcept
-{
- file_status status;
- stat_type st;
- if (posix::stat(p.c_str(), &st))
- {
- int err = errno;
- ec.assign(err, std::generic_category());
- if (is_not_found_errno(err))
- status.type(file_type::not_found);
-#ifdef EOVERFLOW
- else if (err == EOVERFLOW)
- status.type(file_type::unknown);
-#endif
- }
- else
- {
- status = make_file_status(st);
- ec.clear();
- }
- return status;
-}
-
-fs::file_status
-fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
-{
- file_status status;
- stat_type st;
- if (posix::lstat(p.c_str(), &st))
- {
- int err = errno;
- ec.assign(err, std::generic_category());
- if (is_not_found_errno(err))
- status.type(file_type::not_found);
- }
- else
- {
- status = make_file_status(st);
- ec.clear();
- }
- return status;
-}
-#endif
-
-fs::file_status
-fs::status(const fs::path& p)
-{
- std::error_code ec;
- auto result = status(p, ec);
- if (result.type() == file_type::none)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
- return result;
-}
-
-fs::file_status
-fs::symlink_status(const fs::path& p)
-{
- std::error_code ec;
- auto result = symlink_status(p, ec);
- if (result.type() == file_type::none)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
- return result;
-}
-
-fs::path fs::temp_directory_path()
-{
- error_code ec;
- path tmp = temp_directory_path(ec);
- if (ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
- return tmp;
-}
-
-fs::path fs::temp_directory_path(error_code& ec)
-{
- path p;
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- unsigned len = 1024;
- std::wstring buf;
- do
- {
- buf.resize(len);
- len = GetTempPathW(buf.size(), buf.data());
- } while (len > buf.size());
-
- if (len == 0)
- {
- ec.assign((int)GetLastError(), std::system_category());
- return p;
- }
- buf.resize(len);
- p = std::move(buf);
-#else
- const char* tmpdir = nullptr;
- const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
- for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
- tmpdir = ::getenv(*e);
- p = tmpdir ? tmpdir : "/tmp";
-#endif
- auto st = status(p, ec);
- if (ec)
- p.clear();
- else if (!is_directory(st))
- {
- p.clear();
- ec = std::make_error_code(std::errc::not_a_directory);
- }
- return p;
-}
-
-fs::path
-fs::weakly_canonical(const path& p)
-{
- path result;
- if (exists(status(p)))
- return canonical(p);
-
- path tmp;
- auto iter = p.begin(), end = p.end();
- // find leading elements of p that exist:
- while (iter != end)
- {
- tmp = result / *iter;
- if (exists(status(tmp)))
- swap(result, tmp);
- else
- break;
- ++iter;
- }
- // canonicalize:
- if (!result.empty())
- result = canonical(result);
- // append the non-existing elements:
- while (iter != end)
- result /= *iter++;
- // normalize:
- return result.lexically_normal();
-}
-
-fs::path
-fs::weakly_canonical(const path& p, error_code& ec)
-{
- path result;
- file_status st = status(p, ec);
- if (exists(st))
- return canonical(p, ec);
- else if (status_known(st))
- ec.clear();
- else
- return result;
-
- path tmp;
- auto iter = p.begin(), end = p.end();
- // find leading elements of p that exist:
- while (iter != end)
- {
- tmp = result / *iter;
- st = status(tmp, ec);
- if (exists(st))
- swap(result, tmp);
- else
- {
- if (status_known(st))
- ec.clear();
- break;
- }
- ++iter;
- }
- // canonicalize:
- if (!ec && !result.empty())
- result = canonical(result, ec);
- if (ec)
- result.clear();
- else
- {
- // append the non-existing elements:
- while (iter != end)
- result /= *iter++;
- // normalize:
- result = result.lexically_normal();
- }
- return result;
-}
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// { dg-xfail-if "symlinks not supported" { *-*-mingw* } }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// { dg-xfail-if "symlinks not supported" { *-*-mingw* } }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-options "-std=gnu++17" }
// { dg-do run { target c++17 } }
// { dg-require-filesystem-ts "" }