From b3dec9e57e6960cae54187b7fa416052c8e32e19 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 24 Oct 2016 17:45:31 +0100 Subject: [PATCH] Implement DR resolutions for filesystem::copy * src/filesystem/ops.cc (do_copy_file): Return an error if either source or destination is not a regular file. (copy): Update comment to refer to LWG 2681. Implement 2682 and 2683 resolutions. (read_symlink): Add missing ec.clear(). * testsuite/experimental/filesystem/operations/copy.cc: Update expected behaviour for copying directories with create_symlinks. Verify that error_code arguments are cleared if there's no error. * testsuite/experimental/filesystem/operations/read_symlink.cc: New. From-SVN: r241484 --- libstdc++-v3/ChangeLog | 12 +++++ libstdc++-v3/src/filesystem/ops.cc | 23 ++++++++- .../filesystem/operations/copy.cc | 30 +++++++++--- .../filesystem/operations/read_symlink.cc | 49 +++++++++++++++++++ 4 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5937af9daa5..112e9415c7f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2016-10-24 Jonathan Wakely + + * src/filesystem/ops.cc (do_copy_file): Return an error if either + source or destination is not a regular file. + (copy): Update comment to refer to LWG 2681. Implement 2682 and 2683 + resolutions. + (read_symlink): Add missing ec.clear(). + * testsuite/experimental/filesystem/operations/copy.cc: Update + expected behaviour for copying directories with create_symlinks. + Verify that error_code arguments are cleared if there's no error. + * testsuite/experimental/filesystem/operations/read_symlink.cc: New. + 2016-10-24 Ville Voutilainen Cross-port exception-safety and move fixes of std::any to diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index 2286e2201f4..6f76053d571 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -361,6 +361,11 @@ namespace from_st = &st2; } f = make_file_status(*from_st); + if (!is_regular_file(f)) + { + ec = std::make_error_code(std::errc::not_supported); + return false; + } using opts = fs::copy_options; @@ -392,6 +397,11 @@ namespace 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 { @@ -489,7 +499,8 @@ fs::copy(const path& from, const path& to, copy_options options, file_status f, t; stat_type from_st, to_st; - // N4099 doesn't check copy_symlinks here, but I think that's a defect. + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2681. filesystem::copy() cannot copy symlinks if (use_lstat || copy_symlinks ? ::lstat(from.c_str(), &from_st) : ::stat(from.c_str(), &from_st)) @@ -556,6 +567,10 @@ fs::copy(const path& from, const path& to, copy_options options, do_copy_file(from, to, 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)) { @@ -568,7 +583,10 @@ fs::copy(const path& from, const path& to, copy_options options, for (const directory_entry& x : directory_iterator(from)) copy(x.path(), to/x.path().filename(), options, ec); } - // "Otherwise no effects." (should ec.clear() be called?) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2683. filesystem::copy() says "no effects" + else + ec.clear(); } bool @@ -1168,6 +1186,7 @@ fs::path fs::read_symlink(const path& p, error_code& ec) ec.assign(errno, std::generic_category()); return {}; } + ec.clear(); return path{buf.data(), buf.data()+len}; #else ec = std::make_error_code(std::errc::not_supported); diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc index 0d112a21ff6..2cfb1c1fea4 100644 --- a/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc +++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc @@ -22,7 +22,6 @@ // 15.3 Copy [fs.op.copy] #include -#include #include #include @@ -43,14 +42,25 @@ test01() fs::copy(".", ".", fs::copy_options::none, ec); VERIFY( ec ); - std::ofstream{p.native()}; + __gnu_test::scoped_file f(p); VERIFY( fs::is_directory(".") ); VERIFY( fs::is_regular_file(p) ); ec.clear(); fs::copy(".", p, fs::copy_options::none, ec); VERIFY( ec ); - remove(p, ec); + auto to = __gnu_test::nonexistent_path(); + ec.clear(); + auto opts = fs::copy_options::create_symlinks; + fs::copy("/", to, opts, ec); + VERIFY( ec == std::make_error_code(std::errc::is_a_directory) ); + VERIFY( !exists(to) ); + + ec.clear(); + opts != fs::copy_options::recursive; + fs::copy("/", to, opts, ec); + VERIFY( ec == std::make_error_code(std::errc::is_a_directory) ); + VERIFY( !exists(to) ); } // Test is_symlink(f) case. @@ -59,29 +69,35 @@ test02() { auto from = __gnu_test::nonexistent_path(); auto to = __gnu_test::nonexistent_path(); - std::error_code ec; + std::error_code ec, bad = std::make_error_code(std::errc::invalid_argument); + ec = bad; fs::create_symlink(".", from, ec); VERIFY( !ec ); VERIFY( fs::exists(from) ); + ec = bad; fs::copy(from, to, fs::copy_options::skip_symlinks, ec); VERIFY( !ec ); VERIFY( !fs::exists(to) ); + ec = bad; fs::copy(from, to, fs::copy_options::skip_symlinks, ec); VERIFY( !ec ); VERIFY( !fs::exists(to) ); + ec = bad; fs::copy(from, to, fs::copy_options::skip_symlinks|fs::copy_options::copy_symlinks, ec); VERIFY( !ec ); VERIFY( !fs::exists(to) ); + ec = bad; fs::copy(from, to, fs::copy_options::copy_symlinks, ec); VERIFY( !ec ); VERIFY( fs::exists(to) ); + VERIFY( is_symlink(to) ); fs::copy(from, to, fs::copy_options::copy_symlinks, ec); VERIFY( ec ); @@ -129,10 +145,10 @@ void test05() { auto to = __gnu_test::nonexistent_path(); - std::error_code ec; + std::error_code ec = std::make_error_code(std::errc::invalid_argument); - fs::copy("/", to, fs::copy_options::create_symlinks, ec); - VERIFY( !ec ); + fs::copy("/", to, fs::copy_options::copy_symlinks, ec); + VERIFY( !ec ); // Previous value should be cleared (LWG 2683) } int diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc new file mode 100644 index 00000000000..c4137bd9369 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc @@ -0,0 +1,49 @@ +// Copyright (C) 2016 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. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-lstdc++fs" } +// { dg-do run { target c++11 } } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +namespace fs = std::experimental::filesystem; + +void +test01() +{ + auto p = __gnu_test::nonexistent_path(); + std::error_code ec; + + read_symlink(p, ec); + VERIFY( ec ); + + fs::path tgt = "."; + create_symlink(tgt, p); + + auto result = read_symlink(p, ec); + VERIFY( !ec ); + VERIFY( result == tgt ); +} + +int +main() +{ + test01(); +} -- 2.30.2