Implement DR resolutions for filesystem::copy
authorJonathan Wakely <jwakely@redhat.com>
Mon, 24 Oct 2016 16:45:31 +0000 (17:45 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 24 Oct 2016 16:45:31 +0000 (17:45 +0100)
* 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
libstdc++-v3/src/filesystem/ops.cc
libstdc++-v3/testsuite/experimental/filesystem/operations/copy.cc
libstdc++-v3/testsuite/experimental/filesystem/operations/read_symlink.cc [new file with mode: 0644]

index 5937af9daa5dc087f2f2b3ec2e23dcffe3874a30..112e9415c7fd4766070de4039e1dde2986ad43a3 100644 (file)
@@ -1,3 +1,15 @@
+2016-10-24  Jonathan Wakely  <jwakely@redhat.com>
+
+       * 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  <ville.voutilainen@gmail.com>
 
        Cross-port exception-safety and move fixes of std::any to
index 2286e2201f4fe829bf1ddb7594704b145b6e49a6..6f76053d57177cbbb9cee6b1b9db4213fe46e925 100644 (file)
@@ -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);
index 0d112a21ff61664335e2ed4825599dec01435e16..2cfb1c1fea4e0981b5685d637eade03072bf3b13 100644 (file)
@@ -22,7 +22,6 @@
 // 15.3 Copy [fs.op.copy]
 
 #include <experimental/filesystem>
-#include <fstream>
 #include <testsuite_fs.h>
 #include <testsuite_hooks.h>
 
@@ -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 (file)
index 0000000..c4137bd
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-lstdc++fs" }
+// { dg-do run { target c++11 } }
+// { dg-require-filesystem-ts "" }
+
+#include <experimental/filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+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();
+}