From 998d93cdf476ce9723ae07d02ed6d981c5f37f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20Schu=CC=88mann?= Date: Sun, 12 Jul 2026 10:06:11 +0200 Subject: [PATCH] `copy_file()` handls non-regular sources with error reporting (#205) --- README.md | 2 ++ include/ghc/filesystem.hpp | 10 +++++++++- test/filesystem_test.cpp | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ec2099..40be530 100644 --- a/README.md +++ b/README.md @@ -661,6 +661,8 @@ to the expected behavior. now supports device UNC paths. * Fix for [#204](https://github.com/gulrak/filesystem/issues/204), `weakly_canonical()` now propagates component lookup errors. +* Fix for [#205](https://github.com/gulrak/filesystem/issues/205), `copy_file()` + now reports an error for non-regular sources. * Fix for [#185](https://github.com/gulrak/filesystem/issues/185), `lexically_normal()` now preserves unresolved parent components in relative paths. diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 454dfe7..db3daf1 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -3951,7 +3951,15 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options bool overwrite = false; ec.clear(); if (!is_regular_file(sf)) { - ec = tecf; + if (tecf) { + ec = tecf; + } + else if (is_directory(sf)) { + ec = detail::make_error_code(detail::portable_error::is_a_directory); + } + else { + ec = detail::make_error_code(detail::portable_error::invalid_argument); + } return false; } if (exists(st)) { diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index 263a837..8bd4d82 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -1825,6 +1825,24 @@ TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_fi CHECK_NOTHROW(fs::copy_file("foobar", "foobar2", ec)); CHECK(ec); CHECK(!fs::exists("foobar")); + CHECK(!fs::exists("foobar2")); + + fs::create_directory("source_dir"); + CHECK_FALSE(fs::copy_file("source_dir", "dir_copy", ec)); + CHECK(ec); + CHECK_FALSE(fs::exists("dir_copy")); + CHECK_THROWS_AS(fs::copy_file("source_dir", "dir_copy"), fs::filesystem_error); + CHECK_FALSE(fs::exists("dir_copy")); + +#if !defined(GHC_OS_WINDOWS) && !defined(GHC_OS_WEB) + REQUIRE(::mkfifo("source_fifo", 0644) == 0); + CHECK_FALSE(fs::copy_file("source_fifo", "fifo_copy", ec)); + CHECK(ec); + CHECK_FALSE(fs::exists("fifo_copy")); + CHECK_THROWS_AS(fs::copy_file("source_fifo", "fifo_copy"), fs::filesystem_error); + CHECK_FALSE(fs::exists("fifo_copy")); +#endif + fs::path file1("temp1.txt"); fs::path file2("temp2.txt"); generateFile(file1, 200); @@ -1838,6 +1856,10 @@ TEST_CASE("fs.op.copy_file - copy_file", "[filesystem][operations][fs.op.copy_fi CHECK((fs::status(file2).permissions() & fs::perms::owner_write) != fs::perms::owner_write); CHECK_NOTHROW(fs::permissions(file1, allWrite, fs::perm_options::add)); CHECK_NOTHROW(fs::permissions(file2, allWrite, fs::perm_options::add)); + + ec = std::make_error_code(std::errc::invalid_argument); + CHECK(fs::copy_file("foo", "bar3", ec)); + CHECK(!ec); } TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.copy_symlink]")