summaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/27_io/filesystem
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-01-31 21:12:53 +0000
committerJonathan Wakely <jwakely@redhat.com>2022-02-01 21:56:16 +0000
commitec09a5335f0ade7071f6157dfd97dbb3de3e4f97 (patch)
treecca20f16242dda1452a0a0d179a859b097ecc767 /libstdc++-v3/testsuite/27_io/filesystem
parent90263a48303a5ae552ea04c68ed7fa5da49b1876 (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.cc135
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();
+}