diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2016-10-21 18:01:05 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2016-10-21 18:01:05 +0100 |
commit | d17f7088fbe9b7d159021d0442d174925df7b20d (patch) | |
tree | 8368472a50257c8a6a58991fb43b970d547507cc | |
parent | 2be921271333c81ec9fcf71ba49110bf23971d09 (diff) | |
download | gcc-d17f7088fbe9b7d159021d0442d174925df7b20d.zip gcc-d17f7088fbe9b7d159021d0442d174925df7b20d.tar.gz gcc-d17f7088fbe9b7d159021d0442d174925df7b20d.tar.bz2 |
LWG2720 implement filesystem::perms::symlink_nofollow
* include/experimental/bits/fs_fwd.h (perms::resolve_symlinks):
Replace with symlink_nofollow (LWG 2720).
* src/filesystem/ops.cc (permissions(const path&, perms, error_code&)):
Handle symlink_nofollow.
* testsuite/experimental/filesystem/operations/create_symlink.cc: New
test.
* testsuite/experimental/filesystem/operations/permissions.cc: Test
overload taking error_code.
From-SVN: r241418
5 files changed, 192 insertions, 6 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d4250ee..fd79dec 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2016-10-21 Jonathan Wakely <jwakely@redhat.com> + * include/experimental/bits/fs_fwd.h (perms::resolve_symlinks): + Replace with symlink_nofollow (LWG 2720). + * src/filesystem/ops.cc (permissions(const path&, perms, error_code&)): + Handle symlink_nofollow. + * testsuite/experimental/filesystem/operations/create_symlink.cc: New + test. + * testsuite/experimental/filesystem/operations/permissions.cc: Test + overload taking error_code. + * include/experimental/bits/fs_ops.h (exists(const path&, error_code&)): Clear error if status is known (LWG 2725). diff --git a/libstdc++-v3/include/experimental/bits/fs_fwd.h b/libstdc++-v3/include/experimental/bits/fs_fwd.h index 1c08b19..fb8521a 100644 --- a/libstdc++-v3/include/experimental/bits/fs_fwd.h +++ b/libstdc++-v3/include/experimental/bits/fs_fwd.h @@ -162,7 +162,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 unknown = 0xFFFF, add_perms = 0x10000, remove_perms = 0x20000, - resolve_symlinks = 0x40000 + symlink_nofollow = 0x40000 }; constexpr perms diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index 6b38584..68343a9 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -1101,6 +1101,7 @@ 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); + const bool nofollow = is_set(prms, perms::symlink_nofollow); if (add && remove) { ec = std::make_error_code(std::errc::invalid_argument); @@ -1111,7 +1112,7 @@ void fs::permissions(const path& p, perms prms, error_code& ec) noexcept if (add || remove) { - auto st = status(p, ec); + auto st = nofollow ? symlink_status(p, ec) : status(p, ec); if (ec) return; auto curr = st.permissions(); @@ -1122,9 +1123,12 @@ void fs::permissions(const path& p, perms prms, error_code& ec) noexcept } #if _GLIBCXX_USE_FCHMODAT - if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0)) + const int flag = nofollow ? AT_SYMLINK_NOFOLLOW : 0; + if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag)) #else - if (::chmod(p.c_str(), static_cast<mode_t>(prms))) + if (nofollow) + ec = std::make_error_code(std::errc::operation_not_supported); + else if (::chmod(p.c_str(), static_cast<mode_t>(prms))) #endif ec.assign(errno, std::generic_category()); else diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc new file mode 100644 index 0000000..7297259 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_symlink.cc @@ -0,0 +1,93 @@ +// 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() +{ + std::error_code ec, ec2; + __gnu_test::scoped_file f; + auto tgt = f.path; + + // Test empty path. + fs::path p; + create_symlink(tgt, p, ec ); + VERIFY( ec ); + try + { + create_symlink(tgt, p); + } + catch (const std::experimental::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == tgt ); + VERIFY( ex.path2() == p ); + } + VERIFY( ec2 == ec ); +} + +void +test02() +{ + std::error_code ec, ec2; + __gnu_test::scoped_file f; + auto tgt = f.path; + + // Test non-existent path + auto p = __gnu_test::nonexistent_path(); + VERIFY( !exists(p) ); + + create_symlink(tgt, p, ec); // create the symlink once + VERIFY( !ec ); + VERIFY( exists(p) ); + VERIFY( is_symlink(p) ); + remove(p); + create_symlink(tgt, p); // create the symlink again + VERIFY( exists(p) ); + VERIFY( is_symlink(p) ); + + create_symlink(tgt, p, ec); // Try to create existing symlink + VERIFY( ec ); + try + { + create_symlink(tgt, p); + } + catch (const std::experimental::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == tgt ); + VERIFY( ex.path2() == p ); + } + VERIFY( ec2 == ec ); + + remove(p); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc index 07e8366..839cfef 100644 --- a/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc +++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/permissions.cc @@ -22,7 +22,6 @@ // 15.26 Permissions [fs.op.permissions] #include <experimental/filesystem> -#include <fstream> #include <testsuite_fs.h> #include <testsuite_hooks.h> @@ -32,7 +31,8 @@ test01() using perms = std::experimental::filesystem::perms; auto p = __gnu_test::nonexistent_path(); - std::ofstream{p.native()}; + + __gnu_test::scoped_file f(p); VERIFY( exists(p) ); permissions(p, perms::owner_all); VERIFY( status(p).permissions() == perms::owner_all ); @@ -40,6 +40,83 @@ test01() VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) ); permissions(p, perms::group_read | perms::remove_perms); VERIFY( status(p).permissions() == perms::owner_all ); +} + +void +test02() +{ + using perms = std::experimental::filesystem::perms; + + auto p = __gnu_test::nonexistent_path(); + + std::error_code ec; + permissions(p, perms::owner_all, ec); + VERIFY( ec ); + + __gnu_test::scoped_file f(p); + VERIFY( exists(p) ); + + ec = std::make_error_code(std::errc::invalid_argument); + permissions(p, perms::owner_all, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == perms::owner_all ); + permissions(p, perms::group_read | perms::add_perms, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) ); + permissions(p, perms::group_read | perms::remove_perms, ec); + VERIFY( !ec ); + VERIFY( status(p).permissions() == perms::owner_all ); +} + +void +test03() +{ + using perms = std::experimental::filesystem::perms; + + __gnu_test::scoped_file f; + VERIFY( exists(f.path) ); + + auto p = __gnu_test::nonexistent_path(); + create_symlink(f.path, p); + + std::error_code ec, ec2; + permissions(p, perms::owner_all | perms::symlink_nofollow, ec); + try + { + permissions(p, perms::owner_all | perms::symlink_nofollow); + } + catch (const std::experimental::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == p ); + } + // Both calls should succeed, or both should fail with same error: + VERIFY( ec == ec2 ); + + remove(p); +} + +void +test04() +{ + using perms = std::experimental::filesystem::perms; + + auto p = __gnu_test::nonexistent_path(); + create_symlink(__gnu_test::nonexistent_path(), p); + + std::error_code ec, ec2; + permissions(p, perms::owner_all, ec); + VERIFY( ec ); + try + { + permissions(p, perms::owner_all); + } + catch (const std::experimental::filesystem::filesystem_error& ex) + { + ec2 = ex.code(); + VERIFY( ex.path1() == p ); + } + VERIFY( ec == ec2 ); remove(p); } @@ -48,4 +125,7 @@ int main() { test01(); + test02(); + test03(); + test04(); } |