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
This commit is contained in:
Jonathan Wakely 2016-10-21 18:01:05 +01:00 committed by Jonathan Wakely
parent 2be9212713
commit d17f7088fb
5 changed files with 192 additions and 6 deletions

View File

@ -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).

View File

@ -162,7 +162,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
unknown = 0xFFFF,
add_perms = 0x10000,
remove_perms = 0x20000,
resolve_symlinks = 0x40000
symlink_nofollow = 0x40000
};
constexpr perms

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}