Ignore perms::symlink_nofollow on non-symlinks
authorJonathan Wakely <jwakely@redhat.com>
Sat, 22 Oct 2016 11:42:16 +0000 (12:42 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Sat, 22 Oct 2016 11:42:16 +0000 (12:42 +0100)
* src/filesystem/ops.cc (permissions(const path&, perms, error_code&)):
Ignore symlink_nofollow flag if file is not a symlink.
* testsuite/experimental/filesystem/operations/permissions.cc: Test
symlink_nofollow on non-symlinks.

From-SVN: r241438

libstdc++-v3/ChangeLog
libstdc++-v3/src/filesystem/ops.cc
libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc

index fd79decb4d8ac30d0491274d47557d095854a40a..abe1efce08b6e8e7a52262801618c97387ae8605 100644 (file)
@@ -1,3 +1,10 @@
+2016-10-22  Jonathan Wakely  <jwakely@redhat.com>
+
+       * src/filesystem/ops.cc (permissions(const path&, perms, error_code&)):
+       Ignore symlink_nofollow flag if file is not a symlink.
+       * testsuite/experimental/filesystem/operations/permissions.cc: Test
+       symlink_nofollow on non-symlinks.
+
 2016-10-21  Jonathan Wakely  <jwakely@redhat.com>
 
        * include/experimental/bits/fs_fwd.h (perms::resolve_symlinks):
index 68343a938249bb9a3acca59f296ede76d2fd955b..2286e2201f4fe829bf1ddb7594704b145b6e49a6 100644 (file)
@@ -1097,7 +1097,8 @@ fs::permissions(const path& p, perms prms)
     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
 }
 
-void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
+void
+fs::permissions(const path& p, perms prms, error_code& ec) noexcept
 {
   const bool add = is_set(prms, perms::add_perms);
   const bool remove = is_set(prms, perms::remove_perms);
@@ -1110,27 +1111,33 @@ void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
 
   prms &= perms::mask;
 
-  if (add || remove)
+  file_status st;
+  if (add || remove || nofollow)
     {
-      auto st = nofollow ? symlink_status(p, ec) : status(p, ec);
+      st = nofollow ? symlink_status(p, ec) : status(p, ec);
       if (ec)
        return;
       auto curr = st.permissions();
       if (add)
        prms |= curr;
-      else
+      else if (remove)
        prms = curr & ~prms;
     }
 
+  int err = 0;
 #if _GLIBCXX_USE_FCHMODAT
-  const int flag = nofollow ? AT_SYMLINK_NOFOLLOW : 0;
+  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)
+  if (nofollow && is_symlink(st))
     ec = std::make_error_code(std::errc::operation_not_supported);
   else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+    err = errno;
 #endif
-    ec.assign(errno, std::generic_category());
+
+  if (err)
+    ec.assign(err, std::generic_category());
   else
     ec.clear();
 }
index 839cfefa8827bf400e288d5c6e299710822b3dfc..61471a35f7ba9d9b61f608808b99bdbc7ad5d29a 100644 (file)
@@ -121,6 +121,26 @@ test04()
   remove(p);
 }
 
+void
+test05()
+{
+  using perms = std::experimental::filesystem::perms;
+  std::error_code ec;
+
+  __gnu_test::scoped_file f;
+  auto p = perms::owner_write;
+
+  // symlink_nofollow should not give an error for non-symlinks
+  permissions(f.path, p|perms::symlink_nofollow, ec);
+  VERIFY( !ec );
+  auto st = status(f.path);
+  VERIFY( st.permissions() == p );
+  p |= perms::owner_read;
+  permissions(f.path, p|perms::symlink_nofollow, ec);
+  st = status(f.path);
+  VERIFY( st.permissions() == p );
+}
+
 int
 main()
 {
@@ -128,4 +148,5 @@ main()
   test02();
   test03();
   test04();
+  test05();
 }