Fix error handling in copy_file and equivalent
* src/filesystem/ops.cc (do_copy_file): Report an error if source or destination is not a regular file (LWG 2712). (equivalent): Fix error handling and result when only one file exists. * testsuite/experimental/filesystem/operations/copy.cc: Remove files created by tests. Test copying directories. * testsuite/experimental/filesystem/operations/copy_file.cc: Remove files created by tests. * testsuite/experimental/filesystem/operations/equivalent.cc: New. * testsuite/experimental/filesystem/operations/is_empty.cc: New. * testsuite/experimental/filesystem/operations/read_symlink.cc: Remove file created by test. * testsuite/experimental/filesystem/operations/remove_all.cc: New. * testsuite/util/testsuite_fs.h (~scoped_file): Only try to remove file if path is non-empty, to support removal by other means. From-SVN: r241521
This commit is contained in:
parent
1cf1719bc0
commit
ec04aad76d
@ -1,3 +1,20 @@
|
|||||||
|
2016-10-25 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
* src/filesystem/ops.cc (do_copy_file): Report an error if source or
|
||||||
|
destination is not a regular file (LWG 2712).
|
||||||
|
(equivalent): Fix error handling and result when only one file exists.
|
||||||
|
* testsuite/experimental/filesystem/operations/copy.cc: Remove files
|
||||||
|
created by tests. Test copying directories.
|
||||||
|
* testsuite/experimental/filesystem/operations/copy_file.cc: Remove
|
||||||
|
files created by tests.
|
||||||
|
* testsuite/experimental/filesystem/operations/equivalent.cc: New.
|
||||||
|
* testsuite/experimental/filesystem/operations/is_empty.cc: New.
|
||||||
|
* testsuite/experimental/filesystem/operations/read_symlink.cc: Remove
|
||||||
|
file created by test.
|
||||||
|
* testsuite/experimental/filesystem/operations/remove_all.cc: New.
|
||||||
|
* testsuite/util/testsuite_fs.h (~scoped_file): Only try to remove
|
||||||
|
file if path is non-empty, to support removal by other means.
|
||||||
|
|
||||||
2016-10-24 Jonathan Wakely <jwakely@redhat.com>
|
2016-10-24 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* src/filesystem/ops.cc (is_empty): Fix error handling.
|
* src/filesystem/ops.cc (is_empty): Fix error handling.
|
||||||
|
@ -350,6 +350,8 @@ namespace
|
|||||||
from_st = &st2;
|
from_st = &st2;
|
||||||
}
|
}
|
||||||
f = make_file_status(*from_st);
|
f = make_file_status(*from_st);
|
||||||
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||||
|
// 2712. copy_file() has a number of unspecified error conditions
|
||||||
if (!is_regular_file(f))
|
if (!is_regular_file(f))
|
||||||
{
|
{
|
||||||
ec = std::make_error_code(std::errc::not_supported);
|
ec = std::make_error_code(std::errc::not_supported);
|
||||||
@ -360,8 +362,13 @@ namespace
|
|||||||
|
|
||||||
if (exists(t))
|
if (exists(t))
|
||||||
{
|
{
|
||||||
if (!is_other(t) && !is_other(f)
|
if (!is_regular_file(t))
|
||||||
&& to_st->st_dev == from_st->st_dev
|
{
|
||||||
|
ec = std::make_error_code(std::errc::not_supported);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_st->st_dev == from_st->st_dev
|
||||||
&& to_st->st_ino == from_st->st_ino)
|
&& to_st->st_ino == from_st->st_ino)
|
||||||
{
|
{
|
||||||
ec = std::make_error_code(std::errc::file_exists);
|
ec = std::make_error_code(std::errc::file_exists);
|
||||||
@ -912,7 +919,7 @@ fs::equivalent(const path& p1, const path& p2)
|
|||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto result = equivalent(p1, p2, ec);
|
auto result = equivalent(p1, p2, ec);
|
||||||
if (ec.value())
|
if (ec)
|
||||||
_GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
|
_GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
|
||||||
p1, p2, ec));
|
p1, p2, ec));
|
||||||
return result;
|
return result;
|
||||||
@ -922,25 +929,42 @@ bool
|
|||||||
fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
|
fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||||
|
int err = 0;
|
||||||
|
file_status s1, s2;
|
||||||
stat_type st1, st2;
|
stat_type st1, st2;
|
||||||
if (::stat(p1.c_str(), &st1) == 0 && ::stat(p2.c_str(), &st2) == 0)
|
if (::stat(p1.c_str(), &st1) == 0)
|
||||||
|
s1 = make_file_status(st1);
|
||||||
|
else if (is_not_found_errno(errno))
|
||||||
|
s1.type(file_type::not_found);
|
||||||
|
else
|
||||||
|
err = errno;
|
||||||
|
|
||||||
|
if (::stat(p2.c_str(), &st2) == 0)
|
||||||
|
s2 = make_file_status(st2);
|
||||||
|
else if (is_not_found_errno(errno))
|
||||||
|
s2.type(file_type::not_found);
|
||||||
|
else
|
||||||
|
err = errno;
|
||||||
|
|
||||||
|
if (exists(s1) && exists(s2))
|
||||||
{
|
{
|
||||||
file_status s1 = make_file_status(st1);
|
|
||||||
file_status s2 = make_file_status(st2);
|
|
||||||
if (is_other(s1) && is_other(s2))
|
if (is_other(s1) && is_other(s2))
|
||||||
{
|
{
|
||||||
ec = std::make_error_code(std::errc::not_supported);
|
ec = std::make_error_code(std::errc::not_supported);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ec.clear();
|
ec.clear();
|
||||||
|
if (is_other(s1) || is_other(s2))
|
||||||
|
return false;
|
||||||
return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
|
return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
|
||||||
}
|
}
|
||||||
else if (is_not_found_errno(errno))
|
else if (!exists(s1) && !exists(s2))
|
||||||
{
|
ec = std::make_error_code(std::errc::no_such_file_or_directory);
|
||||||
ec = std::make_error_code(std::errc::no_such_file_or_directory);
|
else if (err)
|
||||||
return false;
|
ec.assign(err, std::generic_category());
|
||||||
}
|
else
|
||||||
ec.assign(errno, std::generic_category());
|
ec.clear();
|
||||||
|
return false;
|
||||||
#else
|
#else
|
||||||
ec = std::make_error_code(std::errc::not_supported);
|
ec = std::make_error_code(std::errc::not_supported);
|
||||||
#endif
|
#endif
|
||||||
|
@ -128,6 +128,9 @@ test03()
|
|||||||
fs::copy(from, to);
|
fs::copy(from, to);
|
||||||
VERIFY( fs::exists(to) );
|
VERIFY( fs::exists(to) );
|
||||||
VERIFY( fs::file_size(to) == fs::file_size(from) );
|
VERIFY( fs::file_size(to) == fs::file_size(from) );
|
||||||
|
|
||||||
|
remove(from);
|
||||||
|
remove(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test is_directory(f) case.
|
// Test is_directory(f) case.
|
||||||
@ -138,6 +141,37 @@ test04()
|
|||||||
auto to = __gnu_test::nonexistent_path();
|
auto to = __gnu_test::nonexistent_path();
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
|
create_directories(from/"a/b/c");
|
||||||
|
|
||||||
|
{
|
||||||
|
__gnu_test::scoped_file f(to);
|
||||||
|
copy(from, to, ec);
|
||||||
|
VERIFY( ec );
|
||||||
|
}
|
||||||
|
|
||||||
|
__gnu_test::scoped_file f1(from/"a/f1");
|
||||||
|
std::ofstream{f1.path} << "file one";
|
||||||
|
__gnu_test::scoped_file f2(from/"a/b/f2");
|
||||||
|
std::ofstream{f2.path} << "file two";
|
||||||
|
|
||||||
|
copy(from, to, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( exists(to) && is_empty(to) );
|
||||||
|
remove(to);
|
||||||
|
|
||||||
|
copy(from, to, fs::copy_options::recursive, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( exists(to) && !is_empty(to) );
|
||||||
|
VERIFY( is_regular_file(to/"a/f1") && !is_empty(to/"a/f1") );
|
||||||
|
VERIFY( file_size(from/"a/f1") == file_size(to/"a/f1") );
|
||||||
|
VERIFY( is_regular_file(to/"a/b/f2") && !is_empty(to/"a/b/f2") );
|
||||||
|
VERIFY( file_size(from/"a/b/f2") == file_size(to/"a/b/f2") );
|
||||||
|
VERIFY( is_directory(to/"a/b/c") && is_empty(to/"a/b/c") );
|
||||||
|
|
||||||
|
f1.path.clear();
|
||||||
|
f2.path.clear();
|
||||||
|
remove_all(from, ec);
|
||||||
|
remove_all(to, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test no-op cases.
|
// Test no-op cases.
|
||||||
|
@ -73,6 +73,9 @@ test01()
|
|||||||
VERIFY( !ec );
|
VERIFY( !ec );
|
||||||
VERIFY( exists(to) );
|
VERIFY( exists(to) );
|
||||||
VERIFY( file_size(to) == file_size(from) );
|
VERIFY( file_size(to) == file_size(from) );
|
||||||
|
|
||||||
|
remove(from);
|
||||||
|
remove(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
// 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_fs.h>
|
||||||
|
#include <testsuite_hooks.h>
|
||||||
|
|
||||||
|
namespace fs = std::experimental::filesystem;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
test01()
|
||||||
|
{
|
||||||
|
auto p1 = __gnu_test::nonexistent_path();
|
||||||
|
auto p2 = __gnu_test::nonexistent_path();
|
||||||
|
std::error_code ec;
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = equivalent(p1, p2, ec);
|
||||||
|
VERIFY( ec );
|
||||||
|
VERIFY( !result );
|
||||||
|
const auto bad_ec = ec;
|
||||||
|
|
||||||
|
__gnu_test::scoped_file f1(p1);
|
||||||
|
result = equivalent(p1, p2, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( !result );
|
||||||
|
|
||||||
|
__gnu_test::scoped_file f2(p2);
|
||||||
|
ec = bad_ec;
|
||||||
|
result = equivalent(p1, p2, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( !result );
|
||||||
|
|
||||||
|
auto p3 = __gnu_test::nonexistent_path();
|
||||||
|
create_hard_link(p1, p3, ec);
|
||||||
|
if (ec)
|
||||||
|
return; // hard links not supported
|
||||||
|
__gnu_test::scoped_file f3(p3, __gnu_test::scoped_file::adopt_file);
|
||||||
|
|
||||||
|
ec = bad_ec;
|
||||||
|
result = equivalent(p1, p3, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( result );
|
||||||
|
|
||||||
|
ec = bad_ec;
|
||||||
|
result = equivalent(p2, p3, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( !result );
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
test01();
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
// 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 } }E
|
||||||
|
// { 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();
|
||||||
|
create_directory(p);
|
||||||
|
permissions(p, fs::perms::none);
|
||||||
|
std::error_code ec, ec2;
|
||||||
|
|
||||||
|
bool result = fs::is_empty(p, ec);
|
||||||
|
VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
|
||||||
|
VERIFY( !result );
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs::is_empty(p);
|
||||||
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
ec2 = e.code();
|
||||||
|
}
|
||||||
|
VERIFY( ec2 == ec );
|
||||||
|
|
||||||
|
result = fs::is_empty(p/"f", ec);
|
||||||
|
VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
|
||||||
|
VERIFY( !result );
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs::is_empty(p/"f");
|
||||||
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
ec2 = e.code();
|
||||||
|
}
|
||||||
|
VERIFY( ec2 == ec );
|
||||||
|
|
||||||
|
permissions(p, fs::perms::owner_all, ec);
|
||||||
|
remove_all(p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test02()
|
||||||
|
{
|
||||||
|
auto p = __gnu_test::nonexistent_path();
|
||||||
|
create_directory(p);
|
||||||
|
std::error_code ec, bad_ec = make_error_code(std::errc::invalid_argument);
|
||||||
|
bool empty;
|
||||||
|
|
||||||
|
ec = bad_ec;
|
||||||
|
empty = is_empty(p, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( empty );
|
||||||
|
empty = is_empty(p);
|
||||||
|
VERIFY( empty );
|
||||||
|
|
||||||
|
__gnu_test::scoped_file f(p/"f");
|
||||||
|
ec = bad_ec;
|
||||||
|
empty = is_empty(f.path, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( empty );
|
||||||
|
empty = is_empty(f.path);
|
||||||
|
VERIFY( empty );
|
||||||
|
|
||||||
|
std::ofstream{f.path.native()} << "data";
|
||||||
|
ec = bad_ec;
|
||||||
|
empty = is_empty(p, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( !empty );
|
||||||
|
empty = is_empty(p);
|
||||||
|
VERIFY( !empty );
|
||||||
|
|
||||||
|
ec = bad_ec;
|
||||||
|
empty = is_empty(p, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( !empty );
|
||||||
|
empty = is_empty(p);
|
||||||
|
VERIFY( !empty );
|
||||||
|
|
||||||
|
f.path.clear();
|
||||||
|
remove_all(p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
test01();
|
||||||
|
test02();
|
||||||
|
}
|
@ -40,6 +40,8 @@ test01()
|
|||||||
auto result = read_symlink(p, ec);
|
auto result = read_symlink(p, ec);
|
||||||
VERIFY( !ec );
|
VERIFY( !ec );
|
||||||
VERIFY( result == tgt );
|
VERIFY( result == tgt );
|
||||||
|
|
||||||
|
remove(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
// 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;
|
||||||
|
std::uintmax_t n;
|
||||||
|
|
||||||
|
n = fs::remove_all("", ec);
|
||||||
|
VERIFY( ec );
|
||||||
|
VERIFY( n == std::uintmax_t(-1) );
|
||||||
|
|
||||||
|
auto p = __gnu_test::nonexistent_path();
|
||||||
|
ec.clear();
|
||||||
|
n = remove_all(p, ec);
|
||||||
|
VERIFY( ec );
|
||||||
|
VERIFY( n == std::uintmax_t(-1) );
|
||||||
|
|
||||||
|
const auto bad_ec = ec;
|
||||||
|
auto link = __gnu_test::nonexistent_path();
|
||||||
|
create_symlink(p, link); // dangling symlink
|
||||||
|
ec = bad_ec;
|
||||||
|
n = remove_all(link, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( n == 1 );
|
||||||
|
VERIFY( !exists(symlink_status(link)) ); // DR 2721
|
||||||
|
|
||||||
|
__gnu_test::scoped_file f(p);
|
||||||
|
create_symlink(p, link);
|
||||||
|
ec = bad_ec;
|
||||||
|
n = remove_all(link, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( n == 1 );
|
||||||
|
VERIFY( !exists(symlink_status(link)) ); // The symlink is removed, but
|
||||||
|
VERIFY( exists(p) ); // its target is not.
|
||||||
|
|
||||||
|
auto dir = __gnu_test::nonexistent_path();
|
||||||
|
create_directories(dir/"a/b/c");
|
||||||
|
ec = bad_ec;
|
||||||
|
n = remove_all(dir/"a", ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( n == 3 );
|
||||||
|
VERIFY( exists(dir) );
|
||||||
|
VERIFY( !exists(dir/"a") );
|
||||||
|
|
||||||
|
create_directories(dir/"a/b/c");
|
||||||
|
__gnu_test::scoped_file a1(dir/"a/1");
|
||||||
|
__gnu_test::scoped_file a2(dir/"a/2");
|
||||||
|
__gnu_test::scoped_file b1(dir/"a/b/1");
|
||||||
|
__gnu_test::scoped_file b2(dir/"a/b/2");
|
||||||
|
ec = bad_ec;
|
||||||
|
n = remove_all(dir, ec);
|
||||||
|
VERIFY( !ec );
|
||||||
|
VERIFY( n == 8 );
|
||||||
|
VERIFY( !exists(dir) );
|
||||||
|
|
||||||
|
a1.path.clear();
|
||||||
|
a2.path.clear();
|
||||||
|
b1.path.clear();
|
||||||
|
b2.path.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
test01();
|
||||||
|
}
|
@ -107,7 +107,7 @@ namespace __gnu_test
|
|||||||
|
|
||||||
scoped_file(path_type p, adopt_file_t) : path(p) { }
|
scoped_file(path_type p, adopt_file_t) : path(p) { }
|
||||||
|
|
||||||
~scoped_file() { remove(path); }
|
~scoped_file() { if (!path.empty()) remove(path); }
|
||||||
|
|
||||||
path_type path;
|
path_type path;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user