diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2022-01-31 21:12:53 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2022-02-01 21:56:16 +0000 |
commit | ec09a5335f0ade7071f6157dfd97dbb3de3e4f97 (patch) | |
tree | cca20f16242dda1452a0a0d179a859b097ecc767 /libstdc++-v3/testsuite/27_io/filesystem | |
parent | 90263a48303a5ae552ea04c68ed7fa5da49b1876 (diff) |
libstdc++: Reset filesystem::recursive_directory_iterator on error
The standard requires directory iterators to become equal to the end
iterator value if they report an error. Some members functions of
filesystem::recursive_directory_iterator fail to do that.
libstdc++-v3/ChangeLog:
* src/c++17/fs_dir.cc (recursive_directory_iterator::increment):
Reset state to past-the-end iterator on error.
(fs::recursive_directory_iterator::pop(error_code&)): Likewise.
(fs::recursive_directory_iterator::pop()): Check _M_dirs before
it might get reset.
* src/filesystem/dir.cc (recursive_directory_iterator): Likewise,
for the TS implementation.
* testsuite/27_io/filesystem/iterators/error_reporting.cc: New test.
* testsuite/experimental/filesystem/iterators/error_reporting.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/27_io/filesystem')
-rw-r--r-- | libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc new file mode 100644 index 00000000000..81ef1069367 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/error_reporting.cc @@ -0,0 +1,135 @@ +// Copyright (C) 2020-2022 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-do run { target { c++17 } } } +// { dg-require-filesystem-ts "" } + +#include <filesystem> +#include <cerrno> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <testsuite_hooks.h> +#include <testsuite_fs.h> + +int choice; + +struct dirent global_dirent; + +extern "C" struct dirent* readdir(DIR*) +{ + switch (choice) + { + case 1: + global_dirent.d_ino = 999; + global_dirent.d_type = DT_REG; + global_dirent.d_reclen = 0; + std::char_traits<char>::copy(global_dirent.d_name, "file", 5); + choice = 0; + return &global_dirent; + case 2: + global_dirent.d_ino = 111; + global_dirent.d_type = DT_DIR; + global_dirent.d_reclen = 60; + std::char_traits<char>::copy(global_dirent.d_name, "subdir", 7); + choice = 1; + return &global_dirent; + default: + errno = EIO; + return nullptr; + } + return &global_dirent; +} + +void +test01() +{ + namespace fs = std::filesystem; + std::error_code ec; + choice = 1; + fs::recursive_directory_iterator it(".", ec); + if (choice == 0) // custom readdir was called + { + it.increment(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + else + { + puts("Custom readdir not used, cannot test error handling"); + exit(0); + } + +#if __cpp_exceptions + choice = 1; + fs::recursive_directory_iterator it2(".", ec); + if (choice == 0) + { + try { + ++it2; + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif +} + +void +test02() +{ + namespace fs = std::filesystem; + auto dir = __gnu_test::nonexistent_path(); + fs::create_directories(dir/"subdir"); + + std::error_code ec; + choice = 2; + fs::recursive_directory_iterator it(dir, ec); + if (choice == 1) + { + ++it; + it.pop(ec); + VERIFY( ec.value() == EIO ); + VERIFY( it == end(it) ); + } + +#if __cpp_exceptions + choice = 2; + fs::recursive_directory_iterator it2(dir, ec); + if (choice == 1) + { + ++it2; + try { + it2.pop(); + VERIFY( false ); + } catch (const fs::filesystem_error& e) { + VERIFY( e.code().value() == EIO ); + VERIFY( it2 == end(it2) ); + } + } +#endif + + fs::remove_all(dir, ec); +} + +int +main() +{ + test01(); + test02(); +} |