Implement C++17 Filesystem library
authorJonathan Wakely <jwakely@redhat.com>
Mon, 23 Oct 2017 12:11:22 +0000 (13:11 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 23 Oct 2017 12:11:22 +0000 (13:11 +0100)
Based on Filesystem TS implementation, with the changes applied by:

- P0219R1 Relative Paths for Filesystem
- P0317R1 Directory Entry Caching for Filesystem
- P0492R2 Resolution of C++17 National Body Comments

Where appropriate code is shared between the TS and C++17
implementations.

* include/Makefile.am: Add new headers for C++17 filesystem library.
* include/Makefile.in: Regenerate.
* include/bits/fs_dir.h: New header, based on Filesystem TS code in
include/experimental/bits directory.
* include/bits/fs_fwd.h: Likewise.
* include/bits/fs_ops.h: Likewise.
* include/bits/fs_path.h: Likewise.
* include/experimental/bits/fs_dir.h: Rename Doxygen group.
* include/experimental/bits/fs_fwd.h: Likewise.
* include/experimental/bits/fs_ops.h: Likewise.
* include/experimental/bits/fs_path.h: Likewise.
* include/experimental/filesystem (filesystem_error::_M_gen_what):
Remove inline definition.
* include/precompiled/stdc++.h: Add <filesystem> to precompiled
header.
* include/std/filesystem: New header.
* python/libstdcxx/v6/printers.py: Enable printer for std::filesystem
paths.
* src/filesystem/Makefile.am: Add new files. Compile as C++17.
* src/filesystem/Makefile.in: Regenerate.
* src/filesystem/cow-dir.cc: Update comment.
* src/filesystem/cow-ops.cc: Likewise.
* src/filesystem/cow-path.cc: Likewise.
* src/filesystem/cow-std-dir.cc: New file.
* src/filesystem/cow-std-ops.cc: New file.
* src/filesystem/cow-std-path.cc: New file.
* src/filesystem/dir-common.h (_Dir_base, get_file_type): New header
for common code.
* src/filesystem/dir.cc (_Dir): Derive from _Dir_base.
(open_dir): Move to _Dir_base constructor.
(get_file_type): Move to dir-common.h.
(recurse): Move to _Dir_base::should_recurse.
* src/filesystem/ops-common.h: New header for common code.
* src/filesystem/ops.cc (is_set, make_file_type, make_file_status)
(is_not_found_errno, file_time, do_copy_file): Move to ops-common.h.
* src/filesystem/path.cc (filesystem_error::_M_gen_what): Define.
* src/filesystem/std-dir.cc: New file, based on Filesystem TS code.
* src/filesystem/std-ops.cc: Likewise.
* src/filesystem/std-dir.cc: Likewise.
* testsuite/27_io/filesystem/iterators/directory_iterator.cc: New
test.
* testsuite/27_io/filesystem/iterators/pop.cc: New test.
* testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
New test.
* testsuite/27_io/filesystem/operations/absolute.cc: New test.
* testsuite/27_io/filesystem/operations/canonical.cc: New test.
* testsuite/27_io/filesystem/operations/copy.cc: New test.
* testsuite/27_io/filesystem/operations/copy_file.cc: New test.
* testsuite/27_io/filesystem/operations/create_directories.cc: New
test.
* testsuite/27_io/filesystem/operations/create_directory.cc: New test.
* testsuite/27_io/filesystem/operations/create_symlink.cc: New test.
* testsuite/27_io/filesystem/operations/current_path.cc: New test.
* testsuite/27_io/filesystem/operations/equivalent.cc: New test.
* testsuite/27_io/filesystem/operations/exists.cc: New test.
* testsuite/27_io/filesystem/operations/file_size.cc: New test.
* testsuite/27_io/filesystem/operations/is_empty.cc: New test.
* testsuite/27_io/filesystem/operations/last_write_time.cc: New test.
* testsuite/27_io/filesystem/operations/permissions.cc: New test.
* testsuite/27_io/filesystem/operations/proximate.cc: New test.
* testsuite/27_io/filesystem/operations/read_symlink.cc: New test.
* testsuite/27_io/filesystem/operations/relative.cc: New test.
* testsuite/27_io/filesystem/operations/remove_all.cc: New test.
* testsuite/27_io/filesystem/operations/space.cc: New test.
* testsuite/27_io/filesystem/operations/status.cc: New test.
* testsuite/27_io/filesystem/operations/symlink_status.cc: New test.
* testsuite/27_io/filesystem/operations/temp_directory_path.cc: New
test.
* testsuite/27_io/filesystem/operations/weakly_canonical.cc: New test.
* testsuite/27_io/filesystem/path/append/path.cc: New test.
* testsuite/27_io/filesystem/path/assign/assign.cc: New test.
* testsuite/27_io/filesystem/path/assign/copy.cc: New test.
* testsuite/27_io/filesystem/path/compare/compare.cc: New test.
* testsuite/27_io/filesystem/path/compare/path.cc: New test.
* testsuite/27_io/filesystem/path/compare/strings.cc: New test.
* testsuite/27_io/filesystem/path/concat/path.cc: New test.
* testsuite/27_io/filesystem/path/concat/strings.cc: New test.
* testsuite/27_io/filesystem/path/construct/copy.cc: New test.
* testsuite/27_io/filesystem/path/construct/default.cc: New test.
* testsuite/27_io/filesystem/path/construct/locale.cc: New test.
* testsuite/27_io/filesystem/path/construct/range.cc: New test.
* testsuite/27_io/filesystem/path/construct/string_view.cc: New test.
* testsuite/27_io/filesystem/path/decompose/extension.cc: New test.
* testsuite/27_io/filesystem/path/decompose/filename.cc: New test.
* testsuite/27_io/filesystem/path/decompose/parent_path.cc: New test.
* testsuite/27_io/filesystem/path/decompose/relative_path.cc: New
test.
* testsuite/27_io/filesystem/path/decompose/root_directory.cc: New
test.
* testsuite/27_io/filesystem/path/decompose/root_name.cc: New test.
* testsuite/27_io/filesystem/path/decompose/root_path.cc: New test.
* testsuite/27_io/filesystem/path/decompose/stem.cc: New test.
* testsuite/27_io/filesystem/path/generation/normal.cc: New test.
* testsuite/27_io/filesystem/path/generation/proximate.cc: New test.
* testsuite/27_io/filesystem/path/generation/relative.cc: New test.
* testsuite/27_io/filesystem/path/generic/generic_string.cc: New test.
* testsuite/27_io/filesystem/path/itr/traversal.cc: New test.
* testsuite/27_io/filesystem/path/modifiers/clear.cc: New test.
* testsuite/27_io/filesystem/path/modifiers/make_preferred.cc: New
test.
* testsuite/27_io/filesystem/path/modifiers/remove_filename.cc: New
test.
* testsuite/27_io/filesystem/path/modifiers/replace_extension.cc: New
test.
* testsuite/27_io/filesystem/path/modifiers/replace_filename.cc: New
test.
* testsuite/27_io/filesystem/path/modifiers/swap.cc: New test.
* testsuite/27_io/filesystem/path/native/string.cc: New test.
* testsuite/27_io/filesystem/path/nonmember/hash_value.cc: New test.
* testsuite/27_io/filesystem/path/query/empty.cc: New test.
* testsuite/27_io/filesystem/path/query/has_extension.cc: New test.
* testsuite/27_io/filesystem/path/query/has_filename.cc: New test.
* testsuite/27_io/filesystem/path/query/has_parent_path.cc: New test.
* testsuite/27_io/filesystem/path/query/has_relative_path.cc: New
test.
* testsuite/27_io/filesystem/path/query/has_root_directory.cc: New
test.
* testsuite/27_io/filesystem/path/query/has_root_name.cc: New test.
* testsuite/27_io/filesystem/path/query/has_root_path.cc: New test.
* testsuite/27_io/filesystem/path/query/has_stem.cc: New test.
* testsuite/27_io/filesystem/path/query/is_relative.cc: New test.
* testsuite/experimental/filesystem/path/construct/string_view.cc:
Define USE_FILESYSTEM_TS.
* testsuite/util/testsuite_fs.h: Allow use with C++17 paths as well
as Filesystem TS.

From-SVN: r254008

103 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/fs_dir.h [new file with mode: 0644]
libstdc++-v3/include/bits/fs_fwd.h [new file with mode: 0644]
libstdc++-v3/include/bits/fs_ops.h [new file with mode: 0644]
libstdc++-v3/include/bits/fs_path.h [new file with mode: 0644]
libstdc++-v3/include/experimental/bits/fs_dir.h
libstdc++-v3/include/experimental/bits/fs_fwd.h
libstdc++-v3/include/experimental/bits/fs_ops.h
libstdc++-v3/include/experimental/bits/fs_path.h
libstdc++-v3/include/experimental/filesystem
libstdc++-v3/include/precompiled/stdc++.h
libstdc++-v3/include/std/filesystem [new file with mode: 0644]
libstdc++-v3/python/libstdcxx/v6/printers.py
libstdc++-v3/src/filesystem/Makefile.am
libstdc++-v3/src/filesystem/Makefile.in
libstdc++-v3/src/filesystem/cow-dir.cc
libstdc++-v3/src/filesystem/cow-ops.cc
libstdc++-v3/src/filesystem/cow-path.cc
libstdc++-v3/src/filesystem/cow-std-dir.cc [new file with mode: 0644]
libstdc++-v3/src/filesystem/cow-std-ops.cc [new file with mode: 0644]
libstdc++-v3/src/filesystem/cow-std-path.cc [new file with mode: 0644]
libstdc++-v3/src/filesystem/dir-common.h [new file with mode: 0644]
libstdc++-v3/src/filesystem/dir.cc
libstdc++-v3/src/filesystem/ops-common.h [new file with mode: 0644]
libstdc++-v3/src/filesystem/ops.cc
libstdc++-v3/src/filesystem/path.cc
libstdc++-v3/src/filesystem/std-dir.cc [new file with mode: 0644]
libstdc++-v3/src/filesystem/std-ops.cc [new file with mode: 0644]
libstdc++-v3/src/filesystem/std-path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc [new file with mode: 0644]
libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
libstdc++-v3/testsuite/util/testsuite_fs.h

index d22a9b9..6bb7214 100644 (file)
@@ -1,5 +1,131 @@
 2017-10-23  Jonathan Wakely  <jwakely@redhat.com>
 
+       * include/Makefile.am: Add new headers for C++17 filesystem library.
+       * include/Makefile.in: Regenerate.
+       * include/bits/fs_dir.h: New header, based on Filesystem TS code in
+       include/experimental/bits directory.
+       * include/bits/fs_fwd.h: Likewise.
+       * include/bits/fs_ops.h: Likewise.
+       * include/bits/fs_path.h: Likewise.
+       * include/experimental/bits/fs_dir.h: Rename Doxygen group.
+       * include/experimental/bits/fs_fwd.h: Likewise.
+       * include/experimental/bits/fs_ops.h: Likewise.
+       * include/experimental/bits/fs_path.h: Likewise.
+       * include/experimental/filesystem (filesystem_error::_M_gen_what):
+       Remove inline definition.
+       * include/precompiled/stdc++.h: Add <filesystem> to precompiled
+       header.
+       * include/std/filesystem: New header.
+       * python/libstdcxx/v6/printers.py: Enable printer for std::filesystem
+       paths.
+       * src/filesystem/Makefile.am: Add new files. Compile as C++17.
+       * src/filesystem/Makefile.in: Regenerate.
+       * src/filesystem/cow-dir.cc: Update comment.
+       * src/filesystem/cow-ops.cc: Likewise.
+       * src/filesystem/cow-path.cc: Likewise.
+       * src/filesystem/cow-std-dir.cc: New file.
+       * src/filesystem/cow-std-ops.cc: New file.
+       * src/filesystem/cow-std-path.cc: New file.
+       * src/filesystem/dir-common.h (_Dir_base, get_file_type): New header
+       for common code.
+       * src/filesystem/dir.cc (_Dir): Derive from _Dir_base.
+       (open_dir): Move to _Dir_base constructor.
+       (get_file_type): Move to dir-common.h.
+       (recurse): Move to _Dir_base::should_recurse.
+       * src/filesystem/ops-common.h: New header for common code.
+       * src/filesystem/ops.cc (is_set, make_file_type, make_file_status)
+       (is_not_found_errno, file_time, do_copy_file): Move to ops-common.h.
+       * src/filesystem/path.cc (filesystem_error::_M_gen_what): Define.
+       * src/filesystem/std-dir.cc: New file, based on Filesystem TS code.
+       * src/filesystem/std-ops.cc: Likewise.
+       * src/filesystem/std-dir.cc: Likewise.
+       * testsuite/27_io/filesystem/iterators/directory_iterator.cc: New
+       test.
+       * testsuite/27_io/filesystem/iterators/pop.cc: New test.
+       * testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
+       New test.
+       * testsuite/27_io/filesystem/operations/absolute.cc: New test.
+       * testsuite/27_io/filesystem/operations/canonical.cc: New test.
+       * testsuite/27_io/filesystem/operations/copy.cc: New test.
+       * testsuite/27_io/filesystem/operations/copy_file.cc: New test.
+       * testsuite/27_io/filesystem/operations/create_directories.cc: New
+       test.
+       * testsuite/27_io/filesystem/operations/create_directory.cc: New test.
+       * testsuite/27_io/filesystem/operations/create_symlink.cc: New test.
+       * testsuite/27_io/filesystem/operations/current_path.cc: New test.
+       * testsuite/27_io/filesystem/operations/equivalent.cc: New test.
+       * testsuite/27_io/filesystem/operations/exists.cc: New test.
+       * testsuite/27_io/filesystem/operations/file_size.cc: New test.
+       * testsuite/27_io/filesystem/operations/is_empty.cc: New test.
+       * testsuite/27_io/filesystem/operations/last_write_time.cc: New test.
+       * testsuite/27_io/filesystem/operations/permissions.cc: New test.
+       * testsuite/27_io/filesystem/operations/proximate.cc: New test.
+       * testsuite/27_io/filesystem/operations/read_symlink.cc: New test.
+       * testsuite/27_io/filesystem/operations/relative.cc: New test.
+       * testsuite/27_io/filesystem/operations/remove_all.cc: New test.
+       * testsuite/27_io/filesystem/operations/space.cc: New test.
+       * testsuite/27_io/filesystem/operations/status.cc: New test.
+       * testsuite/27_io/filesystem/operations/symlink_status.cc: New test.
+       * testsuite/27_io/filesystem/operations/temp_directory_path.cc: New
+       test.
+       * testsuite/27_io/filesystem/operations/weakly_canonical.cc: New test.
+       * testsuite/27_io/filesystem/path/append/path.cc: New test.
+       * testsuite/27_io/filesystem/path/assign/assign.cc: New test.
+       * testsuite/27_io/filesystem/path/assign/copy.cc: New test.
+       * testsuite/27_io/filesystem/path/compare/compare.cc: New test.
+       * testsuite/27_io/filesystem/path/compare/path.cc: New test.
+       * testsuite/27_io/filesystem/path/compare/strings.cc: New test.
+       * testsuite/27_io/filesystem/path/concat/path.cc: New test.
+       * testsuite/27_io/filesystem/path/concat/strings.cc: New test.
+       * testsuite/27_io/filesystem/path/construct/copy.cc: New test.
+       * testsuite/27_io/filesystem/path/construct/default.cc: New test.
+       * testsuite/27_io/filesystem/path/construct/locale.cc: New test.
+       * testsuite/27_io/filesystem/path/construct/range.cc: New test.
+       * testsuite/27_io/filesystem/path/construct/string_view.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/extension.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/filename.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/parent_path.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/relative_path.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/decompose/root_directory.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/decompose/root_name.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/root_path.cc: New test.
+       * testsuite/27_io/filesystem/path/decompose/stem.cc: New test.
+       * testsuite/27_io/filesystem/path/generation/normal.cc: New test.
+       * testsuite/27_io/filesystem/path/generation/proximate.cc: New test.
+       * testsuite/27_io/filesystem/path/generation/relative.cc: New test.
+       * testsuite/27_io/filesystem/path/generic/generic_string.cc: New test.
+       * testsuite/27_io/filesystem/path/itr/traversal.cc: New test.
+       * testsuite/27_io/filesystem/path/modifiers/clear.cc: New test.
+       * testsuite/27_io/filesystem/path/modifiers/make_preferred.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/modifiers/remove_filename.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/modifiers/replace_extension.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/modifiers/replace_filename.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/modifiers/swap.cc: New test.
+       * testsuite/27_io/filesystem/path/native/string.cc: New test.
+       * testsuite/27_io/filesystem/path/nonmember/hash_value.cc: New test.
+       * testsuite/27_io/filesystem/path/query/empty.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_extension.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_filename.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_parent_path.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_relative_path.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/query/has_root_directory.cc: New
+       test.
+       * testsuite/27_io/filesystem/path/query/has_root_name.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_root_path.cc: New test.
+       * testsuite/27_io/filesystem/path/query/has_stem.cc: New test.
+       * testsuite/27_io/filesystem/path/query/is_relative.cc: New test.
+       * testsuite/experimental/filesystem/path/construct/string_view.cc:
+       Define USE_FILESYSTEM_TS.
+       * testsuite/util/testsuite_fs.h: Allow use with C++17 paths as well
+       as Filesystem TS.
+
        PR libstdc++/82644
        * doc/xml/manual/intro.xml: Include new section.
        * doc/xml/manual/status_cxxis29124.xml: New section on IS 29124
index 236c2d6..2c4d193 100644 (file)
@@ -37,6 +37,7 @@ std_headers = \
        ${std_srcdir}/complex \
        ${std_srcdir}/condition_variable \
        ${std_srcdir}/deque \
+       ${std_srcdir}/filesystem \
        ${std_srcdir}/forward_list \
        ${std_srcdir}/fstream \
        ${std_srcdir}/functional \
@@ -104,6 +105,10 @@ bits_headers = \
        ${bits_srcdir}/enable_special_members.h \
        ${bits_srcdir}/forward_list.h \
        ${bits_srcdir}/forward_list.tcc \
+       ${bits_srcdir}/fs_dir.h \
+       ${bits_srcdir}/fs_fwd.h \
+       ${bits_srcdir}/fs_ops.h \
+       ${bits_srcdir}/fs_path.h \
        ${bits_srcdir}/fstream.tcc \
        ${bits_srcdir}/functexcept.h \
        ${bits_srcdir}/functional_hash.h \
index 39dfede..bc8556c 100644 (file)
@@ -330,6 +330,7 @@ std_headers = \
        ${std_srcdir}/complex \
        ${std_srcdir}/condition_variable \
        ${std_srcdir}/deque \
+       ${std_srcdir}/filesystem \
        ${std_srcdir}/forward_list \
        ${std_srcdir}/fstream \
        ${std_srcdir}/functional \
@@ -397,6 +398,10 @@ bits_headers = \
        ${bits_srcdir}/enable_special_members.h \
        ${bits_srcdir}/forward_list.h \
        ${bits_srcdir}/forward_list.tcc \
+       ${bits_srcdir}/fs_dir.h \
+       ${bits_srcdir}/fs_fwd.h \
+       ${bits_srcdir}/fs_ops.h \
+       ${bits_srcdir}/fs_path.h \
        ${bits_srcdir}/fstream.tcc \
        ${bits_srcdir}/functexcept.h \
        ${bits_srcdir}/functional_hash.h \
diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h
new file mode 100644 (file)
index 0000000..20ce9be
--- /dev/null
@@ -0,0 +1,526 @@
+// Filesystem directory utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_dir.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_DIR_H
+#define _GLIBCXX_FS_DIR_H 1
+
+#if __cplusplus >= 201703L
+# include <typeinfo>
+# include <ext/concurrence.h>
+# include <bits/unique_ptr.h>
+# include <bits/shared_ptr.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+  /**
+   * @ingroup filesystem
+   * @{
+   */
+
+  class file_status
+  {
+  public:
+    // constructors
+    explicit
+    file_status(file_type __ft = file_type::none,
+               perms __prms = perms::unknown) noexcept
+    : _M_type(__ft), _M_perms(__prms) { }
+
+    file_status(const file_status&) noexcept = default;
+    file_status(file_status&&) noexcept = default;
+    ~file_status() = default;
+
+    file_status& operator=(const file_status&) noexcept = default;
+    file_status& operator=(file_status&&) noexcept = default;
+
+    // observers
+    file_type  type() const noexcept { return _M_type; }
+    perms      permissions() const noexcept { return _M_perms; }
+
+    // modifiers
+    void       type(file_type __ft) noexcept { _M_type = __ft; }
+    void       permissions(perms __prms) noexcept { _M_perms = __prms; }
+
+  private:
+    file_type  _M_type;
+    perms      _M_perms;
+  };
+
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+  struct _Dir;
+  class directory_iterator;
+  class recursive_directory_iterator;
+
+  class directory_entry
+  {
+  public:
+    // constructors and destructor
+    directory_entry() noexcept = default;
+    directory_entry(const directory_entry&) = default;
+    directory_entry(directory_entry&&) noexcept = default;
+
+    explicit
+    directory_entry(const filesystem::path& __p)
+    : _M_path(__p)
+    { refresh(); }
+
+    directory_entry(const filesystem::path& __p, error_code& __ec)
+    : _M_path(__p)
+    {
+      refresh(__ec);
+      if (__ec)
+       _M_path.clear();
+    }
+
+    ~directory_entry() = default;
+
+    // modifiers
+    directory_entry& operator=(const directory_entry&) = default;
+    directory_entry& operator=(directory_entry&&) noexcept = default;
+
+    void
+    assign(const filesystem::path& __p)
+    {
+      _M_path = __p;
+      refresh();
+    }
+
+    void
+    assign(const filesystem::path& __p, error_code& __ec)
+    {
+      _M_path = __p;
+      refresh(__ec);
+    }
+
+    void
+    replace_filename(const filesystem::path& __p)
+    {
+      _M_path.replace_filename(__p);
+      refresh();
+    }
+
+    void
+    replace_filename(const filesystem::path& __p, error_code& __ec)
+    {
+      _M_path.replace_filename(__p);
+      refresh(__ec);
+    }
+
+    void refresh() { _M_type = symlink_status().type(); }
+    void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); }
+
+    // observers
+    const filesystem::path& path() const noexcept { return _M_path; }
+    operator const filesystem::path& () const noexcept { return _M_path; }
+
+    bool
+    exists() const
+    { return filesystem::exists(file_status{_M_file_type()}); }
+
+    bool
+    exists(error_code& __ec) const noexcept
+    { return filesystem::exists(file_status{_M_file_type(__ec)}); }
+
+    bool
+    is_block_file() const
+    { return _M_file_type() == file_type::block; }
+
+    bool
+    is_block_file(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::block; }
+
+    bool
+    is_character_file() const
+    { return _M_file_type() == file_type::character; }
+
+    bool
+    is_character_file(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::character; }
+
+    bool
+    is_directory() const
+    { return _M_file_type() == file_type::directory; }
+
+    bool
+    is_directory(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::directory; }
+
+    bool
+    is_fifo() const
+    { return _M_file_type() == file_type::fifo; }
+
+    bool
+    is_fifo(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::fifo; }
+
+    bool
+    is_other() const
+    { return filesystem::is_other(file_status{_M_file_type()}); }
+
+    bool
+    is_other(error_code& __ec) const noexcept
+    { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
+
+    bool
+    is_regular_file() const
+    { return _M_file_type() == file_type::regular; }
+
+    bool
+    is_regular_file(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::regular; }
+
+    bool
+    is_socket() const
+    { return _M_file_type() == file_type::socket; }
+
+    bool
+    is_socket(error_code& __ec) const noexcept
+    { return _M_file_type(__ec) == file_type::socket; }
+
+    bool
+    is_symlink() const
+    {
+      if (_M_type != file_type::none)
+       return _M_type == file_type::symlink;
+      return symlink_status().type() == file_type::symlink;
+    }
+
+    bool
+    is_symlink(error_code& __ec) const noexcept
+    {
+      if (_M_type != file_type::none)
+       return _M_type == file_type::symlink;
+      return symlink_status(__ec).type() == file_type::symlink;
+    }
+
+    uintmax_t
+    file_size() const
+    { return filesystem::file_size(_M_path); }
+
+    uintmax_t
+    file_size(error_code& __ec) const noexcept
+    { return filesystem::file_size(_M_path, __ec); }
+
+    uintmax_t
+    hard_link_count() const
+    { return filesystem::hard_link_count(_M_path); }
+
+    uintmax_t
+    hard_link_count(error_code& __ec) const noexcept
+    { return filesystem::hard_link_count(_M_path, __ec); }
+
+    file_time_type
+    last_write_time() const
+    { return filesystem::last_write_time(_M_path); }
+
+
+    file_time_type
+    last_write_time(error_code& __ec) const noexcept
+    { return filesystem::last_write_time(_M_path, __ec); }
+
+    file_status
+    status() const
+    { return filesystem::status(_M_path); }
+
+    file_status
+    status(error_code& __ec) const noexcept
+    { return filesystem::status(_M_path, __ec); }
+
+    file_status
+    symlink_status() const
+    { return filesystem::symlink_status(_M_path); }
+
+    file_status
+    symlink_status(error_code& __ec) const noexcept
+    { return filesystem::symlink_status(_M_path, __ec); }
+
+    bool
+    operator< (const directory_entry& __rhs) const noexcept
+    { return _M_path < __rhs._M_path; }
+
+    bool
+    operator==(const directory_entry& __rhs) const noexcept
+    { return _M_path == __rhs._M_path; }
+
+    bool
+    operator!=(const directory_entry& __rhs) const noexcept
+    { return _M_path != __rhs._M_path; }
+
+    bool
+    operator<=(const directory_entry& __rhs) const noexcept
+    { return _M_path <= __rhs._M_path; }
+
+    bool
+    operator> (const directory_entry& __rhs) const noexcept
+    { return _M_path > __rhs._M_path; }
+
+    bool
+    operator>=(const directory_entry& __rhs) const noexcept
+    { return _M_path >= __rhs._M_path; }
+
+  private:
+    friend class _Dir;
+    friend class directory_iterator;
+    friend class recursive_directory_iterator;
+
+    directory_entry(const filesystem::path& __p, file_type __t)
+    : _M_path(__p), _M_type(__t)
+    { }
+
+    // Equivalent to status().type() but uses cached value, if any.
+    file_type
+    _M_file_type() const
+    {
+      if (_M_type != file_type::none && _M_type != file_type::symlink)
+       return _M_type;
+      return status().type();
+    }
+
+    // Equivalent to status(__ec).type() but uses cached value, if any.
+    file_type
+    _M_file_type(error_code& __ec) const noexcept
+    {
+      if (_M_type != file_type::none && _M_type != file_type::symlink)
+       return _M_type;
+      return status(__ec).type();
+    }
+
+    filesystem::path   _M_path;
+    file_type          _M_type = file_type::none;
+  };
+
+  struct __directory_iterator_proxy
+  {
+    const directory_entry& operator*() const& noexcept { return _M_entry; }
+
+    directory_entry operator*() && noexcept { return std::move(_M_entry); }
+
+  private:
+    friend class directory_iterator;
+    friend class recursive_directory_iterator;
+
+    explicit
+    __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
+
+    directory_entry _M_entry;
+  };
+
+  class directory_iterator
+  {
+  public:
+    typedef directory_entry        value_type;
+    typedef ptrdiff_t              difference_type;
+    typedef const directory_entry* pointer;
+    typedef const directory_entry& reference;
+    typedef input_iterator_tag     iterator_category;
+
+    directory_iterator() = default;
+
+    explicit
+    directory_iterator(const path& __p)
+    : directory_iterator(__p, directory_options::none, nullptr) { }
+
+    directory_iterator(const path& __p, directory_options __options)
+    : directory_iterator(__p, __options, nullptr) { }
+
+    directory_iterator(const path& __p, error_code& __ec) noexcept
+    : directory_iterator(__p, directory_options::none, __ec) { }
+
+    directory_iterator(const path& __p,
+                      directory_options __options,
+                      error_code& __ec) noexcept
+    : directory_iterator(__p, __options, &__ec) { }
+
+    directory_iterator(const directory_iterator& __rhs) = default;
+
+    directory_iterator(directory_iterator&& __rhs) noexcept = default;
+
+    ~directory_iterator() = default;
+
+    directory_iterator&
+    operator=(const directory_iterator& __rhs) = default;
+
+    directory_iterator&
+    operator=(directory_iterator&& __rhs) noexcept = default;
+
+    const directory_entry& operator*() const;
+    const directory_entry* operator->() const { return &**this; }
+    directory_iterator&    operator++();
+    directory_iterator&    increment(error_code& __ec) noexcept;
+
+    __directory_iterator_proxy operator++(int)
+    {
+      __directory_iterator_proxy __pr{**this};
+      ++*this;
+      return __pr;
+    }
+
+  private:
+    directory_iterator(const path&, directory_options, error_code*);
+
+    friend bool
+    operator==(const directory_iterator& __lhs,
+               const directory_iterator& __rhs);
+
+    friend class recursive_directory_iterator;
+
+    std::shared_ptr<_Dir> _M_dir;
+  };
+
+  inline directory_iterator
+  begin(directory_iterator __iter) noexcept
+  { return __iter; }
+
+  inline directory_iterator
+  end(directory_iterator) noexcept
+  { return directory_iterator(); }
+
+  inline bool
+  operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
+  {
+    return !__rhs._M_dir.owner_before(__lhs._M_dir)
+      && !__lhs._M_dir.owner_before(__rhs._M_dir);
+  }
+
+  inline bool
+  operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
+  { return !(__lhs == __rhs); }
+
+  class recursive_directory_iterator
+  {
+  public:
+    typedef directory_entry        value_type;
+    typedef ptrdiff_t              difference_type;
+    typedef const directory_entry* pointer;
+    typedef const directory_entry& reference;
+    typedef input_iterator_tag     iterator_category;
+
+    recursive_directory_iterator() = default;
+
+    explicit
+    recursive_directory_iterator(const path& __p)
+    : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
+
+    recursive_directory_iterator(const path& __p, directory_options __options)
+    : recursive_directory_iterator(__p, __options, nullptr) { }
+
+    recursive_directory_iterator(const path& __p,
+                                 directory_options __options,
+                                 error_code& __ec) noexcept
+    : recursive_directory_iterator(__p, __options, &__ec) { }
+
+    recursive_directory_iterator(const path& __p, error_code& __ec) noexcept
+    : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
+
+    recursive_directory_iterator(
+        const recursive_directory_iterator&) = default;
+
+    recursive_directory_iterator(recursive_directory_iterator&&) = default;
+
+    ~recursive_directory_iterator();
+
+    // observers
+    directory_options  options() const { return _M_options; }
+    int                depth() const;
+    bool               recursion_pending() const { return _M_pending; }
+
+    const directory_entry& operator*() const;
+    const directory_entry* operator->() const { return &**this; }
+
+    // modifiers
+    recursive_directory_iterator&
+    operator=(const recursive_directory_iterator& __rhs) noexcept;
+    recursive_directory_iterator&
+    operator=(recursive_directory_iterator&& __rhs) noexcept;
+
+    recursive_directory_iterator& operator++();
+    recursive_directory_iterator& increment(error_code& __ec) noexcept;
+
+    __directory_iterator_proxy operator++(int)
+    {
+      __directory_iterator_proxy __pr{**this};
+      ++*this;
+      return __pr;
+    }
+
+    void pop();
+    void pop(error_code&);
+
+    void disable_recursion_pending() { _M_pending = false; }
+
+  private:
+    recursive_directory_iterator(const path&, directory_options, error_code*);
+
+    friend bool
+    operator==(const recursive_directory_iterator& __lhs,
+               const recursive_directory_iterator& __rhs);
+
+    struct _Dir_stack;
+    std::shared_ptr<_Dir_stack> _M_dirs;
+    directory_options _M_options = {};
+    bool _M_pending = false;
+  };
+
+  inline recursive_directory_iterator
+  begin(recursive_directory_iterator __iter) noexcept
+  { return __iter; }
+
+  inline recursive_directory_iterator
+  end(recursive_directory_iterator) noexcept
+  { return recursive_directory_iterator(); }
+
+  inline bool
+  operator==(const recursive_directory_iterator& __lhs,
+             const recursive_directory_iterator& __rhs)
+  {
+    return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
+      && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
+  }
+
+  inline bool
+  operator!=(const recursive_directory_iterator& __lhs,
+             const recursive_directory_iterator& __rhs)
+  { return !(__lhs == __rhs); }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+
+  // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_DIR_H
diff --git a/libstdc++-v3/include/bits/fs_fwd.h b/libstdc++-v3/include/bits/fs_fwd.h
new file mode 100644 (file)
index 0000000..f408a39
--- /dev/null
@@ -0,0 +1,348 @@
+// Filesystem declarations -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_fwd.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_FWD_H
+#define _GLIBCXX_FS_FWD_H 1
+
+#if __cplusplus >= 201703L
+
+#include <system_error>
+#include <cstdint>
+#include <chrono>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+#if _GLIBCXX_USE_CXX11_ABI
+inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
+#endif
+
+  /**
+   * @defgroup filesystem Filesystem
+   *
+   * Utilities for performing operations on file systems and their components,
+   * such as paths, regular files, and directories.
+   *
+   * @{
+   */
+
+  class file_status;
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+  class path;
+  class filesystem_error;
+  class directory_entry;
+  class directory_iterator;
+  class recursive_directory_iterator;
+_GLIBCXX_END_NAMESPACE_CXX11
+
+  struct space_info
+  {
+    uintmax_t capacity;
+    uintmax_t free;
+    uintmax_t available;
+  };
+
+  enum class file_type : signed char {
+      none = 0, not_found = -1, regular = 1, directory = 2, symlink = 3,
+      block = 4, character = 5, fifo = 6, socket = 7, unknown = 8
+  };
+
+  /// Bitmask type
+  enum class copy_options : unsigned short {
+      none = 0,
+      skip_existing = 1, overwrite_existing = 2, update_existing = 4,
+      recursive = 8,
+      copy_symlinks = 16, skip_symlinks = 32,
+      directories_only = 64, create_symlinks = 128, create_hard_links = 256
+  };
+
+  constexpr copy_options
+  operator&(copy_options __x, copy_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<copy_options>::type;
+    return static_cast<copy_options>(
+       static_cast<__utype>(__x) & static_cast<__utype>(__y));
+  }
+
+  constexpr copy_options
+  operator|(copy_options __x, copy_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<copy_options>::type;
+    return static_cast<copy_options>(
+       static_cast<__utype>(__x) | static_cast<__utype>(__y));
+  }
+
+  constexpr copy_options
+  operator^(copy_options __x, copy_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<copy_options>::type;
+    return static_cast<copy_options>(
+       static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+  }
+
+  constexpr copy_options
+  operator~(copy_options __x) noexcept
+  {
+    using __utype = typename std::underlying_type<copy_options>::type;
+    return static_cast<copy_options>(~static_cast<__utype>(__x));
+  }
+
+  inline copy_options&
+  operator&=(copy_options& __x, copy_options __y) noexcept
+  { return __x = __x & __y; }
+
+  inline copy_options&
+  operator|=(copy_options& __x, copy_options __y) noexcept
+  { return __x = __x | __y; }
+
+  inline copy_options&
+  operator^=(copy_options& __x, copy_options __y) noexcept
+  { return __x = __x ^ __y; }
+
+
+  /// Bitmask type
+  enum class perms : unsigned {
+      none             =  0,
+      owner_read       =  0400,
+      owner_write      =  0200,
+      owner_exec       =  0100,
+      owner_all                =  0700,
+      group_read       =   040,
+      group_write      =   020,
+      group_exec       =   010,
+      group_all                =   070,
+      others_read      =    04,
+      others_write     =    02,
+      others_exec      =    01,
+      others_all       =    07,
+      all              =  0777,
+      set_uid          = 04000,
+      set_gid          = 02000,
+      sticky_bit       = 01000,
+      mask             = 07777,
+      unknown          =  0xFFFF,
+  };
+
+  constexpr perms
+  operator&(perms __x, perms __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perms>::type;
+    return static_cast<perms>(
+       static_cast<__utype>(__x) & static_cast<__utype>(__y));
+  }
+
+  constexpr perms
+  operator|(perms __x, perms __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perms>::type;
+    return static_cast<perms>(
+       static_cast<__utype>(__x) | static_cast<__utype>(__y));
+  }
+
+  constexpr perms
+  operator^(perms __x, perms __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perms>::type;
+    return static_cast<perms>(
+       static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+  }
+
+  constexpr perms
+  operator~(perms __x) noexcept
+  {
+    using __utype = typename std::underlying_type<perms>::type;
+    return static_cast<perms>(~static_cast<__utype>(__x));
+  }
+
+  inline perms&
+  operator&=(perms& __x, perms __y) noexcept
+  { return __x = __x & __y; }
+
+  inline perms&
+  operator|=(perms& __x, perms __y) noexcept
+  { return __x = __x | __y; }
+
+  inline perms&
+  operator^=(perms& __x, perms __y) noexcept
+  { return __x = __x ^ __y; }
+
+  /// Bitmask type
+  enum class perm_options : unsigned {
+      replace  = 0x1,
+      add      = 0x2,
+      remove   = 0x4,
+      nofollow = 0x8
+  };
+
+  constexpr perm_options
+  operator&(perm_options __x, perm_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perm_options>::type;
+    return static_cast<perm_options>(
+       static_cast<__utype>(__x) & static_cast<__utype>(__y));
+  }
+
+  constexpr perm_options
+  operator|(perm_options __x, perm_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perm_options>::type;
+    return static_cast<perm_options>(
+       static_cast<__utype>(__x) | static_cast<__utype>(__y));
+  }
+
+  constexpr perm_options
+  operator^(perm_options __x, perm_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<perm_options>::type;
+    return static_cast<perm_options>(
+       static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+  }
+
+  constexpr perm_options
+  operator~(perm_options __x) noexcept
+  {
+    using __utype = typename std::underlying_type<perm_options>::type;
+    return static_cast<perm_options>(~static_cast<__utype>(__x));
+  }
+
+  inline perm_options&
+  operator&=(perm_options& __x, perm_options __y) noexcept
+  { return __x = __x & __y; }
+
+  inline perm_options&
+  operator|=(perm_options& __x, perm_options __y) noexcept
+  { return __x = __x | __y; }
+
+  inline perm_options&
+  operator^=(perm_options& __x, perm_options __y) noexcept
+  { return __x = __x ^ __y; }
+
+  // Bitmask type
+  enum class directory_options : unsigned char {
+      none = 0, follow_directory_symlink = 1, skip_permission_denied = 2
+  };
+
+  constexpr directory_options
+  operator&(directory_options __x, directory_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<directory_options>::type;
+    return static_cast<directory_options>(
+       static_cast<__utype>(__x) & static_cast<__utype>(__y));
+  }
+
+  constexpr directory_options
+  operator|(directory_options __x, directory_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<directory_options>::type;
+    return static_cast<directory_options>(
+       static_cast<__utype>(__x) | static_cast<__utype>(__y));
+  }
+
+  constexpr directory_options
+  operator^(directory_options __x, directory_options __y) noexcept
+  {
+    using __utype = typename std::underlying_type<directory_options>::type;
+    return static_cast<directory_options>(
+       static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+  }
+
+  constexpr directory_options
+  operator~(directory_options __x) noexcept
+  {
+    using __utype = typename std::underlying_type<directory_options>::type;
+    return static_cast<directory_options>(~static_cast<__utype>(__x));
+  }
+
+  inline directory_options&
+  operator&=(directory_options& __x, directory_options __y) noexcept
+  { return __x = __x & __y; }
+
+  inline directory_options&
+  operator|=(directory_options& __x, directory_options __y) noexcept
+  { return __x = __x | __y; }
+
+  inline directory_options&
+  operator^=(directory_options& __x, directory_options __y) noexcept
+  { return __x = __x ^ __y; }
+
+  using file_time_type = std::chrono::system_clock::time_point;
+
+  // operational functions
+
+  void copy(const path& __from, const path& __to, copy_options __options);
+  void copy(const path& __from, const path& __to, copy_options __options,
+           error_code&) noexcept;
+
+  bool copy_file(const path& __from, const path& __to, copy_options __option);
+  bool copy_file(const path& __from, const path& __to, copy_options __option,
+                error_code&) noexcept;
+
+  path current_path();
+
+  bool exists(file_status) noexcept;
+
+  bool is_other(file_status) noexcept;
+
+  uintmax_t file_size(const path&);
+  uintmax_t file_size(const path&, error_code&) noexcept;
+  uintmax_t hard_link_count(const path&);
+  uintmax_t hard_link_count(const path&, error_code&) noexcept;
+  file_time_type last_write_time(const path&);
+  file_time_type last_write_time(const path&, error_code&) noexcept;
+
+  void permissions(const path&, perms, perm_options, error_code&);
+
+  path proximate(const path& __p, const path& __base, error_code& __ec);
+  path proximate(const path& __p, const path& __base, error_code& __ec);
+
+  path relative(const path& __p, const path& __base, error_code& __ec);
+
+  file_status status(const path&);
+  file_status status(const path&, error_code&) noexcept;
+
+  bool status_known(file_status) noexcept;
+
+  file_status symlink_status(const path&);
+  file_status symlink_status(const path&, error_code&) noexcept;
+
+  bool is_regular_file(file_status) noexcept;
+  bool is_symlink(file_status) noexcept;
+
+  // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_FWD_H
diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h
new file mode 100644 (file)
index 0000000..563d63d
--- /dev/null
@@ -0,0 +1,311 @@
+// Filesystem operational functions -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_fwd.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_OPS_H
+#define _GLIBCXX_FS_OPS_H 1
+
+#if __cplusplus >= 201703L
+
+#include <cstdint>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+  /**
+   * @ingroup filesystem
+   * @{
+   */
+
+  path absolute(const path& __p);
+  path absolute(const path& __p, error_code& __ec);
+
+  path canonical(const path& __p);
+  path canonical(const path& __p, error_code& __ec);
+
+  inline void
+  copy(const path& __from, const path& __to)
+  { copy(__from, __to, copy_options::none); }
+
+  inline void
+  copy(const path& __from, const path& __to, error_code& __ec) noexcept
+  { copy(__from, __to, copy_options::none, __ec); }
+
+  void copy(const path& __from, const path& __to, copy_options __options);
+  void copy(const path& __from, const path& __to, copy_options __options,
+           error_code& __ec) noexcept;
+
+  inline bool
+  copy_file(const path& __from, const path& __to)
+  { return copy_file(__from, __to, copy_options::none); }
+
+  inline bool
+  copy_file(const path& __from, const path& __to, error_code& __ec) noexcept
+  { return copy_file(__from, __to, copy_options::none, __ec); }
+
+  bool copy_file(const path& __from, const path& __to, copy_options __option);
+  bool copy_file(const path& __from, const path& __to, copy_options __option,
+                error_code& __ec) noexcept;
+
+  void copy_symlink(const path& __existing_symlink, const path& __new_symlink);
+  void copy_symlink(const path& __existing_symlink, const path& __new_symlink,
+                   error_code& __ec) noexcept;
+
+  bool create_directories(const path& __p);
+  bool create_directories(const path& __p, error_code& __ec) noexcept;
+
+  bool create_directory(const path& __p);
+  bool create_directory(const path& __p, error_code& __ec) noexcept;
+
+  bool create_directory(const path& __p, const path& attributes);
+  bool create_directory(const path& __p, const path& attributes,
+                       error_code& __ec) noexcept;
+
+  void create_directory_symlink(const path& __to, const path& __new_symlink);
+  void create_directory_symlink(const path& __to, const path& __new_symlink,
+                               error_code& __ec) noexcept;
+
+  void create_hard_link(const path& __to, const path& __new_hard_link);
+  void create_hard_link(const path& __to, const path& __new_hard_link,
+                       error_code& __ec) noexcept;
+
+  void create_symlink(const path& __to, const path& __new_symlink);
+  void create_symlink(const path& __to, const path& __new_symlink,
+                     error_code& __ec) noexcept;
+
+  path current_path();
+  path current_path(error_code& __ec);
+  void current_path(const path& __p);
+  void current_path(const path& __p, error_code& __ec) noexcept;
+
+  bool
+  equivalent(const path& __p1, const path& __p2);
+
+  bool
+  equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept;
+
+  inline bool
+  exists(file_status __s) noexcept
+  { return status_known(__s) && __s.type() != file_type::not_found; }
+
+  inline bool
+  exists(const path& __p)
+  { return exists(status(__p)); }
+
+  inline bool
+  exists(const path& __p, error_code& __ec) noexcept
+  {
+    auto __s = status(__p, __ec);
+    if (status_known(__s))
+      __ec.clear();
+    return exists(__s);
+  }
+
+  uintmax_t file_size(const path& __p);
+  uintmax_t file_size(const path& __p, error_code& __ec) noexcept;
+
+  uintmax_t hard_link_count(const path& __p);
+  uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept;
+
+  inline bool
+  is_block_file(file_status __s) noexcept
+  { return __s.type() == file_type::block; }
+
+  inline bool
+  is_block_file(const path& __p)
+  { return is_block_file(status(__p)); }
+
+  inline bool
+  is_block_file(const path& __p, error_code& __ec) noexcept
+  { return is_block_file(status(__p, __ec)); }
+
+  inline bool
+  is_character_file(file_status __s) noexcept
+  { return __s.type() == file_type::character; }
+
+  inline bool
+  is_character_file(const path& __p)
+  { return is_character_file(status(__p)); }
+
+  inline bool
+  is_character_file(const path& __p, error_code& __ec) noexcept
+  { return is_character_file(status(__p, __ec)); }
+
+  inline bool
+  is_directory(file_status __s) noexcept
+  { return __s.type() == file_type::directory; }
+
+  inline bool
+  is_directory(const path& __p)
+  { return is_directory(status(__p)); }
+
+  inline bool
+  is_directory(const path& __p, error_code& __ec) noexcept
+  { return is_directory(status(__p, __ec)); }
+
+  bool is_empty(const path& __p);
+  bool is_empty(const path& __p, error_code& __ec) noexcept;
+
+  inline bool
+  is_fifo(file_status __s) noexcept
+  { return __s.type() == file_type::fifo; }
+
+  inline bool
+  is_fifo(const path& __p)
+  { return is_fifo(status(__p)); }
+
+  inline bool
+  is_fifo(const path& __p, error_code& __ec) noexcept
+  { return is_fifo(status(__p, __ec)); }
+
+  inline bool
+  is_other(file_status __s) noexcept
+  {
+    return exists(__s) && !is_regular_file(__s) && !is_directory(__s)
+      && !is_symlink(__s);
+  }
+
+  inline bool
+  is_other(const path& __p)
+  { return is_other(status(__p)); }
+
+  inline bool
+  is_other(const path& __p, error_code& __ec) noexcept
+  { return is_other(status(__p, __ec)); }
+
+  inline bool
+  is_regular_file(file_status __s) noexcept
+  { return __s.type() == file_type::regular; }
+
+  inline bool
+  is_regular_file(const path& __p)
+  { return is_regular_file(status(__p)); }
+
+  inline bool
+  is_regular_file(const path& __p, error_code& __ec) noexcept
+  { return is_regular_file(status(__p, __ec)); }
+
+  inline bool
+  is_socket(file_status __s) noexcept
+  { return __s.type() == file_type::socket; }
+
+  inline bool
+  is_socket(const path& __p)
+  { return is_socket(status(__p)); }
+
+  inline bool
+  is_socket(const path& __p, error_code& __ec) noexcept
+  { return is_socket(status(__p, __ec)); }
+
+  inline bool
+  is_symlink(file_status __s) noexcept
+  { return __s.type() == file_type::symlink; }
+
+  inline bool
+  is_symlink(const path& __p)
+  { return is_symlink(symlink_status(__p)); }
+
+  inline bool
+  is_symlink(const path& __p, error_code& __ec) noexcept
+  { return is_symlink(symlink_status(__p, __ec)); }
+
+  file_time_type  last_write_time(const path& __p);
+  file_time_type  last_write_time(const path& __p, error_code& __ec) noexcept;
+  void last_write_time(const path& __p, file_time_type __new_time);
+  void last_write_time(const path& __p, file_time_type __new_time,
+                      error_code& __ec) noexcept;
+
+  void
+  permissions(const path& __p, perms __prms,
+             perm_options __opts = perm_options::replace);
+
+  inline void
+  permissions(const path& __p, perms __prms, error_code& __ec) noexcept
+  { permissions(__p, __prms, perm_options::replace, __ec); }
+
+  void
+  permissions(const path& __p, perms __prms, perm_options __opts,
+             error_code& __ec);
+
+  inline path proximate(const path& __p, error_code& __ec)
+  { return proximate(__p, current_path(), __ec); }
+
+  path proximate(const path& __p, const path& __base = current_path());
+  path proximate(const path& __p, const path& __base, error_code& __ec);
+
+  path read_symlink(const path& __p);
+  path read_symlink(const path& __p, error_code& __ec);
+
+  inline path relative(const path& __p, error_code& __ec)
+  { return relative(__p, current_path(), __ec); }
+
+  path relative(const path& __p, const path& __base = current_path());
+  path relative(const path& __p, const path& __base, error_code& __ec);
+
+  bool remove(const path& __p);
+  bool remove(const path& __p, error_code& __ec) noexcept;
+
+  uintmax_t remove_all(const path& __p);
+  uintmax_t remove_all(const path& __p, error_code& __ec) noexcept;
+
+  void rename(const path& __from, const path& __to);
+  void rename(const path& __from, const path& __to, error_code& __ec) noexcept;
+
+  void resize_file(const path& __p, uintmax_t __size);
+  void resize_file(const path& __p, uintmax_t __size, error_code& __ec) noexcept;
+
+  space_info space(const path& __p);
+  space_info space(const path& __p, error_code& __ec) noexcept;
+
+  file_status status(const path& __p);
+  file_status status(const path& __p, error_code& __ec) noexcept;
+
+  inline bool status_known(file_status __s) noexcept
+  { return __s.type() != file_type::none; }
+
+  file_status symlink_status(const path& __p);
+  file_status symlink_status(const path& __p, error_code& __ec) noexcept;
+
+  path temp_directory_path();
+  path temp_directory_path(error_code& __ec);
+
+  path weakly_canonical(const path& __p);
+  path weakly_canonical(const path& __p, error_code& __ec);
+
+  // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_OPS_H
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
new file mode 100644 (file)
index 0000000..6ba2bd2
--- /dev/null
@@ -0,0 +1,1163 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_path.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_PATH_H
+#define _GLIBCXX_FS_PATH_H 1
+
+#if __cplusplus >= 201703L
+
+#include <utility>
+#include <type_traits>
+#include <vector>
+#include <locale>
+#include <iosfwd>
+#include <codecvt>
+#include <string_view>
+#include <system_error>
+#include <bits/stl_algobase.h>
+#include <bits/quoted_string.h>
+#include <bits/locale_conv.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
+# include <algorithm>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+  /**
+   * @ingroup filesystem
+   * @{
+   */
+
+  /// A filesystem path.
+  class path
+  {
+    template<typename _CharT>
+      struct __is_encoded_char : std::false_type { };
+
+    template<typename _Iter,
+            typename _Iter_traits = std::iterator_traits<_Iter>>
+      using __is_path_iter_src
+       = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
+                std::is_base_of<std::input_iterator_tag,
+                                typename _Iter_traits::iterator_category>>;
+
+    template<typename _Iter>
+      static __is_path_iter_src<_Iter>
+      __is_path_src(_Iter, int);
+
+    template<typename _CharT, typename _Traits, typename _Alloc>
+      static __is_encoded_char<_CharT>
+      __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
+
+    template<typename _CharT, typename _Traits>
+      static __is_encoded_char<_CharT>
+      __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
+
+    template<typename _Unknown>
+      static std::false_type
+      __is_path_src(const _Unknown&, ...);
+
+    template<typename _Tp1, typename _Tp2>
+      struct __constructible_from;
+
+    template<typename _Iter>
+      struct __constructible_from<_Iter, _Iter>
+      : __is_path_iter_src<_Iter>
+      { };
+
+    template<typename _Source>
+      struct __constructible_from<_Source, void>
+      : decltype(__is_path_src(std::declval<_Source>(), 0))
+      { };
+
+    template<typename _Tp1, typename _Tp2 = void>
+      using _Path = typename
+       std::enable_if<__and_<__not_<is_same<_Tp1, path>>,
+                             __constructible_from<_Tp1, _Tp2>>::value,
+                      path>::type;
+
+    template<typename _Source>
+      static _Source
+      _S_range_begin(_Source __begin) { return __begin; }
+
+    struct __null_terminated { };
+
+    template<typename _Source>
+      static __null_terminated
+      _S_range_end(_Source) { return {}; }
+
+    template<typename _CharT, typename _Traits, typename _Alloc>
+      static const _CharT*
+      _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
+      { return __str.data(); }
+
+    template<typename _CharT, typename _Traits, typename _Alloc>
+      static const _CharT*
+      _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
+      { return __str.data() + __str.size(); }
+
+    template<typename _CharT, typename _Traits>
+      static const _CharT*
+      _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
+      { return __str.data(); }
+
+    template<typename _CharT, typename _Traits>
+      static const _CharT*
+      _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
+      { return __str.data() + __str.size(); }
+
+    template<typename _Tp,
+            typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
+            typename _Val = typename std::iterator_traits<_Iter>::value_type>
+      using __value_type_is_char
+       = typename std::enable_if<std::is_same<_Val, char>::value>::type;
+
+  public:
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    typedef wchar_t                            value_type;
+    static constexpr value_type                        preferred_separator = L'\\';
+#else
+    typedef char                               value_type;
+    static constexpr value_type                        preferred_separator = '/';
+#endif
+    typedef std::basic_string<value_type>      string_type;
+
+    // constructors and destructor
+
+    path() noexcept { }
+
+    path(const path& __p) = default;
+
+    path(path&& __p) noexcept
+    : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
+    {
+      _M_split_cmpts();
+      __p.clear();
+    }
+
+    path(string_type&& __source)
+    : _M_pathname(std::move(__source))
+    { _M_split_cmpts(); }
+
+    template<typename _Source,
+            typename _Require = _Path<_Source>>
+      path(_Source const& __source)
+      : _M_pathname(_S_convert(_S_range_begin(__source),
+                              _S_range_end(__source)))
+      { _M_split_cmpts(); }
+
+    template<typename _InputIterator,
+            typename _Require = _Path<_InputIterator, _InputIterator>>
+      path(_InputIterator __first, _InputIterator __last)
+      : _M_pathname(_S_convert(__first, __last))
+      { _M_split_cmpts(); }
+
+    template<typename _Source,
+            typename _Require = _Path<_Source>,
+            typename _Require2 = __value_type_is_char<_Source>>
+      path(_Source const& __source, const locale& __loc)
+      : _M_pathname(_S_convert_loc(_S_range_begin(__source),
+                                  _S_range_end(__source), __loc))
+      { _M_split_cmpts(); }
+
+    template<typename _InputIterator,
+            typename _Require = _Path<_InputIterator, _InputIterator>,
+            typename _Require2 = __value_type_is_char<_InputIterator>>
+      path(_InputIterator __first, _InputIterator __last, const locale& __loc)
+      : _M_pathname(_S_convert_loc(__first, __last, __loc))
+      { _M_split_cmpts(); }
+
+    ~path() = default;
+
+    // assignments
+
+    path& operator=(const path& __p) = default;
+    path& operator=(path&& __p) noexcept;
+    path& operator=(string_type&& __source);
+    path& assign(string_type&& __source);
+
+    template<typename _Source>
+      _Path<_Source>&
+      operator=(_Source const& __source)
+      { return *this = path(__source); }
+
+    template<typename _Source>
+      _Path<_Source>&
+      assign(_Source const& __source)
+      { return *this = path(__source); }
+
+    template<typename _InputIterator>
+      _Path<_InputIterator, _InputIterator>&
+      assign(_InputIterator __first, _InputIterator __last)
+      { return *this = path(__first, __last); }
+
+    // appends
+
+    path& operator/=(const path& __p)
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      if (__p.is_absolute()
+         || (__p.has_root_name() && __p.root_name() != root_name()))
+       operator=(__p);
+      else
+       {
+         string_type __pathname;
+         if (__p.has_root_directory())
+           __pathname = root_name().native();
+         else if (has_filename() || (!has_root_directory() && is_absolute()))
+           __pathname = _M_pathname + preferred_separator;
+         __pathname += __p.relative_path().native(); // XXX is this right?
+         _M_pathname.swap(__pathname);
+         _M_split_cmpts();
+       }
+#else
+      // Much simpler, as any path with root-name or root-dir is absolute.
+      if (__p.is_absolute())
+       operator=(__p);
+      else
+       {
+         if (has_filename() || (_M_type == _Type::_Root_name))
+           _M_pathname += preferred_separator;
+         _M_pathname += __p.native();
+         _M_split_cmpts();
+       }
+#endif
+      return *this;
+    }
+
+    template <class _Source>
+      _Path<_Source>&
+      operator/=(_Source const& __source)
+      { return append(__source); }
+
+    template<typename _Source>
+      _Path<_Source>&
+      append(_Source const& __source)
+      {
+       return _M_append(_S_convert(_S_range_begin(__source),
+                                   _S_range_end(__source)));
+      }
+
+    template<typename _InputIterator>
+      _Path<_InputIterator, _InputIterator>&
+      append(_InputIterator __first, _InputIterator __last)
+      { return _M_append(_S_convert(__first, __last)); }
+
+    // concatenation
+
+    path& operator+=(const path& __x);
+    path& operator+=(const string_type& __x);
+    path& operator+=(const value_type* __x);
+    path& operator+=(value_type __x);
+    path& operator+=(basic_string_view<value_type> __x);
+
+    template<typename _Source>
+      _Path<_Source>&
+      operator+=(_Source const& __x) { return concat(__x); }
+
+    template<typename _CharT>
+      _Path<_CharT*, _CharT*>&
+      operator+=(_CharT __x);
+
+    template<typename _Source>
+      _Path<_Source>&
+      concat(_Source const& __x)
+      { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
+
+    template<typename _InputIterator>
+      _Path<_InputIterator, _InputIterator>&
+      concat(_InputIterator __first, _InputIterator __last)
+      { return *this += _S_convert(__first, __last); }
+
+    // modifiers
+
+    void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
+
+    path& make_preferred();
+    path& remove_filename();
+    path& replace_filename(const path& __replacement);
+    path& replace_extension(const path& __replacement = path());
+
+    void swap(path& __rhs) noexcept;
+
+    // native format observers
+
+    const string_type&  native() const noexcept { return _M_pathname; }
+    const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
+    operator string_type() const { return _M_pathname; }
+
+    template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
+            typename _Allocator = std::allocator<_CharT>>
+      std::basic_string<_CharT, _Traits, _Allocator>
+      string(const _Allocator& __a = _Allocator()) const;
+
+    std::string    string() const;
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring   wstring() const;
+#endif
+    std::string    u8string() const;
+    std::u16string u16string() const;
+    std::u32string u32string() const;
+
+    // generic format observers
+    template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
+            typename _Allocator = std::allocator<_CharT>>
+      std::basic_string<_CharT, _Traits, _Allocator>
+      generic_string(const _Allocator& __a = _Allocator()) const;
+
+    std::string    generic_string() const;
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring   generic_wstring() const;
+#endif
+    std::string    generic_u8string() const;
+    std::u16string generic_u16string() const;
+    std::u32string generic_u32string() const;
+
+    // compare
+
+    int compare(const path& __p) const noexcept;
+    int compare(const string_type& __s) const;
+    int compare(const value_type* __s) const;
+    int compare(const basic_string_view<value_type> __s) const;
+
+    // decomposition
+
+    path root_name() const;
+    path root_directory() const;
+    path root_path() const;
+    path relative_path() const;
+    path parent_path() const;
+    path filename() const;
+    path stem() const;
+    path extension() const;
+
+    // query
+
+    bool empty() const noexcept { return _M_pathname.empty(); }
+    bool has_root_name() const;
+    bool has_root_directory() const;
+    bool has_root_path() const;
+    bool has_relative_path() const;
+    bool has_parent_path() const;
+    bool has_filename() const;
+    bool has_stem() const;
+    bool has_extension() const;
+    bool is_absolute() const;
+    bool is_relative() const { return !is_absolute(); }
+
+    // generation
+    path lexically_normal() const;
+    path lexically_relative(const path& base) const;
+    path lexically_proximate(const path& base) const;
+
+    // iterators
+    class iterator;
+    typedef iterator const_iterator;
+
+    iterator begin() const;
+    iterator end() const;
+
+  private:
+    enum class _Type : unsigned char {
+       _Multi, _Root_name, _Root_dir, _Filename
+    };
+
+    path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
+    {
+      __glibcxx_assert(_M_type != _Type::_Multi);
+    }
+
+    enum class _Split { _Stem, _Extension };
+
+    path& _M_append(string_type&& __str)
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      operator/=(path(std::move(__str)));
+#else
+      if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
+         && (__str.empty() || !_S_is_dir_sep(__str.front())))
+       _M_pathname += preferred_separator;
+      _M_pathname += __str;
+      _M_split_cmpts();
+#endif
+      return *this;
+    }
+
+    pair<const string_type*, size_t> _M_find_extension() const;
+
+    template<typename _CharT>
+      struct _Cvt;
+
+    static string_type
+    _S_convert(value_type* __src, __null_terminated)
+    { return string_type(__src); }
+
+    static string_type
+    _S_convert(const value_type* __src, __null_terminated)
+    { return string_type(__src); }
+
+    template<typename _Iter>
+      static string_type
+      _S_convert(_Iter __first, _Iter __last)
+      {
+       using __value_type = typename std::iterator_traits<_Iter>::value_type;
+       return _Cvt<typename remove_cv<__value_type>::type>::
+         _S_convert(__first, __last);
+      }
+
+    template<typename _InputIterator>
+      static string_type
+      _S_convert(_InputIterator __src, __null_terminated)
+      {
+       using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
+       std::basic_string<typename remove_cv<_Tp>::type> __tmp;
+       for (; *__src != _Tp{}; ++__src)
+         __tmp.push_back(*__src);
+       return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
+      }
+
+    static string_type
+    _S_convert_loc(const char* __first, const char* __last,
+                  const std::locale& __loc);
+
+    template<typename _Iter>
+      static string_type
+      _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
+      {
+       const std::string __str(__first, __last);
+       return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
+      }
+
+    template<typename _InputIterator>
+      static string_type
+      _S_convert_loc(_InputIterator __src, __null_terminated,
+                    const std::locale& __loc)
+      {
+       std::string __tmp;
+       while (*__src != '\0')
+         __tmp.push_back(*__src++);
+       return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
+      }
+
+    template<typename _CharT, typename _Traits, typename _Allocator>
+      static basic_string<_CharT, _Traits, _Allocator>
+      _S_str_convert(const string_type&, const _Allocator& __a);
+
+    bool _S_is_dir_sep(value_type __ch)
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      return __ch == L'/' || __ch == preferred_separator;
+#else
+      return __ch == '/';
+#endif
+    }
+
+    void _M_split_cmpts();
+    void _M_trim();
+    void _M_add_root_name(size_t __n);
+    void _M_add_root_dir(size_t __pos);
+    void _M_add_filename(size_t __pos, size_t __n);
+
+    string_type _M_pathname;
+
+    struct _Cmpt;
+    using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
+    _List _M_cmpts; // empty unless _M_type == _Type::_Multi
+    _Type _M_type = _Type::_Multi;
+  };
+
+  template<>
+    struct path::__is_encoded_char<char> : std::true_type
+    { using value_type = char; };
+
+  template<>
+    struct path::__is_encoded_char<wchar_t> : std::true_type
+    { using value_type = wchar_t; };
+
+  template<>
+    struct path::__is_encoded_char<char16_t> : std::true_type
+    { using value_type = char16_t; };
+
+  template<>
+    struct path::__is_encoded_char<char32_t> : std::true_type
+    { using value_type = char32_t; };
+
+  template<typename _Tp>
+    struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+
+  inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
+
+  size_t hash_value(const path& __p) noexcept;
+
+  /// Compare paths
+  inline bool operator<(const path& __lhs, const path& __rhs) noexcept
+  { return __lhs.compare(__rhs) < 0; }
+
+  /// Compare paths
+  inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
+  { return !(__rhs < __lhs); }
+
+  /// Compare paths
+  inline bool operator>(const path& __lhs, const path& __rhs) noexcept
+  { return __rhs < __lhs; }
+
+  /// Compare paths
+  inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
+  { return !(__lhs < __rhs); }
+
+  /// Compare paths
+  inline bool operator==(const path& __lhs, const path& __rhs) noexcept
+  { return __lhs.compare(__rhs) == 0; }
+
+  /// Compare paths
+  inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
+  { return !(__lhs == __rhs); }
+
+  /// Append one path to another
+  inline path operator/(const path& __lhs, const path& __rhs)
+  { return path(__lhs) /= __rhs; }
+
+  /// Write a path to a stream
+  template<typename _CharT, typename _Traits>
+    basic_ostream<_CharT, _Traits>&
+    operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
+    {
+      auto __tmp = __p.string<_CharT, _Traits>();
+      using __quoted_string
+       = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+      __os << __quoted_string{__tmp, '"', '\\'};
+      return __os;
+    }
+
+  /// Read a path from a stream
+  template<typename _CharT, typename _Traits>
+    basic_istream<_CharT, _Traits>&
+    operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
+    {
+      basic_string<_CharT, _Traits> __tmp;
+      using __quoted_string
+       = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+      if (__is >> __quoted_string{ __tmp, '"', '\\' })
+       __p = std::move(__tmp);
+      return __is;
+    }
+
+  template<typename _Source>
+    inline auto
+    u8path(const _Source& __source)
+    -> decltype(filesystem::path(__source, std::locale::classic()))
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      const std::string __u8str{__source};
+      return std::filesystem::u8path(__u8str.begin(), __u8str.end());
+#else
+      return path{ __source };
+#endif
+    }
+
+  template<typename _InputIterator>
+    inline auto
+    u8path(_InputIterator __first, _InputIterator __last)
+    -> decltype(filesystem::path(__first, __last, std::locale::classic()))
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      codecvt_utf8<value_type> __cvt;
+      string_type __tmp;
+      if (__str_codecvt_in(__first, __last, __tmp, __cvt))
+       return path{ __tmp };
+      else
+       return {};
+#else
+      return path{ __first, __last };
+#endif
+    }
+
+  class filesystem_error : public std::system_error
+  {
+  public:
+    filesystem_error(const string& __what_arg, error_code __ec)
+    : system_error(__ec, __what_arg) { }
+
+    filesystem_error(const string& __what_arg, const path& __p1,
+                    error_code __ec)
+    : system_error(__ec, __what_arg), _M_path1(__p1) { }
+
+    filesystem_error(const string& __what_arg, const path& __p1,
+                    const path& __p2, error_code __ec)
+    : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
+    { }
+
+    ~filesystem_error();
+
+    const path& path1() const noexcept { return _M_path1; }
+    const path& path2() const noexcept { return _M_path2; }
+    const char* what() const noexcept { return _M_what.c_str(); }
+
+  private:
+    std::string _M_gen_what();
+
+    path _M_path1;
+    path _M_path2;
+    std::string _M_what = _M_gen_what();
+  };
+
+  struct path::_Cmpt : path
+  {
+    _Cmpt(string_type __s, _Type __t, size_t __pos)
+      : path(std::move(__s), __t), _M_pos(__pos) { }
+
+    _Cmpt() : _M_pos(-1) { }
+
+    size_t _M_pos;
+  };
+
+  // specialize _Cvt for degenerate 'noconv' case
+  template<>
+    struct path::_Cvt<path::value_type>
+    {
+      template<typename _Iter>
+       static string_type
+       _S_convert(_Iter __first, _Iter __last)
+       { return string_type{__first, __last}; }
+    };
+
+  template<typename _CharT>
+    struct path::_Cvt
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      static string_type
+      _S_wconvert(const char* __f, const char* __l, true_type)
+      {
+       using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
+       const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
+       std::wstring __wstr;
+       if (__str_codecvt_in(__f, __l, __wstr, __cvt))
+           return __wstr;
+       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "Cannot convert character sequence",
+             std::make_error_code(errc::illegal_byte_sequence)));
+      }
+
+      static string_type
+      _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
+      {
+       std::codecvt_utf8<_CharT> __cvt;
+       std::string __str;
+       if (__str_codecvt_out(__f, __l, __str, __cvt))
+         {
+           const char* __f2 = __str.data();
+           const char* __l2 = __f2 + __str.size();
+           std::codecvt_utf8<wchar_t> __wcvt;
+           std::wstring __wstr;
+           if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
+             return __wstr;
+         }
+       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "Cannot convert character sequence",
+             std::make_error_code(errc::illegal_byte_sequence)));
+      }
+
+      static string_type
+      _S_convert(const _CharT* __f, const _CharT* __l)
+      {
+       return _S_wconvert(__f, __l, is_same<_CharT, char>{});
+      }
+#else
+      static string_type
+      _S_convert(const _CharT* __f, const _CharT* __l)
+      {
+       std::codecvt_utf8<_CharT> __cvt;
+       std::string __str;
+       if (__str_codecvt_out(__f, __l, __str, __cvt))
+         return __str;
+       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "Cannot convert character sequence",
+             std::make_error_code(errc::illegal_byte_sequence)));
+      }
+#endif
+
+      static string_type
+      _S_convert(_CharT* __f, _CharT* __l)
+      {
+       return _S_convert(const_cast<const _CharT*>(__f),
+                         const_cast<const _CharT*>(__l));
+      }
+
+      template<typename _Iter>
+       static string_type
+       _S_convert(_Iter __first, _Iter __last)
+       {
+         const std::basic_string<_CharT> __str(__first, __last);
+         return _S_convert(__str.data(), __str.data() + __str.size());
+       }
+
+      template<typename _Iter, typename _Cont>
+       static string_type
+       _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
+                 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
+       { return _S_convert(__first.base(), __last.base()); }
+    };
+
+  /// An iterator for the components of a path
+  class path::iterator
+  {
+  public:
+    using difference_type      = std::ptrdiff_t;
+    using value_type           = path;
+    using reference            = const path&;
+    using pointer              = const path*;
+    using iterator_category    = std::bidirectional_iterator_tag;
+
+    iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
+
+    iterator(const iterator&) = default;
+    iterator& operator=(const iterator&) = default;
+
+    reference operator*() const;
+    pointer   operator->() const { return std::__addressof(**this); }
+
+    iterator& operator++();
+    iterator  operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
+
+    iterator& operator--();
+    iterator  operator--(int) { auto __tmp = *this; --*this; return __tmp; }
+
+    friend bool operator==(const iterator& __lhs, const iterator& __rhs)
+    { return __lhs._M_equals(__rhs); }
+
+    friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
+    { return !__lhs._M_equals(__rhs); }
+
+  private:
+    friend class path;
+
+    iterator(const path* __path, path::_List::const_iterator __iter)
+    : _M_path(__path), _M_cur(__iter), _M_at_end()
+    { }
+
+    iterator(const path* __path, bool __at_end)
+    : _M_path(__path), _M_cur(), _M_at_end(__at_end)
+    { }
+
+    bool _M_equals(iterator) const;
+
+    const path*                _M_path;
+    path::_List::const_iterator _M_cur;
+    bool                       _M_at_end;  // only used when type != _Multi
+  };
+
+
+  inline path&
+  path::operator=(path&& __p) noexcept
+  {
+    _M_pathname = std::move(__p._M_pathname);
+    _M_cmpts = std::move(__p._M_cmpts);
+    _M_type = __p._M_type;
+    __p.clear();
+    return *this;
+  }
+
+  inline path&
+  path::operator=(string_type&& __source)
+  { return *this = path(std::move(__source)); }
+
+  inline path&
+  path::assign(string_type&& __source)
+  { return *this = path(std::move(__source)); }
+
+  inline path&
+  path::operator+=(const path& __p)
+  {
+    return operator+=(__p.native());
+  }
+
+  inline path&
+  path::operator+=(const string_type& __x)
+  {
+    _M_pathname += __x;
+    _M_split_cmpts();
+    return *this;
+  }
+
+  inline path&
+  path::operator+=(const value_type* __x)
+  {
+    _M_pathname += __x;
+    _M_split_cmpts();
+    return *this;
+  }
+
+  inline path&
+  path::operator+=(value_type __x)
+  {
+    _M_pathname += __x;
+    _M_split_cmpts();
+    return *this;
+  }
+
+  inline path&
+  path::operator+=(basic_string_view<value_type> __x)
+  {
+    _M_pathname.append(__x.data(), __x.size());
+    _M_split_cmpts();
+    return *this;
+  }
+
+  template<typename _CharT>
+    inline path::_Path<_CharT*, _CharT*>&
+    path::operator+=(_CharT __x)
+    {
+      auto* __addr = std::__addressof(__x);
+      return concat(__addr, __addr + 1);
+    }
+
+  inline path&
+  path::make_preferred()
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
+                preferred_separator);
+#endif
+    return *this;
+  }
+
+  inline void path::swap(path& __rhs) noexcept
+  {
+    _M_pathname.swap(__rhs._M_pathname);
+    _M_cmpts.swap(__rhs._M_cmpts);
+    std::swap(_M_type, __rhs._M_type);
+  }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    std::basic_string<_CharT, _Traits, _Allocator>
+    path::_S_str_convert(const string_type& __str, const _Allocator& __a)
+    {
+      if (__str.size() == 0)
+       return std::basic_string<_CharT, _Traits, _Allocator>(__a);
+
+      const value_type* __first = __str.data();
+      const value_type* __last = __first + __str.size();
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      using _CharAlloc = __alloc_rebind<_Allocator, char>;
+      using _String = basic_string<char, char_traits<char>, _CharAlloc>;
+      using _WString = basic_string<_CharT, _Traits, _Allocator>;
+
+      // use codecvt_utf8<wchar_t> to convert native string to UTF-8
+      codecvt_utf8<value_type> __cvt;
+      _String __u8str{_CharAlloc{__a}};
+      if (__str_codecvt_out(__first, __last, __u8str, __cvt))
+       {
+         if constexpr (is_same_v<_CharT, char>)
+           return __u8str;
+         else
+           {
+             _WString __wstr;
+             // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
+             codecvt_utf8<_CharT> __cvt;
+             const char* __f = __u8str.data();
+             const char* __l = __f + __u8str.size();
+             if (__str_codecvt_in(__f, __l, __wstr, __cvt))
+               return __wstr;
+           }
+       }
+#else
+      codecvt_utf8<_CharT> __cvt;
+      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+       return __wstr;
+#endif
+      _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+           "Cannot convert character sequence",
+           std::make_error_code(errc::illegal_byte_sequence)));
+    }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline basic_string<_CharT, _Traits, _Allocator>
+    path::string(const _Allocator& __a) const
+    {
+      if constexpr (is_same_v<_CharT, value_type>)
+#if _GLIBCXX_USE_CXX11_ABI
+       return { _M_pathname, __a };
+#else
+       return { _M_pathname, string_type::size_type(0), __a };
+#endif
+      else
+       return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
+    }
+
+  inline std::string
+  path::string() const { return string<char>(); }
+
+#if _GLIBCXX_USE_WCHAR_T
+  inline std::wstring
+  path::wstring() const { return string<wchar_t>(); }
+#endif
+
+  inline std::string
+  path::u8string() const
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    std::string __str;
+    // convert from native encoding to UTF-8
+    codecvt_utf8<value_type> __cvt;
+    const value_type* __first = _M_pathname.data();
+    const value_type* __last = __first + _M_pathname.size();
+    if (__str_codecvt_out(__first, __last, __str, __cvt))
+      return __str;
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+         "Cannot convert character sequence",
+         std::make_error_code(errc::illegal_byte_sequence)));
+#else
+    return _M_pathname;
+#endif
+  }
+
+  inline std::u16string
+  path::u16string() const { return string<char16_t>(); }
+
+  inline std::u32string
+  path::u32string() const { return string<char32_t>(); }
+
+  template<typename _CharT, typename _Traits, typename _Allocator>
+    inline std::basic_string<_CharT, _Traits, _Allocator>
+    path::generic_string(const _Allocator& __a) const
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      const value_type __slash = L'/';
+#else
+      const value_type __slash = '/';
+#endif
+      string_type __str(__a);
+
+      if (_M_type == _Type::_Root_dir)
+       __str.assign(1, __slash);
+      else
+       {
+         __str.reserve(_M_pathname.size());
+         bool __add_slash = false;
+         for (auto& __elem : *this)
+           {
+             if (__add_slash)
+               __str += __slash;
+             __str += __elem._M_pathname;
+             __add_slash = __elem._M_type == _Type::_Filename;
+           }
+       }
+
+      if constexpr (is_same_v<_CharT, value_type>)
+       return __str;
+      else
+       return _S_str_convert<_CharT, _Traits>(__str, __a);
+    }
+
+  inline std::string
+  path::generic_string() const
+  { return generic_string<char>(); }
+
+#if _GLIBCXX_USE_WCHAR_T
+  inline std::wstring
+  path::generic_wstring() const
+  { return generic_string<wchar_t>(); }
+#endif
+
+  inline std::string
+  path::generic_u8string() const
+  { return generic_string(); }
+
+  inline std::u16string
+  path::generic_u16string() const
+  { return generic_string<char16_t>(); }
+
+  inline std::u32string
+  path::generic_u32string() const
+  { return generic_string<char32_t>(); }
+
+  inline int
+  path::compare(const string_type& __s) const { return compare(path(__s)); }
+
+  inline int
+  path::compare(const value_type* __s) const { return compare(path(__s)); }
+
+  inline int
+  path::compare(basic_string_view<value_type> __s) const
+  { return compare(path(__s)); }
+
+  inline path
+  path::filename() const
+  {
+    if (empty())
+      return {};
+    else if (_M_type == _Type::_Filename)
+      return *this;
+    else if (_M_type == _Type::_Multi)
+      {
+       if (_M_pathname.back() == preferred_separator)
+         return {};
+       auto& __last = *--end();
+       if (__last._M_type == _Type::_Filename)
+         return __last;
+      }
+    return {};
+  }
+
+  inline path
+  path::stem() const
+  {
+    auto ext = _M_find_extension();
+    if (ext.first && ext.second != 0)
+      return path{ext.first->substr(0, ext.second)};
+    return {};
+  }
+
+  inline path
+  path::extension() const
+  {
+    auto ext = _M_find_extension();
+    if (ext.first && ext.second != string_type::npos)
+      return path{ext.first->substr(ext.second)};
+    return {};
+  }
+
+  inline bool
+  path::has_stem() const
+  {
+    auto ext = _M_find_extension();
+    return ext.first && ext.second != 0;
+  }
+
+  inline bool
+  path::has_extension() const
+  {
+    auto ext = _M_find_extension();
+    return ext.first && ext.second != string_type::npos;
+  }
+
+  inline bool
+  path::is_absolute() const
+  {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+    return has_root_name();
+#else
+    return has_root_directory();
+#endif
+  }
+
+  inline path::iterator
+  path::begin() const
+  {
+    if (_M_type == _Type::_Multi)
+      return iterator(this, _M_cmpts.begin());
+    return iterator(this, false);
+  }
+
+  inline path::iterator
+  path::end() const
+  {
+    if (_M_type == _Type::_Multi)
+      return iterator(this, _M_cmpts.end());
+    return iterator(this, true);
+  }
+
+  inline path::iterator&
+  path::iterator::operator++()
+  {
+    __glibcxx_assert(_M_path != nullptr);
+    if (_M_path->_M_type == _Type::_Multi)
+      {
+       __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
+       ++_M_cur;
+      }
+    else
+      {
+       __glibcxx_assert(!_M_at_end);
+       _M_at_end = true;
+      }
+    return *this;
+  }
+
+  inline path::iterator&
+  path::iterator::operator--()
+  {
+    __glibcxx_assert(_M_path != nullptr);
+    if (_M_path->_M_type == _Type::_Multi)
+      {
+       __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
+       --_M_cur;
+      }
+    else
+      {
+       __glibcxx_assert(_M_at_end);
+       _M_at_end = false;
+      }
+    return *this;
+  }
+
+  inline path::iterator::reference
+  path::iterator::operator*() const
+  {
+    __glibcxx_assert(_M_path != nullptr);
+    if (_M_path->_M_type == _Type::_Multi)
+      {
+       __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
+       return *_M_cur;
+      }
+    return *_M_path;
+  }
+
+  inline bool
+  path::iterator::_M_equals(iterator __rhs) const
+  {
+    if (_M_path != __rhs._M_path)
+      return false;
+    if (_M_path == nullptr)
+      return true;
+    if (_M_path->_M_type == path::_Type::_Multi)
+      return _M_cur == __rhs._M_cur;
+    return _M_at_end == __rhs._M_at_end;
+  }
+
+  // @} group filesystem
+_GLIBCXX_END_NAMESPACE_CXX11
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_PATH_H
index 1ff0d9b..ecadf37 100644 (file)
@@ -49,7 +49,7 @@ namespace filesystem
 inline namespace v1
 {
   /**
-   * @ingroup filesystem
+   * @ingroup filesystem-ts
    * @{
    */
 
@@ -351,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
 _GLIBCXX_END_NAMESPACE_CXX11
 
-  // @} group filesystem
+  // @} group filesystem-ts
 } // namespace v1
 } // namespace filesystem
 } // namespace experimental
index 7b851a3..ac43c5f 100644 (file)
@@ -53,7 +53,7 @@ inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
 #endif
 
   /**
-   * @defgroup filesystem Filesystem
+   * @defgroup filesystem-ts Filesystem TS
    * @ingroup experimental
    *
    * Utilities for performing operations on file systems and their components,
@@ -278,7 +278,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
   bool is_regular_file(file_status) noexcept;
   bool is_symlink(file_status) noexcept;
 
-  // @} group filesystem
+  // @} group filesystem-ts
 } // namespace v1
 } // namespace filesystem
 } // namespace experimental
index 3875372..fa7f1de 100644 (file)
@@ -47,7 +47,7 @@ namespace filesystem
 inline namespace v1
 {
   /**
-   * @ingroup filesystem
+   * @ingroup filesystem-ts
    * @{
    */
 
@@ -285,7 +285,7 @@ inline namespace v1
   path temp_directory_path();
   path temp_directory_path(error_code& __ec);
 
-  // @} group filesystem
+  // @} group filesystem-ts
 } // namespace v1
 } // namespace filesystem
 } // namespace experimental
index 9121439..3e9bc63 100644 (file)
@@ -72,7 +72,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #endif
 
   /**
-   * @ingroup filesystem
+   * @ingroup filesystem-ts
    * @{
    */
 
@@ -1079,7 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_at_end == __rhs._M_at_end;
   }
 
-  // @} group filesystem
+  // @} group filesystem-ts
 _GLIBCXX_END_NAMESPACE_CXX11
 } // namespace v1
 } // namespace filesystem
index f0b19dd..90f6f9e 100644 (file)
 
 #define __cpp_lib_experimental_filesystem 201406
 
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-namespace experimental
-{
-namespace filesystem
-{
-inline namespace v1
-{
-  /**
-   * @ingroup filesystem
-   */
-    inline std::string filesystem_error::_M_gen_what()
-    {
-      std::string __what = "filesystem error: ";
-      __what += system_error::what();
-      if (!_M_path1.empty())
-         __what += " [" + _M_path1.string() + ']';
-      if (!_M_path2.empty())
-         __what += " [" + _M_path2.string() + ']';
-      return __what;
-    }
-} // namespace v1
-} // namespace filesystem
-} // namespace experimental
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
 #endif // C++11
 
 #endif // _GLIBCXX_EXPERIMENTAL_FILESYSTEM
index b2993cd..4e1a71a 100644 (file)
 #include <shared_mutex>
 #endif
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
 #include <charconv>
+#include <filesystem>
 #endif
diff --git a/libstdc++-v3/include/std/filesystem b/libstdc++-v3/include/std/filesystem
new file mode 100644 (file)
index 0000000..b099977
--- /dev/null
@@ -0,0 +1,45 @@
+// <filesystem> -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file filesystem
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_FILESYSTEM
+#define _GLIBCXX_FILESYSTEM 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201703L
+
+#include <bits/fs_fwd.h>
+#include <bits/fs_path.h>
+#include <bits/fs_dir.h>
+#include <bits/fs_ops.h>
+
+#define __cpp_lib_filesystem 201703
+
+#endif // C++17
+
+#endif // _GLIBCXX_FILESYSTEM
index 04f413a..9d21196 100644 (file)
@@ -1592,6 +1592,10 @@ def build_libstdcxx_dictionary ():
                                   'path', StdExpPathPrinter)
     libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
                                   'path', StdExpPathPrinter)
+    libstdcxx_printer.add_version('std::filesystem::',
+                                  'path', StdExpPathPrinter)
+    libstdcxx_printer.add_version('std::filesystem::__cxx11::',
+                                  'path', StdExpPathPrinter)
 
     # C++17 components
     libstdcxx_printer.add_version('std::',
index 836bdd3..19de2a3 100644 (file)
@@ -30,7 +30,10 @@ if ENABLE_DUAL_ABI
 cxx11_abi_sources = \
        cow-dir.cc \
        cow-ops.cc \
-       cow-path.cc
+       cow-path.cc \
+       cow-std-dir.cc \
+       cow-std-ops.cc \
+       cow-std-path.cc
 else
 cxx11_abi_sources =
 endif
@@ -39,6 +42,9 @@ sources = \
        dir.cc \
        ops.cc \
        path.cc \
+       std-dir.cc \
+       std-ops.cc \
+       std-path.cc \
        ${cxx11_abi_sources}
 
 # vpath % $(top_srcdir)/src/filesystem
@@ -52,7 +58,7 @@ libstdc__fs_la_SOURCES = $(sources)
 # as the occasion call for it.
 AM_CXXFLAGS = \
        $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
-       -std=gnu++14 \
+       -std=gnu++17 \
        $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS)  $(CONFIG_CXXFLAGS)
 
 AM_MAKEFLAGS = \
index a4fdf79..847b19b 100644 (file)
@@ -114,8 +114,10 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
 LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
 libstdc__fs_la_LIBADD =
 @ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-dir.lo cow-ops.lo \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.lo
-am__objects_2 = dir.lo ops.lo path.lo $(am__objects_1)
+@ENABLE_DUAL_ABI_TRUE@ cow-path.lo cow-std-dir.lo \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.lo cow-std-path.lo
+am__objects_2 = dir.lo ops.lo path.lo std-dir.lo std-ops.lo \
+       std-path.lo $(am__objects_1)
 am_libstdc__fs_la_OBJECTS = $(am__objects_2)
 libstdc__fs_la_OBJECTS = $(am_libstdc__fs_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
@@ -362,12 +364,18 @@ headers =
 @ENABLE_DUAL_ABI_TRUE@cxx11_abi_sources = \
 @ENABLE_DUAL_ABI_TRUE@ cow-dir.cc \
 @ENABLE_DUAL_ABI_TRUE@ cow-ops.cc \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.cc
+@ENABLE_DUAL_ABI_TRUE@ cow-path.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-dir.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-path.cc
 
 sources = \
        dir.cc \
        ops.cc \
        path.cc \
+       std-dir.cc \
+       std-ops.cc \
+       std-path.cc \
        ${cxx11_abi_sources}
 
 
@@ -381,7 +389,7 @@ libstdc__fs_la_SOURCES = $(sources)
 # as the occasion call for it.
 AM_CXXFLAGS = \
        $(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
-       -std=gnu++14 \
+       -std=gnu++17 \
        $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS)  $(CONFIG_CXXFLAGS)
 
 AM_MAKEFLAGS = \
index 4e47bbd..96907ab 100644 (file)
@@ -1,4 +1,4 @@
-// Class filesystem::directory_entry etc. -*- C++ -*-
+// Class experimental::filesystem::directory_entry etc. -*- C++ -*-
 
 // Copyright (C) 2015-2017 Free Software Foundation, Inc.
 //
index 9ad91f0..3b41d7c 100644 (file)
@@ -1,4 +1,4 @@
-// Filesystem operations -*- C++ -*-
+// Filesystem TS operations -*- C++ -*-
 
 // Copyright (C) 2015-2017 Free Software Foundation, Inc.
 //
index b216088..0817b0a 100644 (file)
@@ -1,4 +1,4 @@
-// Class filesystem::path -*- C++ -*-
+// Class experimental::filesystem::path -*- C++ -*-
 
 // Copyright (C) 2015-2017 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/src/filesystem/cow-std-dir.cc b/libstdc++-v3/src/filesystem/cow-std-dir.cc
new file mode 100644 (file)
index 0000000..edcf245
--- /dev/null
@@ -0,0 +1,26 @@
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2015-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-dir.cc"
diff --git a/libstdc++-v3/src/filesystem/cow-std-ops.cc b/libstdc++-v3/src/filesystem/cow-std-ops.cc
new file mode 100644 (file)
index 0000000..bea5470
--- /dev/null
@@ -0,0 +1,26 @@
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2015-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-ops.cc"
diff --git a/libstdc++-v3/src/filesystem/cow-std-path.cc b/libstdc++-v3/src/filesystem/cow-std-path.cc
new file mode 100644 (file)
index 0000000..718ff95
--- /dev/null
@@ -0,0 +1,26 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2015-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-path.cc"
diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h
new file mode 100644 (file)
index 0000000..e803632
--- /dev/null
@@ -0,0 +1,149 @@
+// Filesystem directory iterator utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_DIR_COMMON_H
+#define _GLIBCXX_DIR_COMMON_H 1
+
+#include <string.h>  // strcmp
+#ifdef _GLIBCXX_HAVE_DIRENT_H
+# ifdef _GLIBCXX_HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+# endif
+# include <dirent.h>
+#else
+# error "the <dirent.h> header is needed to build the Filesystem TS"
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef opendir
+# define opendir _wopendir
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+
+struct _Dir_base
+{
+  _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { }
+
+  // If no error occurs then dirp is non-null,
+  // otherwise null (whether error ignored or not).
+  _Dir_base(const char* p, bool skip_permission_denied,
+           error_code& ec) noexcept
+  : dirp(::opendir(p))
+  {
+    if (dirp)
+      ec.clear();
+    else
+    {
+      const int err = errno;
+      if (err == EACCES && skip_permission_denied)
+       ec.clear();
+      else
+       ec.assign(err, std::generic_category());
+    }
+  }
+
+  _Dir_base(_Dir_base&& d) : dirp(std::exchange(d.dirp, nullptr)) { }
+
+  _Dir_base& operator=(_Dir_base&&) = delete;
+
+  ~_Dir_base() { if (dirp) ::closedir(dirp); }
+
+  const struct ::dirent*
+  advance(bool skip_permission_denied, error_code& ec) noexcept
+  {
+    ec.clear();
+
+    int err = std::exchange(errno, 0);
+    const struct ::dirent* entp = readdir(dirp);
+    // std::swap cannot be used with Bionic's errno
+    err = std::exchange(errno, err);
+
+    if (entp)
+      {
+       // skip past dot and dot-dot
+       if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
+         return advance(skip_permission_denied, ec);
+       return entp;
+      }
+    else if (err)
+      {
+       if (err == EACCES && skip_permission_denied)
+         return nullptr;
+       ec.assign(err, std::generic_category());
+       return nullptr;
+      }
+    else
+      {
+       // reached the end
+       return nullptr;
+      }
+  }
+
+  DIR* dirp;
+};
+
+} // namespace filesystem
+
+// BEGIN/END macros must be defined before including this file.
+_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+inline file_type
+get_file_type(const ::dirent& d __attribute__((__unused__)))
+{
+#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
+  switch (d.d_type)
+  {
+  case DT_BLK:
+    return file_type::block;
+  case DT_CHR:
+    return file_type::character;
+  case DT_DIR:
+    return file_type::directory;
+  case DT_FIFO:
+    return file_type::fifo;
+  case DT_LNK:
+    return file_type::symlink;
+  case DT_REG:
+    return file_type::regular;
+  case DT_SOCK:
+    return file_type::socket;
+  case DT_UNKNOWN:
+    return file_type::unknown;
+  default:
+    return file_type::none;
+  }
+#else
+  return file_type::none;
+#endif
+}
+_GLIBCXX_END_NAMESPACE_FILESYSTEM
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // _GLIBCXX_DIR_COMMON_H
index 9aecd80..42f63e7 100644 (file)
 #include <stack>
 #include <string.h>
 #include <errno.h>
-#ifdef _GLIBCXX_HAVE_DIRENT_H
-# ifdef _GLIBCXX_HAVE_SYS_TYPES_H
-#  include <sys/types.h>
-# endif
-# include <dirent.h>
-#else
-# error "the <dirent.h> header is needed to build the Filesystem TS"
-#endif
-
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef opendir
-# define opendir _wopendir
-#endif
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
+  namespace experimental { namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
+#include "dir-common.h"
 
 namespace fs = std::experimental::filesystem;
 
-struct fs::_Dir
+struct fs::_Dir : std::filesystem::_Dir_base
 {
-  _Dir() : dirp(nullptr) { }
+  _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
+  : _Dir_base(p.c_str(), skip_permission_denied, ec)
+  {
+    if (!ec)
+      path = p;
+  }
 
-  _Dir(DIR* dirp, const fs::path& path) : dirp(dirp), path(path) { }
+  _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
 
-  _Dir(_Dir&& d)
-  : dirp(std::exchange(d.dirp, nullptr)), path(std::move(d.path)),
-    entry(std::move(d.entry)), type(d.type)
-  { }
+  _Dir(_Dir&&) = default;
 
-  _Dir& operator=(_Dir&&) = delete;
+  // Returns false when the end of the directory entries is reached.
+  // Reports errors by setting ec.
+  bool advance(bool skip_permission_denied, error_code& ec) noexcept
+  {
+    if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
+      {
+       entry = fs::directory_entry{path / entp->d_name};
+       type = get_file_type(*entp);
+       return true;
+      }
+    else if (!ec)
+      {
+       // reached the end
+       entry = {};
+       type = file_type::none;
+      }
+    return false;
+  }
+
+  bool advance(error_code& ec) noexcept { return advance(false, ec); }
 
-  ~_Dir() { if (dirp) ::closedir(dirp); }
+  // Returns false when the end of the directory entries is reached.
+  // Reports errors by throwing.
+  bool advance(bool skip_permission_denied = false)
+  {
+    error_code ec;
+    const bool ok = advance(skip_permission_denied, ec);
+    if (ec)
+      _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "directory iterator cannot advance", ec));
+    return ok;
+  }
 
-  bool advance(std::error_code*, directory_options = directory_options::none);
+  bool should_recurse(bool follow_symlink, error_code& ec) const
+  {
+    file_type type = this->type;
+    if (type == file_type::none || type == file_type::unknown)
+    {
+      type = entry.symlink_status(ec).type();
+      if (ec)
+       return false;
+    }
+
+    if (type == file_type::directory)
+      return true;
+    if (type == file_type::symlink)
+      return follow_symlink && is_directory(entry.status(ec));
+    return false;
+  }
 
-  DIR*                 dirp;
   fs::path             path;
   directory_entry      entry;
   file_type            type = file_type::none;
@@ -78,119 +114,28 @@ namespace
     {
       return (obj & bits) != Bitmask::none;
     }
-
-  // Returns {dirp, p} on success, {} on error (whether ignored or not).
-  inline fs::_Dir
-  open_dir(const fs::path& p, fs::directory_options options,
-          std::error_code* ec)
-  {
-    if (ec)
-      ec->clear();
-
-    if (DIR* dirp = ::opendir(p.c_str()))
-      return {dirp, p};
-
-    const int err = errno;
-    if (err == EACCES
-        && is_set(options, fs::directory_options::skip_permission_denied))
-      return {};
-
-    if (!ec)
-      _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
-            "directory iterator cannot open directory", p,
-            std::error_code(err, std::generic_category())));
-
-    ec->assign(err, std::generic_category());
-    return {};
-  }
-
-  inline fs::file_type
-  get_file_type(const ::dirent& d __attribute__((__unused__)))
-  {
-#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
-    switch (d.d_type)
-    {
-    case DT_BLK:
-      return fs::file_type::block;
-    case DT_CHR:
-      return fs::file_type::character;
-    case DT_DIR:
-      return fs::file_type::directory;
-    case DT_FIFO:
-      return fs::file_type::fifo;
-    case DT_LNK:
-      return fs::file_type::symlink;
-    case DT_REG:
-      return fs::file_type::regular;
-    case DT_SOCK:
-      return fs::file_type::socket;
-    case DT_UNKNOWN:
-      return fs::file_type::unknown;
-    default:
-      return fs::file_type::none;
-    }
-#else
-    return fs::file_type::none;
-#endif
-  }
-}
-
-
-// Returns false when the end of the directory entries is reached.
-// Reports errors by setting ec or throwing.
-bool
-fs::_Dir::advance(error_code* ec, directory_options options)
-{
-  if (ec)
-    ec->clear();
-
-  int err = std::exchange(errno, 0);
-  const auto entp = readdir(dirp);
-  // std::swap cannot be used with Bionic's errno
-  err = std::exchange(errno, err);
-
-  if (entp)
-    {
-      // skip past dot and dot-dot
-      if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
-       return advance(ec, options);
-      entry = fs::directory_entry{path / entp->d_name};
-      type = get_file_type(*entp);
-      return true;
-    }
-  else if (err)
-    {
-      if (err == EACCES
-        && is_set(options, directory_options::skip_permission_denied))
-       return false;
-
-      if (!ec)
-       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
-             "directory iterator cannot advance",
-             std::error_code(err, std::generic_category())));
-      ec->assign(err, std::generic_category());
-      return false;
-    }
-  else
-    {
-      // reached the end
-      entry = {};
-      type = fs::file_type::none;
-      return false;
-    }
 }
 
 fs::directory_iterator::
-directory_iterator(const path& p, directory_options options, error_code* ec)
+directory_iterator(const path& p, directory_options options, error_code* ecptr)
 {
-  _Dir dir = open_dir(p, options, ec);
+  const bool skip_permission_denied
+    = is_set(options, directory_options::skip_permission_denied);
+
+  error_code ec;
+  _Dir dir(p, skip_permission_denied, ec);
 
   if (dir.dirp)
     {
       auto sp = std::make_shared<fs::_Dir>(std::move(dir));
-      if (sp->advance(ec, options))
+      if (sp->advance(skip_permission_denied, ec))
        _M_dir.swap(sp);
     }
+  if (ecptr)
+    *ecptr = ec;
+  else if (ec)
+    _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
+         "directory iterator cannot open directory", p, ec));
 }
 
 const fs::directory_entry&
@@ -210,7 +155,7 @@ fs::directory_iterator::operator++()
     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
          "cannot advance non-dereferenceable directory iterator",
          std::make_error_code(errc::invalid_argument)));
-  if (!_M_dir->advance(nullptr))
+  if (!_M_dir->advance())
     _M_dir.reset();
   return *this;
 }
@@ -223,13 +168,11 @@ fs::directory_iterator::increment(error_code& ec) noexcept
       ec = std::make_error_code(errc::invalid_argument);
       return *this;
     }
-  if (!_M_dir->advance(&ec))
+  if (!_M_dir->advance(ec))
     _M_dir.reset();
   return *this;
 }
 
-using Dir_iter_pair = std::pair<fs::_Dir, fs::directory_iterator>;
-
 struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
 {
   void clear() { c.clear(); }
@@ -240,6 +183,8 @@ recursive_directory_iterator(const path& p, directory_options options,
                              error_code* ec)
 : _M_options(options), _M_pending(true)
 {
+  if (ec)
+    ec->clear();
   if (DIR* dirp = ::opendir(p.c_str()))
     {
       auto sp = std::make_shared<_Dir_stack>();
@@ -252,11 +197,7 @@ recursive_directory_iterator(const path& p, directory_options options,
       const int err = errno;
       if (err == EACCES
          && is_set(options, fs::directory_options::skip_permission_denied))
-       {
-         if (ec)
-           ec->clear();
-         return;
-       }
+       return;
 
       if (!ec)
        _GLIBCXX_THROW_OR_ABORT(filesystem_error(
@@ -300,35 +241,6 @@ fs::recursive_directory_iterator::operator++()
   return *this;
 }
 
-namespace
-{
-  bool
-  recurse(const fs::_Dir& d, fs::directory_options options, std::error_code& ec)
-  {
-    bool follow_symlink
-      = is_set(options, fs::directory_options::follow_directory_symlink);
-#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
-    if (d.type == fs::file_type::directory)
-      return true;
-    if (d.type == fs::file_type::symlink && follow_symlink)
-      return d.entry.status().type() == fs::file_type::directory;
-    if (d.type != fs::file_type::none && d.type != fs::file_type::unknown)
-      return false;
-#endif
-    const fs::path& path = d.entry.path();
-    auto type = fs::symlink_status(path, ec).type();
-    if (ec.value())
-      return false;
-    if (type == fs::file_type::symlink)
-      {
-       if (!follow_symlink)
-         return false;
-       type = fs::status(path, ec).type();
-      }
-    return type == fs::file_type::directory;
-  }
-}
-
 fs::recursive_directory_iterator&
 fs::recursive_directory_iterator::increment(error_code& ec) noexcept
 {
@@ -338,11 +250,16 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept
       return *this;
     }
 
+  const bool follow
+    = is_set(_M_options, directory_options::follow_directory_symlink);
+  const bool skip_permission_denied
+    = is_set(_M_options, directory_options::skip_permission_denied);
+
   auto& top = _M_dirs->top();
 
-  if (std::exchange(_M_pending, true) && recurse(top, _M_options, ec))
+  if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
     {
-      _Dir dir = open_dir(top.entry.path(), _M_options, &ec);
+      _Dir dir(top.entry.path(), skip_permission_denied, ec);
       if (ec)
        {
          _M_dirs.reset();
@@ -352,7 +269,7 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept
          _M_dirs->push(std::move(dir));
     }
 
-  while (!_M_dirs->top().advance(&ec, _M_options) && !ec)
+  while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
     {
       _M_dirs->pop();
       if (_M_dirs->empty())
@@ -373,6 +290,9 @@ fs::recursive_directory_iterator::pop(error_code& ec)
       return;
     }
 
+  const bool skip_permission_denied
+    = is_set(_M_options, directory_options::skip_permission_denied);
+
   do {
     _M_dirs->pop();
     if (_M_dirs->empty())
@@ -381,7 +301,7 @@ fs::recursive_directory_iterator::pop(error_code& ec)
        ec.clear();
        return;
       }
-  } while (!_M_dirs->top().advance(&ec, _M_options));
+  } while (!_M_dirs->top().advance(skip_permission_denied, ec));
 }
 
 void
diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
new file mode 100644 (file)
index 0000000..12c12b0
--- /dev/null
@@ -0,0 +1,148 @@
+// Filesystem operation utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_OPS_COMMON_H
+#define _GLIBCXX_OPS_COMMON_H 1
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+# include <unistd.h>
+# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
+#  include <sys/types.h>
+#  include <sys/stat.h>
+# endif
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+  template<typename Bitmask>
+    inline bool is_set(Bitmask obj, Bitmask bits)
+    {
+      return (obj & bits) != Bitmask::none;
+    }
+
+  inline bool
+  is_not_found_errno(int err) noexcept
+  {
+    return err == ENOENT || err == ENOTDIR;
+  }
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  typedef struct ::stat stat_type;
+
+  inline std::chrono::system_clock::time_point
+  file_time(const stat_type& st, std::error_code& ec) noexcept
+  {
+    using namespace std::chrono;
+#ifdef _GLIBCXX_USE_ST_MTIM
+    time_t s = st.st_mtim.tv_sec;
+    nanoseconds ns{st.st_mtim.tv_nsec};
+#else
+    time_t s = st.st_mtime;
+    nanoseconds ns{};
+#endif
+
+    if (s >= (nanoseconds::max().count() / 1e9))
+      {
+       ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
+       return system_clock::time_point::min();
+      }
+    ec.clear();
+    return system_clock::time_point{seconds{s} + ns};
+  }
+
+  struct copy_options_existing_file
+  {
+    bool skip, update, overwrite;
+  };
+
+  bool
+  do_copy_file(const char* from, const char* to,
+              copy_options_existing_file options,
+              stat_type* from_st, stat_type* to_st,
+              std::error_code& ec) noexcept;
+
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+} // namespace filesystem
+
+// BEGIN/END macros must be defined before including this file.
+_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  typedef struct ::stat stat_type;
+
+  inline file_type
+  make_file_type(const stat_type& st) noexcept
+  {
+#ifdef _GLIBCXX_HAVE_S_ISREG
+    if (S_ISREG(st.st_mode))
+      return file_type::regular;
+    else if (S_ISDIR(st.st_mode))
+      return file_type::directory;
+    else if (S_ISCHR(st.st_mode))
+      return file_type::character;
+    else if (S_ISBLK(st.st_mode))
+      return file_type::block;
+    else if (S_ISFIFO(st.st_mode))
+      return file_type::fifo;
+    else if (S_ISLNK(st.st_mode))
+      return file_type::symlink;
+    else if (S_ISSOCK(st.st_mode))
+      return file_type::socket;
+#endif
+    return file_type::unknown;
+  }
+
+  inline file_status
+  make_file_status(const stat_type& st) noexcept
+  {
+    return file_status{
+       make_file_type(st),
+       static_cast<perms>(st.st_mode) & perms::mask
+    };
+  }
+
+  inline std::filesystem::copy_options_existing_file
+  copy_file_options(copy_options opt)
+  {
+    using std::filesystem::is_set;
+    return {
+       is_set(opt, copy_options::skip_existing),
+       is_set(opt, copy_options::update_existing),
+       is_set(opt, copy_options::overwrite_existing)
+    };
+  }
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+_GLIBCXX_END_NAMESPACE_FILESYSTEM
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // _GLIBCXX_OPS_COMMON_H
index c711de1..61d9c89 100644 (file)
@@ -1,4 +1,4 @@
-// Filesystem operations -*- C++ -*-
+// Filesystem TS operations -*- C++ -*-
 
 // Copyright (C) 2014-2017 Free Software Foundation, Inc.
 //
 #include <stdio.h>
 #include <errno.h>
 #include <limits.h>  // PATH_MAX
-#ifdef _GLIBCXX_HAVE_UNISTD_H
-# include <unistd.h>
-# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
-#  include <sys/types.h>
-#  include <sys/stat.h>
-# endif
-#endif
 #ifdef _GLIBCXX_HAVE_FCNTL_H
-# include <fcntl.h>
+# include <fcntl.h>  // AT_FDCWD, AT_SYMLINK_NOFOLLOW
 #endif
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
-# include <sys/statvfs.h>
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#  include <sys/stat.h>   // stat, utimensat, fchmodat
 #endif
-#ifdef _GLIBCXX_USE_SENDFILE
-# include <sys/sendfile.h>
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h> // statvfs
 #endif
-#if _GLIBCXX_HAVE_UTIME_H
-# include <utime.h>
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
 #endif
 
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
+  namespace experimental { namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
+#include "ops-common.h"
+
 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 # undef utime
 # define utime _wutime
@@ -240,254 +238,16 @@ fs::copy(const path& from, const path& to, copy_options options)
 
 namespace
 {
-  template<typename Bitmask>
-    inline bool is_set(Bitmask obj, Bitmask bits)
-    {
-      return (obj & bits) != Bitmask::none;
-    }
-}
+  using std::filesystem::is_set;
 
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-namespace
-{
   typedef struct ::stat stat_type;
 
-  inline fs::file_type
-  make_file_type(const stat_type& st) noexcept
-  {
-    using fs::file_type;
-#ifdef _GLIBCXX_HAVE_S_ISREG
-    if (S_ISREG(st.st_mode))
-      return file_type::regular;
-    else if (S_ISDIR(st.st_mode))
-      return file_type::directory;
-    else if (S_ISCHR(st.st_mode))
-      return file_type::character;
-    else if (S_ISBLK(st.st_mode))
-      return file_type::block;
-    else if (S_ISFIFO(st.st_mode))
-      return file_type::fifo;
-    else if (S_ISLNK(st.st_mode))
-      return file_type::symlink;
-    else if (S_ISSOCK(st.st_mode))
-      return file_type::socket;
-#endif
-    return file_type::unknown;
-
-  }
-
-  inline fs::file_status
-  make_file_status(const stat_type& st) noexcept
-  {
-    return fs::file_status{
-       make_file_type(st),
-       static_cast<fs::perms>(st.st_mode) & fs::perms::mask
-    };
-  }
-
-  inline bool
-  is_not_found_errno(int err) noexcept
-  {
-    return err == ENOENT || err == ENOTDIR;
-  }
-
-  inline fs::file_time_type
-  file_time(const stat_type& st, std::error_code& ec) noexcept
-  {
-    using namespace std::chrono;
-#ifdef _GLIBCXX_USE_ST_MTIM
-    time_t s = st.st_mtim.tv_sec;
-    nanoseconds ns{st.st_mtim.tv_nsec};
-#else
-    time_t s = st.st_mtime;
-    nanoseconds ns{};
-#endif
-
-    if (s >= (nanoseconds::max().count() / 1e9))
-      {
-       ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
-       return fs::file_time_type::min();
-      }
-    ec.clear();
-    return fs::file_time_type{seconds{s} + ns};
-  }
-
-  bool
-  do_copy_file(const fs::path& from, const fs::path& to,
-              fs::copy_options option,
-              stat_type* from_st, stat_type* to_st,
-              std::error_code& ec) noexcept
-  {
-    stat_type st1, st2;
-    fs::file_status t, f;
-
-    if (to_st == nullptr)
-      {
-       if (::stat(to.c_str(), &st1))
-         {
-           int err = errno;
-           if (!is_not_found_errno(err))
-             {
-               ec.assign(err, std::generic_category());
-               return false;
-             }
-         }
-       else
-         to_st = &st1;
-      }
-    else if (to_st == from_st)
-      to_st = nullptr;
-
-    if (to_st == nullptr)
-      t = fs::file_status{fs::file_type::not_found};
-    else
-      t = make_file_status(*to_st);
-
-    if (from_st == nullptr)
-      {
-       if (::stat(from.c_str(), &st2))
-         {
-           ec.assign(errno, std::generic_category());
-           return false;
-         }
-       else
-         from_st = &st2;
-      }
-    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))
-      {
-       ec = std::make_error_code(std::errc::not_supported);
-       return false;
-      }
-
-    using opts = fs::copy_options;
-
-    if (exists(t))
-      {
-       if (!is_regular_file(t))
-         {
-           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)
-         {
-           ec = std::make_error_code(std::errc::file_exists);
-           return false;
-         }
-
-       if (is_set(option, opts::skip_existing))
-         {
-           ec.clear();
-           return false;
-         }
-       else if (is_set(option, opts::update_existing))
-         {
-           const auto from_mtime = file_time(*from_st, ec);
-           if (ec)
-             return false;
-           if ((from_mtime <= file_time(*to_st, ec)) || ec)
-             return false;
-         }
-       else if (!is_set(option, opts::overwrite_existing))
-         {
-           ec = std::make_error_code(std::errc::file_exists);
-           return false;
-         }
-       else if (!is_regular_file(t))
-         {
-           ec = std::make_error_code(std::errc::not_supported);
-           return false;
-         }
-      }
-
-    struct CloseFD {
-      ~CloseFD() { if (fd != -1) ::close(fd); }
-      bool close() { return ::close(std::exchange(fd, -1)) == 0; }
-      int fd;
-    };
-
-    CloseFD in = { ::open(from.c_str(), O_RDONLY) };
-    if (in.fd == -1)
-      {
-       ec.assign(errno, std::generic_category());
-       return false;
-      }
-    int oflag = O_WRONLY|O_CREAT;
-    if (is_set(option, opts::overwrite_existing|opts::update_existing))
-      oflag |= O_TRUNC;
-    else
-      oflag |= O_EXCL;
-    CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) };
-    if (out.fd == -1)
-      {
-       if (errno == EEXIST && is_set(option, opts::skip_existing))
-         ec.clear();
-       else
-         ec.assign(errno, std::generic_category());
-       return false;
-      }
-
-#ifdef _GLIBCXX_USE_FCHMOD
-    if (::fchmod(out.fd, from_st->st_mode))
-#elif defined _GLIBCXX_USE_FCHMODAT
-    if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
-#else
-    if (::chmod(to.c_str(), from_st->st_mode))
-#endif
-      {
-       ec.assign(errno, std::generic_category());
-       return false;
-      }
-
-#ifdef _GLIBCXX_USE_SENDFILE
-    off_t offset = 0;
-    const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
-    if (n < 0 && (errno == ENOSYS || errno == EINVAL))
-      {
-#endif
-       __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
-       __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
-       if (sbin.is_open())
-         in.fd = -1;
-       if (sbout.is_open())
-         out.fd = -1;
-       if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
-         {
-           ec = std::make_error_code(std::errc::io_error);
-           return false;
-         }
-       if (!sbout.close() || !sbin.close())
-         {
-           ec.assign(errno, std::generic_category());
-           return false;
-         }
-
-       ec.clear();
-       return true;
-
-#ifdef _GLIBCXX_USE_SENDFILE
-      }
-    if (n != from_st->st_size)
-      {
-       ec.assign(errno, std::generic_category());
-       return false;
-      }
-    if (!out.close() || !in.close())
-      {
-       ec.assign(errno, std::generic_category());
-       return false;
-      }
-
-    ec.clear();
-    return true;
-#endif
-  }
-}
-#endif
+  using std::filesystem::is_not_found_errno;
+  using std::filesystem::file_time;
+  using std::filesystem::do_copy_file;
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+} // namespace
 
 void
 fs::copy(const path& from, const path& to, copy_options options,
@@ -561,11 +321,13 @@ fs::copy(const path& from, const path& to, copy_options options,
       else if (is_set(options, copy_options::create_hard_links))
        create_hard_link(from, to, ec);
       else if (is_directory(t))
-       do_copy_file(from, to / from.filename(), options, &from_st, 0, ec);
+       do_copy_file(from.c_str(), (to / from.filename()).c_str(),
+                    copy_file_options(options), &from_st, nullptr, ec);
       else
        {
          auto ptr = exists(t) ? &to_st : &from_st;
-         do_copy_file(from, to, options, &from_st, ptr,  ec);
+         do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+                      &from_st, ptr,  ec);
        }
     }
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -602,11 +364,12 @@ fs::copy_file(const path& from, const path& to, copy_options option)
 }
 
 bool
-fs::copy_file(const path& from, const path& to, copy_options option,
+fs::copy_file(const path& from, const path& to, copy_options options,
              error_code& ec) noexcept
 {
 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
-  return do_copy_file(from, to, option, nullptr, nullptr, ec);
+  return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+                     nullptr, nullptr, ec);
 #else
   ec = std::make_error_code(std::errc::not_supported);
   return false;
index c66d52b..a519667 100644 (file)
@@ -1,4 +1,4 @@
-// Class filesystem::path -*- C++ -*-
+// Class experimental::filesystem::path -*- C++ -*-
 
 // Copyright (C) 2014-2017 Free Software Foundation, Inc.
 //
 
 #include <experimental/filesystem>
 
-using std::experimental::filesystem::path;
+namespace fs = std::experimental::filesystem;
+using fs::path;
 
-std::experimental::filesystem::filesystem_error::~filesystem_error() = default;
+fs::filesystem_error::~filesystem_error() = default;
 
 constexpr path::value_type path::preferred_separator;
 
@@ -461,7 +462,7 @@ path::_S_convert_loc(const char* __first, const char* __last,
 }
 
 std::size_t
-std::experimental::filesystem::hash_value(const path& p) noexcept
+fs::hash_value(const path& p) noexcept
 {
   // [path.non-member]
   // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
@@ -477,3 +478,29 @@ std::experimental::filesystem::hash_value(const path& p) noexcept
     }
   return seed;
 }
+
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+  extern string
+  fs_err_concat(const string& __what, const string& __path1,
+               const string& __path2);
+} // namespace filesystem
+
+namespace experimental::filesystem::v1 {
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+  std::string filesystem_error::_M_gen_what()
+  {
+    using std::filesystem::fs_err_concat;
+    return fs_err_concat(system_error::what(), _M_path1.native(),
+                        _M_path2.native());
+  }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+} // namespace experimental::filesystem::v1
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc
new file mode 100644 (file)
index 0000000..8e45890
--- /dev/null
@@ -0,0 +1,318 @@
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#include <experimental/filesystem>
+#include <utility>
+#include <stack>
+#include <string.h>
+#include <errno.h>
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "dir-common.h"
+
+namespace fs = std::filesystem;
+
+struct fs::_Dir : _Dir_base
+{
+  _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
+  : _Dir_base(p.c_str(), skip_permission_denied, ec)
+  {
+    if (!ec)
+      path = p;
+  }
+
+  _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+
+  _Dir(_Dir&&) = default;
+
+  // Returns false when the end of the directory entries is reached.
+  // Reports errors by setting ec.
+  bool advance(bool skip_permission_denied, error_code& ec) noexcept
+  {
+    if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
+      {
+       entry = fs::directory_entry{path / entp->d_name, get_file_type(*entp)};
+       return true;
+      }
+    else if (!ec)
+      {
+       // reached the end
+       entry = {};
+      }
+    return false;
+  }
+
+  bool advance(error_code& ec) noexcept { return advance(false, ec); }
+
+  // Returns false when the end of the directory entries is reached.
+  // Reports errors by throwing.
+  bool advance(bool skip_permission_denied = false)
+  {
+    error_code ec;
+    const bool ok = advance(skip_permission_denied, ec);
+    if (ec)
+      _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "directory iterator cannot advance", ec));
+    return ok;
+  }
+
+  bool should_recurse(bool follow_symlink, error_code& ec) const
+  {
+    file_type type = entry._M_type;
+    if (type == file_type::none || type == file_type::unknown)
+    {
+      type = entry.symlink_status(ec).type();
+      if (ec)
+       return false;
+    }
+
+    if (type == file_type::directory)
+      return true;
+    if (type == file_type::symlink)
+      return follow_symlink && is_directory(entry.status(ec));
+    return false;
+  }
+
+  fs::path             path;
+  directory_entry      entry;
+};
+
+namespace
+{
+  template<typename Bitmask>
+    inline bool
+    is_set(Bitmask obj, Bitmask bits)
+    {
+      return (obj & bits) != Bitmask::none;
+    }
+}
+
+fs::directory_iterator::
+directory_iterator(const path& p, directory_options options, error_code* ecptr)
+{
+  const bool skip_permission_denied
+    = is_set(options, directory_options::skip_permission_denied);
+
+  error_code ec;
+  _Dir dir(p, skip_permission_denied, ec);
+
+  if (dir.dirp)
+    {
+      auto sp = std::make_shared<fs::_Dir>(std::move(dir));
+      if (sp->advance(skip_permission_denied, ec))
+       _M_dir.swap(sp);
+    }
+  if (ecptr)
+    *ecptr = ec;
+  else if (ec)
+    _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
+         "directory iterator cannot open directory", p, ec));
+}
+
+const fs::directory_entry&
+fs::directory_iterator::operator*() const
+{
+  if (!_M_dir)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+         "non-dereferenceable directory iterator",
+         std::make_error_code(errc::invalid_argument)));
+  return _M_dir->entry;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::operator++()
+{
+  if (!_M_dir)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+         "cannot advance non-dereferenceable directory iterator",
+         std::make_error_code(errc::invalid_argument)));
+  if (!_M_dir->advance())
+    _M_dir.reset();
+  return *this;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::increment(error_code& ec) noexcept
+{
+  if (!_M_dir)
+    {
+      ec = std::make_error_code(errc::invalid_argument);
+      return *this;
+    }
+  if (!_M_dir->advance(ec))
+    _M_dir.reset();
+  return *this;
+}
+
+struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
+{
+  void clear() { c.clear(); }
+};
+
+fs::recursive_directory_iterator::
+recursive_directory_iterator(const path& p, directory_options options,
+                             error_code* ecptr)
+: _M_options(options), _M_pending(true)
+{
+  if (DIR* dirp = ::opendir(p.c_str()))
+    {
+      if (ecptr)
+       ecptr->clear();
+      auto sp = std::make_shared<_Dir_stack>();
+      sp->push(_Dir{ dirp, p });
+      if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance())
+       _M_dirs.swap(sp);
+    }
+  else
+    {
+      const int err = errno;
+      if (err == EACCES
+         && is_set(options, fs::directory_options::skip_permission_denied))
+       {
+         if (ecptr)
+           ecptr->clear();
+         return;
+       }
+
+      if (!ecptr)
+       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+             "recursive directory iterator cannot open directory", p,
+             std::error_code(err, std::generic_category())));
+
+      ecptr->assign(err, std::generic_category());
+    }
+}
+
+fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
+
+int
+fs::recursive_directory_iterator::depth() const
+{
+  return int(_M_dirs->size()) - 1;
+}
+
+const fs::directory_entry&
+fs::recursive_directory_iterator::operator*() const
+{
+  return _M_dirs->top().entry;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(const recursive_directory_iterator& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(recursive_directory_iterator&& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::operator++()
+{
+  error_code ec;
+  increment(ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+         "cannot increment recursive directory iterator", ec));
+  return *this;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::increment(error_code& ec) noexcept
+{
+  if (!_M_dirs)
+    {
+      ec = std::make_error_code(errc::invalid_argument);
+      return *this;
+    }
+
+  const bool follow
+    = is_set(_M_options, directory_options::follow_directory_symlink);
+  const bool skip_permission_denied
+    = is_set(_M_options, directory_options::skip_permission_denied);
+
+  auto& top = _M_dirs->top();
+
+  if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
+    {
+      _Dir dir(top.entry.path(), skip_permission_denied, ec);
+      if (ec)
+       {
+         _M_dirs.reset();
+         return *this;
+       }
+      if (dir.dirp)
+         _M_dirs->push(std::move(dir));
+    }
+
+  while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
+    {
+      _M_dirs->pop();
+      if (_M_dirs->empty())
+       {
+         _M_dirs.reset();
+         return *this;
+       }
+    }
+  return *this;
+}
+
+void
+fs::recursive_directory_iterator::pop(error_code& ec)
+{
+  if (!_M_dirs)
+    {
+      ec = std::make_error_code(errc::invalid_argument);
+      return;
+    }
+
+  const bool skip_permission_denied
+    = is_set(_M_options, directory_options::skip_permission_denied);
+
+  do {
+    _M_dirs->pop();
+    if (_M_dirs->empty())
+      {
+       _M_dirs.reset();
+       ec.clear();
+       return;
+      }
+  } while (!_M_dirs->top().advance(skip_permission_denied, ec));
+}
+
+void
+fs::recursive_directory_iterator::pop()
+{
+  error_code ec;
+  pop(ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
+         ? "recursive directory iterator cannot pop"
+         : "non-dereferenceable recursive directory iterator cannot pop",
+         ec));
+}
diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc
new file mode 100644 (file)
index 0000000..ff7acbf
--- /dev/null
@@ -0,0 +1,1513 @@
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#include <experimental/filesystem>
+#include <functional>
+#include <ostream>
+#include <stack>
+#include <ext/stdio_filebuf.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>  // PATH_MAX
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h>  // AT_FDCWD, AT_SYMLINK_NOFOLLOW
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#  include <sys/stat.h>   // stat, utimensat, fchmodat
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h> // statvfs
+#endif
+#ifdef _GLIBCXX_USE_SENDFILE
+# include <sys/sendfile.h> // sendfile
+#endif
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
+#endif
+
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "ops-common.h"
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef utime
+# define utime _wutime
+# undef chmod
+# define chmod _wchmod
+#endif
+
+namespace fs = std::filesystem;
+
+fs::path
+fs::absolute(const path& p)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  error_code ec;
+  path ret = absolute(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
+       std::make_error_code(errc::not_supported)));
+  return ret;
+#else
+  return current_path() / p;
+#endif
+}
+
+fs::path
+fs::absolute(const path& p, error_code& ec)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  ec = std::make_error_code(errc::not_supported);
+  return {};
+#else
+  ec.clear();
+  return current_path() / p;
+#endif
+}
+
+namespace
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  inline bool is_dot(wchar_t c) { return c == L'.'; }
+#else
+  inline bool is_dot(char c) { return c == '.'; }
+#endif
+
+  inline bool is_dot(const fs::path& path)
+  {
+    const auto& filename = path.native();
+    return filename.size() == 1 && is_dot(filename[0]);
+  }
+
+  inline bool is_dotdot(const fs::path& path)
+  {
+    const auto& filename = path.native();
+    return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
+  }
+
+  struct free_as_in_malloc
+  {
+    void operator()(void* p) const { ::free(p); }
+  };
+
+  using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
+}
+
+fs::path
+fs::canonical(const path& p, error_code& ec)
+{
+  path result;
+  const path pa = absolute(p, ec);
+  if (ec)
+    return result;
+
+#ifdef _GLIBCXX_USE_REALPATH
+  char_ptr buf{ nullptr };
+# if _XOPEN_VERSION < 700
+  // Not safe to call realpath(path, NULL)
+  buf.reset( (char*)::malloc(PATH_MAX) );
+# endif
+  if (char* rp = ::realpath(pa.c_str(), buf.get()))
+    {
+      if (buf == nullptr)
+       buf.reset(rp);
+      result.assign(rp);
+      ec.clear();
+      return result;
+    }
+  if (errno != ENAMETOOLONG)
+    {
+      ec.assign(errno, std::generic_category());
+      return result;
+    }
+#endif
+
+  if (!exists(pa, ec))
+    {
+      if (!ec)
+       ec = make_error_code(std::errc::no_such_file_or_directory);
+      return result;
+    }
+  // else: we know there are (currently) no unresolvable symlink loops
+
+  result = pa.root_path();
+
+  deque<path> cmpts;
+  for (auto& f : pa.relative_path())
+    cmpts.push_back(f);
+
+  int max_allowed_symlinks = 40;
+
+  while (!cmpts.empty() && !ec)
+    {
+      path f = std::move(cmpts.front());
+      cmpts.pop_front();
+
+      if (f.empty())
+       {
+         // ignore empty element
+       }
+      else if (is_dot(f))
+       {
+         if (!is_directory(result, ec) && !ec)
+           ec.assign(ENOTDIR, std::generic_category());
+       }
+      else if (is_dotdot(f))
+       {
+         auto parent = result.parent_path();
+         if (parent.empty())
+           result = pa.root_path();
+         else
+           result.swap(parent);
+       }
+      else
+       {
+         result /= f;
+
+         if (is_symlink(result, ec))
+           {
+             path link = read_symlink(result, ec);
+             if (!ec)
+               {
+                 if (--max_allowed_symlinks == 0)
+                   ec.assign(ELOOP, std::generic_category());
+                 else
+                   {
+                     if (link.is_absolute())
+                       {
+                         result = link.root_path();
+                         link = link.relative_path();
+                       }
+                     else
+                       result = result.parent_path();
+
+                     cmpts.insert(cmpts.begin(), link.begin(), link.end());
+                   }
+               }
+           }
+       }
+    }
+
+  if (ec || !exists(result, ec))
+    result.clear();
+
+  return result;
+}
+
+fs::path
+fs::canonical(const path& p)
+{
+  error_code ec;
+  path res = canonical(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
+                                            p, ec));
+  return res;
+}
+
+void
+fs::copy(const path& from, const path& to, copy_options options)
+{
+  error_code ec;
+  copy(from, to, options, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
+}
+
+namespace std::filesystem
+{
+  // Need this as there's no 'perm_options::none' enumerator.
+  inline bool is_set(fs::perm_options obj, fs::perm_options bits)
+  {
+    return (obj & bits) != fs::perm_options{};
+  }
+}
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+bool
+fs::do_copy_file(const char* from, const char* to,
+                copy_options_existing_file options,
+                stat_type* from_st, stat_type* to_st,
+                std::error_code& ec) noexcept
+{
+  stat_type st1, st2;
+  fs::file_status t, f;
+
+  if (to_st == nullptr)
+    {
+      if (::stat(to, &st1))
+       {
+         const int err = errno;
+         if (!is_not_found_errno(err))
+           {
+             ec.assign(err, std::generic_category());
+             return false;
+           }
+       }
+      else
+       to_st = &st1;
+    }
+  else if (to_st == from_st)
+    to_st = nullptr;
+
+  if (to_st == nullptr)
+    t = fs::file_status{fs::file_type::not_found};
+  else
+    t = make_file_status(*to_st);
+
+  if (from_st == nullptr)
+    {
+      if (::stat(from, &st2))
+       {
+         ec.assign(errno, std::generic_category());
+         return false;
+       }
+      else
+       from_st = &st2;
+    }
+  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))
+    {
+      ec = std::make_error_code(std::errc::not_supported);
+      return false;
+    }
+
+  if (exists(t))
+    {
+      if (!is_regular_file(t))
+       {
+         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)
+       {
+         ec = std::make_error_code(std::errc::file_exists);
+         return false;
+       }
+
+      if (options.skip)
+       {
+         ec.clear();
+         return false;
+       }
+      else if (options.update)
+       {
+         const auto from_mtime = file_time(*from_st, ec);
+         if (ec)
+           return false;
+         if ((from_mtime <= file_time(*to_st, ec)) || ec)
+           return false;
+       }
+      else if (!options.overwrite)
+       {
+         ec = std::make_error_code(std::errc::file_exists);
+         return false;
+       }
+      else if (!is_regular_file(t))
+       {
+         ec = std::make_error_code(std::errc::not_supported);
+         return false;
+       }
+    }
+
+  struct CloseFD {
+    ~CloseFD() { if (fd != -1) ::close(fd); }
+    bool close() { return ::close(std::exchange(fd, -1)) == 0; }
+    int fd;
+  };
+
+  CloseFD in = { ::open(from, O_RDONLY) };
+  if (in.fd == -1)
+    {
+      ec.assign(errno, std::generic_category());
+      return false;
+    }
+  int oflag = O_WRONLY|O_CREAT;
+  if (options.overwrite || options.update)
+    oflag |= O_TRUNC;
+  else
+    oflag |= O_EXCL;
+  CloseFD out = { ::open(to, oflag, S_IWUSR) };
+  if (out.fd == -1)
+    {
+      if (errno == EEXIST && options.skip)
+       ec.clear();
+      else
+       ec.assign(errno, std::generic_category());
+      return false;
+    }
+
+#ifdef _GLIBCXX_USE_FCHMOD
+  if (::fchmod(out.fd, from_st->st_mode))
+#elif defined _GLIBCXX_USE_FCHMODAT
+  if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
+#else
+  if (::chmod(to, from_st->st_mode))
+#endif
+    {
+      ec.assign(errno, std::generic_category());
+      return false;
+    }
+
+#ifdef _GLIBCXX_USE_SENDFILE
+  off_t offset = 0;
+  const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
+  if (n < 0 && (errno == ENOSYS || errno == EINVAL))
+    {
+#endif // _GLIBCXX_USE_SENDFILE
+      __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
+      __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
+      if (sbin.is_open())
+       in.fd = -1;
+      if (sbout.is_open())
+       out.fd = -1;
+      if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
+       {
+         ec = std::make_error_code(std::errc::io_error);
+         return false;
+       }
+      if (!sbout.close() || !sbin.close())
+       {
+         ec.assign(errno, std::generic_category());
+         return false;
+       }
+
+      ec.clear();
+      return true;
+
+#ifdef _GLIBCXX_USE_SENDFILE
+    }
+  if (n != from_st->st_size)
+    {
+      ec.assign(errno, std::generic_category());
+      return false;
+    }
+  if (!out.close() || !in.close())
+    {
+      ec.assign(errno, std::generic_category());
+      return false;
+    }
+
+  ec.clear();
+  return true;
+#endif // _GLIBCXX_USE_SENDFILE
+}
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+void
+fs::copy(const path& from, const path& to, copy_options options,
+        error_code& ec) noexcept
+{
+  const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
+  const bool create_symlinks = is_set(options, copy_options::create_symlinks);
+  const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
+  const bool use_lstat = create_symlinks || skip_symlinks;
+
+  file_status f, t;
+  stat_type from_st, to_st;
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2681. filesystem::copy() cannot copy symlinks
+  if (use_lstat || copy_symlinks
+      ? ::lstat(from.c_str(), &from_st)
+      : ::stat(from.c_str(), &from_st))
+    {
+      ec.assign(errno, std::generic_category());
+      return;
+    }
+  if (use_lstat
+      ? ::lstat(to.c_str(), &to_st)
+      : ::stat(to.c_str(), &to_st))
+    {
+      if (!is_not_found_errno(errno))
+       {
+         ec.assign(errno, std::generic_category());
+         return;
+       }
+      t = file_status{file_type::not_found};
+    }
+  else
+    t = make_file_status(to_st);
+  f = make_file_status(from_st);
+
+  if (exists(t) && !is_other(t) && !is_other(f)
+      && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
+    {
+      ec = std::make_error_code(std::errc::file_exists);
+      return;
+    }
+  if (is_other(f) || is_other(t))
+    {
+      ec = std::make_error_code(std::errc::not_supported);
+      return;
+    }
+  if (is_directory(f) && is_regular_file(t))
+    {
+      ec = std::make_error_code(std::errc::is_a_directory);
+      return;
+    }
+
+  if (is_symlink(f))
+    {
+      if (skip_symlinks)
+       ec.clear();
+      else if (!exists(t) && copy_symlinks)
+       copy_symlink(from, to, ec);
+      else
+       // Not clear what should be done here.
+       // "Otherwise report an error as specified in Error reporting (7)."
+       ec = std::make_error_code(std::errc::invalid_argument);
+    }
+  else if (is_regular_file(f))
+    {
+      if (is_set(options, copy_options::directories_only))
+       ec.clear();
+      else if (create_symlinks)
+       create_symlink(from, to, ec);
+      else if (is_set(options, copy_options::create_hard_links))
+       create_hard_link(from, to, ec);
+      else if (is_directory(t))
+       do_copy_file(from.c_str(), (to / from.filename()).c_str(),
+                    copy_file_options(options), &from_st, nullptr, ec);
+      else
+       {
+         auto ptr = exists(t) ? &to_st : &from_st;
+         do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+                      &from_st, ptr, ec);
+       }
+    }
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2682. filesystem::copy() won't create a symlink to a directory
+  else if (is_directory(f) && create_symlinks)
+    ec = std::make_error_code(errc::is_a_directory);
+  else if (is_directory(f) && (is_set(options, copy_options::recursive)
+                              || options == copy_options::none))
+    {
+      if (!exists(t))
+       if (!create_directory(to, from, ec))
+         return;
+      // set an unused bit in options to disable further recursion
+      if (!is_set(options, copy_options::recursive))
+       options |= static_cast<copy_options>(4096);
+      for (const directory_entry& x : directory_iterator(from))
+       copy(x.path(), to/x.path().filename(), options, ec);
+    }
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2683. filesystem::copy() says "no effects"
+  else
+    ec.clear();
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options option)
+{
+  error_code ec;
+  bool result = copy_file(from, to, option, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
+                                            ec));
+  return result;
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options options,
+             error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+                     nullptr, nullptr, ec);
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+  return false;
+#endif
+}
+
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
+{
+  error_code ec;
+  copy_symlink(existing_symlink, new_symlink, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
+         existing_symlink, new_symlink, ec));
+}
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
+                error_code& ec) noexcept
+{
+  auto p = read_symlink(existing_symlink, ec);
+  if (ec)
+    return;
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  if (is_directory(p))
+    {
+      create_directory_symlink(p, new_symlink, ec);
+      return;
+    }
+#endif
+  create_symlink(p, new_symlink, ec);
+}
+
+
+bool
+fs::create_directories(const path& p)
+{
+  error_code ec;
+  bool result = create_directories(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
+                                            ec));
+  return result;
+}
+
+bool
+fs::create_directories(const path& p, error_code& ec) noexcept
+{
+  if (p.empty())
+    {
+      ec = std::make_error_code(errc::invalid_argument);
+      return false;
+    }
+  std::stack<path> missing;
+  path pp = p;
+
+  while (pp.has_filename() && status(pp, ec).type() == file_type::not_found)
+    {
+      ec.clear();
+      const auto& filename = pp.filename();
+      if (!is_dot(filename) && !is_dotdot(filename))
+       missing.push(pp);
+      pp = pp.parent_path();
+
+      if (missing.size() > 1000) // sanity check
+       {
+         ec = std::make_error_code(std::errc::filename_too_long);
+         return false;
+       }
+    }
+
+  if (ec || missing.empty())
+    return false;
+
+  do
+    {
+      const path& top = missing.top();
+      create_directory(top, ec);
+      if (ec && is_directory(top))
+       ec.clear();
+      missing.pop();
+    }
+  while (!missing.empty() && !ec);
+
+  return missing.empty();
+}
+
+namespace
+{
+  bool
+  create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
+  {
+    bool created = false;
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+    ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+    if (::mkdir(p.c_str(), mode))
+      {
+       const int err = errno;
+       if (err != EEXIST || !is_directory(p))
+         ec.assign(err, std::generic_category());
+       else
+         ec.clear();
+      }
+    else
+      {
+       ec.clear();
+       created = true;
+      }
+#else
+    ec = std::make_error_code(std::errc::not_supported);
+#endif
+    return created;
+  }
+} // namespace
+
+bool
+fs::create_directory(const path& p)
+{
+  error_code ec;
+  bool result = create_directory(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+         ec));
+  return result;
+}
+
+bool
+fs::create_directory(const path& p, error_code& ec) noexcept
+{
+  return create_dir(p, perms::all, ec);
+}
+
+
+bool
+fs::create_directory(const path& p, const path& attributes)
+{
+  error_code ec;
+  bool result = create_directory(p, attributes, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+         ec));
+  return result;
+}
+
+bool
+fs::create_directory(const path& p, const path& attributes,
+                    error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  stat_type st;
+  if (::stat(attributes.c_str(), &st))
+    {
+      ec.assign(errno, std::generic_category());
+      return false;
+    }
+  return create_dir(p, static_cast<perms>(st.st_mode), ec);
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+  return false;
+#endif
+}
+
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink)
+{
+  error_code ec;
+  create_directory_symlink(to, new_symlink, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
+         to, new_symlink, ec));
+}
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink,
+                            error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  ec = std::make_error_code(std::errc::not_supported);
+#else
+  create_symlink(to, new_symlink, ec);
+#endif
+}
+
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link)
+{
+  error_code ec;
+  create_hard_link(to, new_hard_link, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
+         to, new_hard_link, ec));
+}
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link,
+                    error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+  if (::link(to.c_str(), new_hard_link.c_str()))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink)
+{
+  error_code ec;
+  create_symlink(to, new_symlink, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
+         to, new_symlink, ec));
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink,
+                  error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+  if (::symlink(to.c_str(), new_symlink.c_str()))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::path
+fs::current_path()
+{
+  error_code ec;
+  path p = current_path(ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
+  return p;
+}
+
+fs::path
+fs::current_path(error_code& ec)
+{
+  path p;
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef __GLIBC__
+  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
+    {
+      p.assign(cwd.get());
+      ec.clear();
+    }
+  else
+    ec.assign(errno, std::generic_category());
+#else
+  long path_max = pathconf(".", _PC_PATH_MAX);
+  size_t size;
+  if (path_max == -1)
+      size = 1024;
+  else if (path_max > 10240)
+      size = 10240;
+  else
+      size = path_max;
+  for (char_ptr buf; p.empty(); size *= 2)
+    {
+      buf.reset((char*)malloc(size));
+      if (buf)
+       {
+         if (getcwd(buf.get(), size))
+           {
+             p.assign(buf.get());
+             ec.clear();
+           }
+         else if (errno != ERANGE)
+           {
+             ec.assign(errno, std::generic_category());
+             return {};
+           }
+       }
+      else
+       {
+         ec = std::make_error_code(std::errc::not_enough_memory);
+         return {};
+       }
+    }
+#endif  // __GLIBC__
+#else   // _GLIBCXX_HAVE_UNISTD_H
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+  return p;
+}
+
+void
+fs::current_path(const path& p)
+{
+  error_code ec;
+  current_path(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
+}
+
+void
+fs::current_path(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+  if (::chdir(p.c_str()))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2)
+{
+  error_code ec;
+  auto result = equivalent(p1, p2, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
+         p1, p2, ec));
+  return result;
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  int err = 0;
+  file_status s1, s2;
+  stat_type st1, st2;
+  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))
+    {
+      if (is_other(s1) && is_other(s2))
+       {
+         ec = std::make_error_code(std::errc::not_supported);
+         return false;
+       }
+      ec.clear();
+      if (is_other(s1) || is_other(s2))
+       return false;
+      return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
+    }
+  else if (!exists(s1) && !exists(s2))
+    ec = std::make_error_code(std::errc::no_such_file_or_directory);
+  else if (err)
+    ec.assign(err, std::generic_category());
+  else
+    ec.clear();
+  return false;
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+  return false;
+}
+
+std::uintmax_t
+fs::file_size(const path& p)
+{
+  error_code ec;
+  auto sz = file_size(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
+  return sz;
+}
+
+namespace
+{
+  template<typename Accessor, typename T>
+    inline T
+    do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
+    {
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+      fs::stat_type st;
+      if (::stat(p.c_str(), &st))
+       {
+         ec.assign(errno, std::generic_category());
+         return deflt;
+       }
+      ec.clear();
+      return f(st);
+#else
+      ec = std::make_error_code(std::errc::not_supported);
+      return deflt;
+#endif
+    }
+}
+
+std::uintmax_t
+fs::file_size(const path& p, error_code& ec) noexcept
+{
+  struct S
+  {
+    S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
+    S() : type(file_type::not_found) { }
+    file_type type;
+    size_t size;
+  };
+  auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
+  if (s.type == file_type::regular)
+    return s.size;
+  if (!ec)
+    {
+      if (s.type == file_type::directory)
+       ec = std::make_error_code(std::errc::is_a_directory);
+      else
+       ec = std::make_error_code(std::errc::not_supported);
+    }
+  return -1;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p)
+{
+  error_code ec;
+  auto count = hard_link_count(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
+  return count;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p, error_code& ec) noexcept
+{
+  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
+                static_cast<uintmax_t>(-1));
+}
+
+bool
+fs::is_empty(const path& p)
+{
+  error_code ec;
+  bool e = is_empty(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
+                                            p, ec));
+  return e;
+}
+
+bool
+fs::is_empty(const path& p, error_code& ec) noexcept
+{
+  auto s = status(p, ec);
+  if (ec)
+    return false;
+  bool empty = fs::is_directory(s)
+    ? fs::directory_iterator(p, ec) == fs::directory_iterator()
+    : fs::file_size(p, ec) == 0;
+  return ec ? false : empty;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p)
+{
+  error_code ec;
+  auto t = last_write_time(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
+  return t;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p, error_code& ec) noexcept
+{
+  return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
+                file_time_type::min());
+}
+
+void
+fs::last_write_time(const path& p, file_time_type new_time)
+{
+  error_code ec;
+  last_write_time(p, new_time, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
+}
+
+void
+fs::last_write_time(const path& p __attribute__((__unused__)),
+                   file_time_type new_time, error_code& ec) noexcept
+{
+  auto d = new_time.time_since_epoch();
+  auto s = chrono::duration_cast<chrono::seconds>(d);
+#if _GLIBCXX_USE_UTIMENSAT
+  auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
+  if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
+    {
+      --s;
+      ns += chrono::seconds(1);
+    }
+  struct ::timespec ts[2];
+  ts[0].tv_sec = 0;
+  ts[0].tv_nsec = UTIME_OMIT;
+  ts[1].tv_sec = static_cast<std::time_t>(s.count());
+  ts[1].tv_nsec = static_cast<long>(ns.count());
+  if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#elif _GLIBCXX_HAVE_UTIME_H
+  ::utimbuf times;
+  times.modtime = s.count();
+  times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
+                        times.modtime);
+  if (::utime(p.c_str(), &times))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts)
+{
+  error_code ec;
+  permissions(p, prms, opts, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts,
+               error_code& ec) noexcept
+{
+  const bool replace = is_set(opts, perm_options::replace);
+  const bool add = is_set(opts, perm_options::add);
+  const bool remove = is_set(opts, perm_options::remove);
+  const bool nofollow = is_set(opts, perm_options::nofollow);
+  if (((int)replace + (int)add + (int)remove) != 1)
+    {
+      ec = std::make_error_code(std::errc::invalid_argument);
+      return;
+    }
+
+  prms &= perms::mask;
+
+  file_status st;
+  if (add || remove || nofollow)
+    {
+      st = nofollow ? symlink_status(p, ec) : status(p, ec);
+      if (ec)
+       return;
+      auto curr = st.permissions();
+      if (add)
+       prms |= curr;
+      else if (remove)
+       prms = curr & ~prms;
+    }
+
+  int err = 0;
+#if _GLIBCXX_USE_FCHMODAT
+  const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
+  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
+    err = errno;
+#else
+  if (nofollow && is_symlink(st))
+    ec = std::make_error_code(std::errc::operation_not_supported);
+  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+    err = errno;
+#endif
+
+  if (err)
+    ec.assign(err, std::generic_category());
+  else
+    ec.clear();
+}
+
+fs::path
+fs::proximate(const path& p, const path& base)
+{
+  return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
+}
+
+fs::path
+fs::proximate(const path& p, const path& base, error_code& ec)
+{
+  path result;
+  const auto p2 = weakly_canonical(p, ec);
+  if (!ec)
+    {
+      const auto base2 = weakly_canonical(base, ec);
+      if (!ec)
+       result = p2.lexically_proximate(base2);
+    }
+  return result;
+}
+
+fs::path
+fs::read_symlink(const path& p)
+{
+  error_code ec;
+  path tgt = read_symlink(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
+  return tgt;
+}
+
+fs::path fs::read_symlink(const path& p, error_code& ec)
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+  stat_type st;
+  if (::lstat(p.c_str(), &st))
+    {
+      ec.assign(errno, std::generic_category());
+      return {};
+    }
+  std::string buf(st.st_size, '\0');
+  ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
+  if (len == -1)
+    {
+      ec.assign(errno, std::generic_category());
+      return {};
+    }
+  ec.clear();
+  return path{buf.data(), buf.data()+len};
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+  return {};
+#endif
+}
+
+fs::path
+fs::relative(const path& p, const path& base)
+{
+  return weakly_canonical(p).lexically_relative(weakly_canonical(base));
+}
+
+fs::path
+fs::relative(const path& p, const path& base, error_code& ec)
+{
+  auto result = weakly_canonical(p, ec);
+  fs::path cbase;
+  if (!ec)
+    cbase = weakly_canonical(base, ec);
+  if (!ec)
+    result = result.lexically_relative(cbase);
+  if (ec)
+    result.clear();
+  return result;
+}
+
+bool
+fs::remove(const path& p)
+{
+  error_code ec;
+  bool result = fs::remove(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
+  return result;
+}
+
+bool
+fs::remove(const path& p, error_code& ec) noexcept
+{
+  if (exists(symlink_status(p, ec)))
+    {
+      if (::remove(p.c_str()) == 0)
+       {
+         ec.clear();
+         return true;
+       }
+      else
+       ec.assign(errno, std::generic_category());
+    }
+  return false;
+}
+
+
+std::uintmax_t
+fs::remove_all(const path& p)
+{
+  error_code ec;
+  bool result = remove_all(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
+  return result;
+}
+
+std::uintmax_t
+fs::remove_all(const path& p, error_code& ec) noexcept
+{
+  auto fs = symlink_status(p, ec);
+  uintmax_t count = 0;
+  if (!ec && fs.type() == file_type::directory)
+    for (directory_iterator d(p, ec), end; !ec && d != end; ++d)
+      count += fs::remove_all(d->path(), ec);
+  if (ec)
+    return -1;
+  return fs::remove(p, ec) ? ++count : -1;  // fs:remove() calls ec.clear()
+}
+
+void
+fs::rename(const path& from, const path& to)
+{
+  error_code ec;
+  rename(from, to, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
+}
+
+void
+fs::rename(const path& from, const path& to, error_code& ec) noexcept
+{
+  if (::rename(from.c_str(), to.c_str()))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size)
+{
+  error_code ec;
+  resize_file(p, size, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+  if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
+    ec.assign(EINVAL, std::generic_category());
+  else if (::truncate(p.c_str(), size))
+    ec.assign(errno, std::generic_category());
+  else
+    ec.clear();
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::space_info
+fs::space(const path& p)
+{
+  error_code ec;
+  space_info s = space(p, ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
+  return s;
+}
+
+fs::space_info
+fs::space(const path& p, error_code& ec) noexcept
+{
+  space_info info = {
+    static_cast<uintmax_t>(-1),
+    static_cast<uintmax_t>(-1),
+    static_cast<uintmax_t>(-1)
+  };
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+  struct ::statvfs f;
+  if (::statvfs(p.c_str(), &f))
+      ec.assign(errno, std::generic_category());
+  else
+    {
+      info = space_info{
+       f.f_blocks * f.f_frsize,
+       f.f_bfree * f.f_frsize,
+       f.f_bavail * f.f_frsize
+      };
+      ec.clear();
+    }
+#else
+  ec = std::make_error_code(std::errc::not_supported);
+#endif
+  return info;
+}
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+fs::file_status
+fs::status(const fs::path& p, error_code& ec) noexcept
+{
+  file_status status;
+  stat_type st;
+  if (::stat(p.c_str(), &st))
+    {
+      int err = errno;
+      ec.assign(err, std::generic_category());
+      if (is_not_found_errno(err))
+       status.type(file_type::not_found);
+#ifdef EOVERFLOW
+      else if (err == EOVERFLOW)
+       status.type(file_type::unknown);
+#endif
+    }
+  else
+    {
+      status = make_file_status(st);
+      ec.clear();
+    }
+  return status;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
+{
+  file_status status;
+  stat_type st;
+  if (::lstat(p.c_str(), &st))
+    {
+      int err = errno;
+      ec.assign(err, std::generic_category());
+      if (is_not_found_errno(err))
+       status.type(file_type::not_found);
+    }
+  else
+    {
+      status = make_file_status(st);
+      ec.clear();
+    }
+  return status;
+}
+#endif
+
+fs::file_status
+fs::status(const fs::path& p)
+{
+  std::error_code ec;
+  auto result = status(p, ec);
+  if (result.type() == file_type::none)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
+  return result;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p)
+{
+  std::error_code ec;
+  auto result = symlink_status(p, ec);
+  if (result.type() == file_type::none)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
+  return result;
+}
+
+fs::path fs::temp_directory_path()
+{
+  error_code ec;
+  path tmp = temp_directory_path(ec);
+  if (ec)
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
+  return tmp;
+}
+
+fs::path fs::temp_directory_path(error_code& ec)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  ec = std::make_error_code(std::errc::not_supported);
+  return {}; // TODO
+#else
+  const char* tmpdir = nullptr;
+  const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
+  for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
+    tmpdir = ::getenv(*e);
+  path p = tmpdir ? tmpdir : "/tmp";
+  auto st = status(p, ec);
+  if (!ec)
+    {
+      if (is_directory(st))
+       {
+         ec.clear();
+         return p;
+       }
+      else
+       ec = std::make_error_code(std::errc::not_a_directory);
+    }
+  return {};
+#endif
+}
+
+fs::path
+fs::weakly_canonical(const path& p)
+{
+  path result;
+  if (exists(status(p)))
+    return canonical(p);
+
+  path tmp;
+  auto iter = p.begin(), end = p.end();
+  // find leading elements of p that exist:
+  while (iter != end)
+    {
+      tmp = result / *iter;
+      if (exists(status(tmp)))
+       swap(result, tmp);
+      else
+       break;
+      ++iter;
+    }
+  // canonicalize:
+  result = canonical(result);
+  // append the non-existing elements:
+  while (iter != end)
+    result /= *iter++;
+  // normalize:
+  return result.lexically_normal();
+}
+
+fs::path
+fs::weakly_canonical(const path& p, error_code& ec)
+{
+  path result;
+  file_status st = status(p, ec);
+  if (exists(st))
+    return canonical(p, ec);
+  else if (status_known(st))
+    ec.clear();
+  else
+    return result;
+
+  path tmp;
+  auto iter = p.begin(), end = p.end();
+  // find leading elements of p that exist:
+  while (iter != end)
+    {
+      tmp = result / *iter;
+      st = status(tmp, ec);
+      if (exists(st))
+       swap(result, tmp);
+      else
+       {
+         if (status_known(st))
+           ec.clear();
+         break;
+       }
+      ++iter;
+    }
+  // canonicalize:
+  if (!ec)
+    result = canonical(result, ec);
+  if (ec)
+    result.clear();
+  else
+    {
+      // append the non-existing elements:
+      while (iter != end)
+       result /= *iter++;
+      // normalize:
+      result = result.lexically_normal();
+    }
+  return result;
+}
diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
new file mode 100644 (file)
index 0000000..b5dd36d
--- /dev/null
@@ -0,0 +1,688 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2014-2017 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <algorithm>
+#endif
+
+namespace fs = std::filesystem;
+using fs::path;
+
+fs::filesystem_error::~filesystem_error() = default;
+
+constexpr path::value_type path::preferred_separator;
+
+path&
+path::remove_filename()
+{
+  if (_M_type == _Type::_Multi)
+    {
+      if (!_M_cmpts.empty())
+       {
+         auto cmpt = std::prev(_M_cmpts.end());
+         if (cmpt->_M_type == _Type::_Filename && !cmpt->empty())
+           {
+             _M_pathname.erase(cmpt->_M_pos);
+             auto prev = std::prev(cmpt);
+             if (prev->_M_type == _Type::_Root_dir
+                 || prev->_M_type == _Type::_Root_name)
+               {
+                 _M_cmpts.erase(cmpt);
+                 _M_trim();
+               }
+             else
+               cmpt->clear();
+           }
+       }
+    }
+  else if (_M_type == _Type::_Filename)
+    clear();
+  if (!empty() && _M_pathname.back() != '/')
+    throw 1;
+  return *this;
+}
+
+path&
+path::replace_filename(const path& replacement)
+{
+  remove_filename();
+  operator/=(replacement);
+  return *this;
+}
+
+path&
+path::replace_extension(const path& replacement)
+{
+  auto ext = _M_find_extension();
+  // Any existing extension() is removed
+  if (ext.first && ext.second != string_type::npos)
+    {
+      if (ext.first == &_M_pathname)
+       _M_pathname.erase(ext.second);
+      else
+       {
+         const auto& back = _M_cmpts.back();
+         if (ext.first != &back._M_pathname)
+           _GLIBCXX_THROW_OR_ABORT(
+               std::logic_error("path::replace_extension failed"));
+         _M_pathname.erase(back._M_pos + ext.second);
+       }
+    }
+   // If replacement is not empty and does not begin with a dot character,
+   // a dot character is appended
+  if (!replacement.empty() && replacement.native()[0] != '.')
+    _M_pathname += '.';
+  operator+=(replacement);
+  return *this;
+}
+
+namespace
+{
+  template<typename Iter1, typename Iter2>
+    int do_compare(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2)
+    {
+      int cmpt = 1;
+      while (begin1 != end1 && begin2 != end2)
+       {
+         if (begin1->native() < begin2->native())
+           return -cmpt;
+         if (begin1->native() > begin2->native())
+           return +cmpt;
+         ++begin1;
+         ++begin2;
+         ++cmpt;
+       }
+      if (begin1 == end1)
+       {
+         if (begin2 == end2)
+           return 0;
+         return -cmpt;
+       }
+      return +cmpt;
+    }
+}
+
+int
+path::compare(const path& p) const noexcept
+{
+  struct CmptRef
+  {
+    const path* ptr;
+    const string_type& native() const noexcept { return ptr->native(); }
+  };
+
+  if (empty() && p.empty())
+    return 0;
+  else if (_M_type == _Type::_Multi && p._M_type == _Type::_Multi)
+    return do_compare(_M_cmpts.begin(), _M_cmpts.end(),
+                     p._M_cmpts.begin(), p._M_cmpts.end());
+  else if (_M_type == _Type::_Multi)
+    {
+      CmptRef c[1] = { { &p } };
+      return do_compare(_M_cmpts.begin(), _M_cmpts.end(), c, c+1);
+    }
+  else if (p._M_type == _Type::_Multi)
+    {
+      CmptRef c[1] = { { this } };
+      return do_compare(c, c+1, p._M_cmpts.begin(), p._M_cmpts.end());
+    }
+  else
+    return _M_pathname.compare(p._M_pathname);
+}
+
+path
+path::root_name() const
+{
+  path __ret;
+  if (_M_type == _Type::_Root_name)
+    __ret = *this;
+  else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+    __ret = *_M_cmpts.begin();
+  return __ret;
+}
+
+path
+path::root_directory() const
+{
+  path __ret;
+  if (_M_type == _Type::_Root_dir)
+    {
+      __ret._M_type = _Type::_Root_dir;
+      __ret._M_pathname.assign(1, preferred_separator);
+    }
+  else if (!_M_cmpts.empty())
+    {
+      auto __it = _M_cmpts.begin();
+      if (__it->_M_type == _Type::_Root_name)
+        ++__it;
+      if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+        __ret = *__it;
+    }
+  return __ret;
+}
+
+path
+path::root_path() const
+{
+  path __ret;
+  if (_M_type == _Type::_Root_name)
+    __ret = *this;
+  else if (_M_type == _Type::_Root_dir)
+    {
+      __ret._M_pathname.assign(1, preferred_separator);
+      __ret._M_type = _Type::_Root_dir;
+    }
+  else if (!_M_cmpts.empty())
+    {
+      auto __it = _M_cmpts.begin();
+      if (__it->_M_type == _Type::_Root_name)
+        {
+          __ret = *__it++;
+          if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+           __ret /= *__it;
+        }
+      else if (__it->_M_type == _Type::_Root_dir)
+        __ret = *__it;
+    }
+  return __ret;
+}
+
+path
+path::relative_path() const
+{
+  path __ret;
+  if (_M_type == _Type::_Filename)
+    __ret = *this;
+  else if (!_M_cmpts.empty())
+    {
+      auto __it = _M_cmpts.begin();
+      if (__it->_M_type == _Type::_Root_name)
+        ++__it;
+      if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+        ++__it;
+      if (__it != _M_cmpts.end())
+        __ret.assign(_M_pathname.substr(__it->_M_pos));
+    }
+  return __ret;
+}
+
+path
+path::parent_path() const
+{
+  path __ret;
+  if (!has_relative_path())
+    __ret = *this;
+  else if (_M_cmpts.size() >= 2)
+    {
+      for (auto __it = _M_cmpts.begin(), __end = std::prev(_M_cmpts.end());
+          __it != __end; ++__it)
+       {
+         __ret /= *__it;
+       }
+    }
+  return __ret;
+}
+
+bool
+path::has_root_name() const
+{
+  if (_M_type == _Type::_Root_name)
+    return true;
+  if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+    return true;
+  return false;
+}
+
+bool
+path::has_root_directory() const
+{
+  if (_M_type == _Type::_Root_dir)
+    return true;
+  if (!_M_cmpts.empty())
+    {
+      auto __it = _M_cmpts.begin();
+      if (__it->_M_type == _Type::_Root_name)
+        ++__it;
+      if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+        return true;
+    }
+  return false;
+}
+
+bool
+path::has_root_path() const
+{
+  if (_M_type == _Type::_Root_name || _M_type == _Type::_Root_dir)
+    return true;
+  if (!_M_cmpts.empty())
+    {
+      auto __type = _M_cmpts.front()._M_type;
+      if (__type == _Type::_Root_name || __type == _Type::_Root_dir)
+        return true;
+    }
+  return false;
+}
+
+bool
+path::has_relative_path() const
+{
+  if (_M_type == _Type::_Filename)
+    return true;
+  if (!_M_cmpts.empty())
+    {
+      auto __it = _M_cmpts.begin();
+      if (__it->_M_type == _Type::_Root_name)
+        ++__it;
+      if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+        ++__it;
+      if (__it != _M_cmpts.end())
+        return true;
+    }
+  return false;
+}
+
+
+bool
+path::has_parent_path() const
+{
+  if (!has_relative_path())
+    return !empty();
+  return _M_cmpts.size() >= 2;
+}
+
+bool
+path::has_filename() const
+{
+  if (empty())
+    return false;
+  if (_M_type == _Type::_Filename)
+    return !_M_pathname.empty();
+  if (_M_type == _Type::_Multi)
+    {
+      if (_M_pathname.back() == preferred_separator)
+       return false;
+      return _M_cmpts.back().has_filename();
+    }
+  return false;
+}
+
+namespace
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  inline bool is_dot(wchar_t c) { return c == L'.'; }
+#else
+  inline bool is_dot(char c) { return c == '.'; }
+#endif
+
+  inline bool is_dot(const fs::path& path)
+  {
+    const auto& filename = path.native();
+    return filename.size() == 1 && is_dot(filename[0]);
+  }
+
+  inline bool is_dotdot(const fs::path& path)
+  {
+    const auto& filename = path.native();
+    return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
+  }
+} // namespace
+
+path
+path::lexically_normal() const
+{
+  /*
+  C++17 [fs.path.generic] p6
+  - If the path is empty, stop.
+  - Replace each slash character in the root-name with a preferred-separator.
+  - Replace each directory-separator with a preferred-separator.
+  - Remove each dot filename and any immediately following directory-separator.
+  - As long as any appear, remove a non-dot-dot filename immediately followed
+    by a directory-separator and a dot-dot filename, along with any immediately
+    following directory-separator.
+  - If the last filename is dot-dot, remove any trailing directory-separator.
+  - If the path is empty, add a dot.
+  */
+  path ret;
+  // If the path is empty, stop.
+  if (empty())
+    return ret;
+  for (auto& p : *this)
+    {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+      // Replace each slash character in the root-name
+      if (p.is_root_name())
+       {
+         string_type s = p.native();
+         std::replace(s.begin(), s.end(), L'/', L'\\');
+         ret /= s;
+         continue;
+       }
+#endif
+      if (is_dotdot(p))
+       {
+         if (ret.has_filename() && !is_dotdot(ret.filename()))
+           ret.remove_filename();
+         else
+           ret /= p;
+       }
+      else if (is_dot(p))
+       ret /= path();
+      else
+       ret /= p;
+    }
+
+  if (ret._M_cmpts.size() >= 2)
+    {
+      auto back = std::prev(ret.end());
+      // If the last filename is dot-dot, ...
+      if (back->empty() && is_dotdot(*std::prev(back)))
+       // ... remove any trailing directory-separator.
+       ret = ret.parent_path();
+    }
+  // If the path is empty, add a dot.
+  else if (ret.empty())
+    ret = ".";
+
+  return ret;
+}
+
+path
+path::lexically_relative(const path& base) const
+{
+  path ret;
+  if (root_name() != base.root_name())
+    return ret;
+  if (is_absolute() != base.is_absolute())
+    return ret;
+  if (!has_root_directory() && base.has_root_directory())
+    return ret;
+  auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
+  if (a == end() && b == base.end())
+    ret = ".";
+  else
+  {
+    int n = 0;
+    for (; b != base.end(); ++b)
+    {
+      const path& p = *b;
+      if (is_dotdot(p))
+       --n;
+      else if (!is_dot(p))
+       ++n;
+    }
+    if (n >= 0)
+    {
+      const path dotdot("..");
+      while (n--)
+       ret /= dotdot;
+      for (; a != end(); ++a)
+       ret /= *a;
+    }
+  }
+  return ret;
+}
+
+path
+path::lexically_proximate(const path& base) const
+{
+  path rel = lexically_relative(base);
+  if (rel.empty())
+    rel = *this;
+  return rel;
+}
+
+std::pair<const path::string_type*, std::size_t>
+path::_M_find_extension() const
+{
+  const std::string* s = nullptr;
+
+  if (_M_type == _Type::_Filename)
+    s = &_M_pathname;
+  else if (_M_type == _Type::_Multi && !_M_cmpts.empty())
+    {
+      const auto& c = _M_cmpts.back();
+      if (c._M_type == _Type::_Filename)
+       s = &c._M_pathname;
+    }
+
+  if (s)
+    {
+      if (auto sz = s->size())
+       {
+         if (sz <= 2 && (*s)[0] == '.')
+           return { s, string_type::npos };
+         const auto pos = s->rfind('.');
+         return { s, pos ? pos : string_type::npos };
+       }
+    }
+  return {};
+}
+
+void
+path::_M_split_cmpts()
+{
+  _M_type = _Type::_Multi;
+  _M_cmpts.clear();
+
+  if (_M_pathname.empty())
+    return;
+
+  size_t pos = 0;
+  const size_t len = _M_pathname.size();
+
+  // look for root name or root directory
+  if (_S_is_dir_sep(_M_pathname[0]))
+    {
+#ifdef __CYGWIN__
+      // look for root name, such as "//foo"
+      if (len > 2 && _M_pathname[1] == _M_pathname[0])
+       {
+         if (!_S_is_dir_sep(_M_pathname[2]))
+           {
+             // got root name, find its end
+             pos = 3;
+             while (pos < len && !_S_is_dir_sep(_M_pathname[pos]))
+               ++pos;
+             _M_add_root_name(pos);
+             if (pos < len) // also got root directory
+               _M_add_root_dir(pos);
+           }
+         else
+           {
+             // got something like "///foo" which is just a root directory
+             // composed of multiple redundant directory separators
+             _M_add_root_dir(0);
+           }
+       }
+      else
+#endif
+        {
+         // got root directory
+         if (_M_pathname.find_first_not_of('/') == string_type::npos)
+           {
+             // entire path is just slashes
+             _M_type = _Type::_Root_dir;
+             return;
+           }
+         _M_add_root_dir(0);
+         ++pos;
+       }
+    }
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  else if (len > 1 && _M_pathname[1] == L':')
+    {
+      // got disk designator
+      _M_add_root_name(2);
+      if (len > 2 && _S_is_dir_sep(_M_pathname[2]))
+       _M_add_root_dir(2);
+      pos = 2;
+    }
+#endif
+
+  size_t back = pos;
+  while (pos < len)
+    {
+      if (_S_is_dir_sep(_M_pathname[pos]))
+       {
+         if (back != pos)
+           _M_add_filename(back, pos - back);
+         back = ++pos;
+       }
+      else
+       ++pos;
+    }
+
+  if (back != pos)
+    _M_add_filename(back, pos - back);
+  else if (_S_is_dir_sep(_M_pathname.back()))
+    {
+      // [fs.path.itr]/4
+      // An empty element, if trailing non-root directory-separator present.
+      if (_M_cmpts.back()._M_type == _Type::_Filename)
+       {
+         const auto& last = _M_cmpts.back();
+         pos = last._M_pos + last._M_pathname.size();
+         _M_cmpts.emplace_back(string_type(), _Type::_Filename, pos);
+       }
+    }
+
+  _M_trim();
+}
+
+void
+path::_M_add_root_name(size_t n)
+{
+  _M_cmpts.emplace_back(_M_pathname.substr(0, n), _Type::_Root_name, 0);
+}
+
+void
+path::_M_add_root_dir(size_t pos)
+{
+  _M_cmpts.emplace_back(_M_pathname.substr(pos, 1), _Type::_Root_dir, pos);
+}
+
+void
+path::_M_add_filename(size_t pos, size_t n)
+{
+  _M_cmpts.emplace_back(_M_pathname.substr(pos, n), _Type::_Filename, pos);
+}
+
+void
+path::_M_trim()
+{
+  if (_M_cmpts.size() == 1)
+    {
+      _M_type = _M_cmpts.front()._M_type;
+      _M_cmpts.clear();
+    }
+}
+
+path::string_type
+path::_S_convert_loc(const char* __first, const char* __last,
+                    const std::locale& __loc)
+{
+#if _GLIBCXX_USE_WCHAR_T
+  auto& __cvt = std::use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc);
+  basic_string<wchar_t> __ws;
+  if (!__str_codecvt_in(__first, __last, __ws, __cvt))
+    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+         "Cannot convert character sequence",
+         std::make_error_code(errc::illegal_byte_sequence)));
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+  return __ws;
+#else
+  return _Cvt<wchar_t>::_S_convert(__ws.data(), __ws.data() + __ws.size());
+#endif
+#else
+  return {__first, __last};
+#endif
+}
+
+std::size_t
+fs::hash_value(const path& p) noexcept
+{
+  // [path.non-member]
+  // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
+  // Equality works as if by traversing the range [begin(), end()), meaning
+  // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname
+  // but need to iterate over individual elements. Use the hash_combine from
+  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
+  size_t seed = 0;
+  for (const auto& x : p)
+    {
+      seed ^= std::hash<path::string_type>()(x.native()) + 0x9e3779b9
+       + (seed<<6) + (seed>>2);
+    }
+  return seed;
+}
+
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+  string
+  fs_err_concat(const string& __what, const string& __path1,
+                 const string& __path2)
+  {
+    const size_t __len = 18 + __what.length()
+      + (__path1.length() ? __path1.length() + 3 : 0)
+      + (__path2.length() ? __path2.length() + 3 : 0);
+    string __ret;
+    __ret.reserve(__len);
+    __ret = "filesystem error: ";
+    __ret += __what;
+    if (!__path1.empty())
+      {
+       __ret += " [";
+       __ret += __path1;
+       __ret += ']';
+      }
+    if (!__path2.empty())
+      {
+       __ret += " [";
+       __ret += __path2;
+       __ret += ']';
+      }
+    return __ret;
+  }
+
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+  std::string filesystem_error::_M_gen_what()
+  {
+    return fs_err_concat(system_error::what(), _M_path1.native(),
+                        _M_path2.native());
+  }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+
+} // filesystem
+_GLIBCXX_END_NAMESPACE_VERSION
+} // std
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
new file mode 100644 (file)
index 0000000..c3e6f01
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  // Test non-existent path.
+  const auto p = __gnu_test::nonexistent_path();
+  fs::directory_iterator iter(p, ec);
+  VERIFY( ec );
+  VERIFY( iter == end(iter) );
+
+  // Test empty directory.
+  create_directory(p, fs::current_path(), ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter == end(iter) );
+
+  // Test non-empty directory.
+  ec = bad_ec;
+  create_directory_symlink(p, p / "l", ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != fs::directory_iterator() );
+  VERIFY( iter->path() == p/"l" );
+  ++iter;
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible directory.
+  ec = bad_ec;
+  permissions(p, fs::perms::none, ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::directory_iterator(p, ec);
+  VERIFY( ec );
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible directory, skipping permission denied.
+  const auto opts = fs::directory_options::skip_permission_denied;
+  ec = bad_ec;
+  iter = fs::directory_iterator(p, opts, ec);
+  VERIFY( !ec );
+  VERIFY( iter == end(iter) );
+
+  permissions(p, fs::perms::owner_all, ec);
+  remove_all(p, ec);
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  ec = bad_ec;
+  create_directory(p, fs::current_path(), ec);
+  create_directory_symlink(p, p / "l", ec);
+  VERIFY( !ec );
+
+  // Test post-increment (libstdc++/71005)
+  ec = bad_ec;
+  auto iter = fs::directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != end(iter) );
+  const auto entry1 = *iter;
+  const auto entry2 = *iter++;
+  VERIFY( entry1 == entry2 );
+  VERIFY( entry1.path() == p/"l" );
+  VERIFY( iter == end(iter) );
+
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  std::error_code ec = make_error_code(std::errc::invalid_argument);
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "longer_than_small_string_buffer", ec);
+  VERIFY( !ec );
+
+  // Test for no reallocation on each dereference (this is a GNU extension)
+  auto iter = fs::directory_iterator(p, ec);
+  const auto* s1 = iter->path().c_str();
+  const auto* s2 = iter->path().c_str();
+  VERIFY( s1 == s2 );
+
+  remove_all(p, ec);
+}
+
+void
+test04()
+{
+  const fs::directory_iterator it;
+  VERIFY( it == fs::directory_iterator() );
+}
+
+void
+test05()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  create_directory_symlink(p, p / "l");
+  fs::directory_iterator it(p), endit;
+  VERIFY( begin(it) == it );
+  static_assert( noexcept(begin(it)), "begin is noexcept" );
+  VERIFY( end(it) == endit );
+  static_assert( noexcept(end(it)), "end is noexcept" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc
new file mode 100644 (file)
index 0000000..02dc04f
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  std::error_code ec;
+  fs::recursive_directory_iterator dir;
+  dir.pop(ec);  // This is undefined, but our implementation
+  VERIFY( ec ); // checks and returns an error.
+  VERIFY( dir == end(dir) );
+
+  std::error_code ec2;
+  try
+  {
+    dir.pop();
+  }
+  catch (const fs::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+  }
+  VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "d1/d2/d3");
+  for (int i = 0; i < 3; ++i)
+  {
+    fs::recursive_directory_iterator dir(p);
+    VERIFY( dir != end(dir) );
+    std::advance(dir, i);
+    VERIFY( dir != end(dir) );
+    VERIFY( dir.depth() == i );
+    ec = bad_ec;
+    dir.pop(ec);
+    VERIFY( !ec );
+    VERIFY( dir == end(dir) );
+
+    dir = fs::recursive_directory_iterator(p);
+    std::advance(dir, i);
+    VERIFY( dir != end(dir) );
+    VERIFY( dir.depth() == i );
+    dir.pop();
+    VERIFY( dir == end(dir) );
+  }
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  create_directories(p / "d1/d2/d3");
+  create_directories(p / "d1/d2/e3");
+  create_directories(p / "d1/e2/d3");
+  for (int i = 0; i < 3; ++i)
+  {
+    fs::recursive_directory_iterator dir(p);
+    std::advance(dir, i);
+    VERIFY( dir != end(dir) );
+    int expected_depth = i;
+    VERIFY( dir.depth() == expected_depth );
+    ec = bad_ec;
+    dir.pop(ec);
+    VERIFY( !ec );
+    if (dir != end(dir))
+      VERIFY( dir.depth() == (expected_depth - 1) );
+
+    dir = fs::recursive_directory_iterator(p);
+    std::advance(dir, i);
+    VERIFY( dir != end(dir) );
+    VERIFY( dir.depth() == i );
+    dir.pop();
+    if (dir != end(dir))
+      VERIFY( dir.depth() == (i -1) );
+  }
+  remove_all(p, ec);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
new file mode 100644 (file)
index 0000000..1ef450f
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  // Test non-existent path.
+  const auto p = __gnu_test::nonexistent_path();
+  fs::recursive_directory_iterator iter(p, ec);
+  VERIFY( ec );
+  VERIFY( iter == end(iter) );
+
+  // Test empty directory.
+  ec = bad_ec;
+  create_directory(p, fs::current_path(), ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter == end(iter) );
+
+  // Test non-empty directory.
+  ec = bad_ec;
+  create_directories(p / "d1/d2", ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != end(iter) );
+  VERIFY( iter->path() == p/"d1" );
+  ++iter;
+  VERIFY( iter->path() == p/"d1/d2" );
+  ++iter;
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible directory.
+  ec = bad_ec;
+  permissions(p, fs::perms::none, ec);
+  VERIFY( !ec );
+  iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( ec );
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible directory, skipping permission denied.
+  const auto opts = fs::directory_options::skip_permission_denied;
+  iter = fs::recursive_directory_iterator(p, opts, ec);
+  VERIFY( !ec );
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible sub-directory.
+  ec = bad_ec;
+  permissions(p, fs::perms::owner_all, ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  permissions(p/"d1/d2", fs::perms::none, ec);
+  VERIFY( !ec );
+  ec = bad_ec;
+  iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != end(iter) );
+  VERIFY( iter->path() == p/"d1" );
+  ++iter;              // should recurse into d1
+  VERIFY( iter->path() == p/"d1/d2" );
+  iter.increment(ec);  // should fail to recurse into p/d1/d2
+  VERIFY( ec );
+  VERIFY( iter == end(iter) );
+
+  // Test inaccessible sub-directory, skipping permission denied.
+  ec = bad_ec;
+  iter = fs::recursive_directory_iterator(p, opts, ec);
+  VERIFY( !ec );
+  VERIFY( iter != end(iter) );
+  VERIFY( iter->path() == p/"d1" );
+  ++iter;              // should recurse into d1
+  VERIFY( iter->path() == p/"d1/d2" );
+  ec = bad_ec;
+  iter.increment(ec);  // should fail to recurse into p/d1/d2, so skip it
+  VERIFY( !ec );
+  VERIFY( iter == end(iter) );
+
+  permissions(p/"d1/d2", fs::perms::owner_all, ec);
+  remove_all(p, ec);
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  ec = bad_ec;
+  create_directories(p / "d1/d2", ec);
+  VERIFY( !ec );
+
+  // Test post-increment (libstdc++/71005)
+  ec = bad_ec;
+  auto iter = fs::recursive_directory_iterator(p, ec);
+  VERIFY( !ec );
+  VERIFY( iter != end(iter) );
+  const auto entry1 = *iter;
+  const auto entry2 = *iter++;
+  VERIFY( entry1 == entry2 );
+  VERIFY( entry1.path() == p/"d1" );
+  const auto entry3 = *iter;
+  const auto entry4 = *iter++;
+  VERIFY( entry3 == entry4 );
+  VERIFY( entry3.path() == p/"d1/d2" );
+  VERIFY( iter == end(iter) );
+
+  remove_all(p, ec);
+}
+
+void
+test03()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  const auto p = __gnu_test::nonexistent_path();
+  ec = bad_ec;
+  create_directories(p / "longer_than_small_string_buffer", ec);
+  VERIFY( !ec );
+
+  // Test for no reallocation on each dereference (this is a GNU extension)
+  auto iter = fs::recursive_directory_iterator(p, ec);
+  const auto* s1 = iter->path().c_str();
+  const auto* s2 = iter->path().c_str();
+  VERIFY( s1 == s2 );
+
+  remove_all(p, ec);
+}
+
+void
+test04()
+{
+  // libstdc++/71004
+  const fs::recursive_directory_iterator it;
+  VERIFY( it == end(it) );
+}
+
+void
+test05()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  create_directory_symlink(p, p / "l");
+  fs::recursive_directory_iterator it(p), endit;
+  VERIFY( begin(it) == it );
+  static_assert( noexcept(begin(it)), "begin is noexcept" );
+  VERIFY( end(it) == endit );
+  static_assert( noexcept(end(it)), "end is noexcept" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
new file mode 100644 (file)
index 0000000..de1cd31
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.14.1 Absolute [fs.op.absolute]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+    VERIFY( absolute(p).is_absolute() );
+}
+
+void
+test02()
+{
+  path p1("/");
+  VERIFY( absolute(p1) == p1 );
+  path p2("/foo");
+  VERIFY( absolute(p2) == p2 );
+  path p3("foo");
+  VERIFY( absolute(p3) != p3 );
+  VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
new file mode 100644 (file)
index 0000000..646c37c
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  auto p = __gnu_test::nonexistent_path();
+  canonical( p, ec );
+  VERIFY( ec );
+
+  create_directory(p);
+  auto p2 = canonical( p, ec );
+  VERIFY( p2 == fs::current_path()/p );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p2 = canonical( fs::current_path() / "." / (p.native() + "////././."), ec );
+  VERIFY( p2 == fs::current_path()/p );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p = fs::current_path();
+  p2 = canonical( p, ec );
+  VERIFY( p2 == p );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p = "/";
+  p = canonical( p, ec );
+  VERIFY( p == "/" );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p = "/.";
+  p = canonical( p, ec );
+  VERIFY( p == "/" );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p = "/..";
+  p = canonical( p, ec );
+  VERIFY( p == "/" );
+  VERIFY( !ec );
+
+  ec = bad_ec;
+  p = "/../.././.";
+  p = canonical( p, ec );
+  VERIFY( p == "/" );
+  VERIFY( !ec );
+}
+
+void
+test02()
+{
+  const fs::path p = __gnu_test::nonexistent_path();
+  std::error_code ec, ec2;
+  const fs::path res = canonical(p, ec);
+  VERIFY( ec );
+  VERIFY( res.empty() );
+
+#if __cpp_exceptions
+  fs::path e1, e2;
+  try {
+    canonical(p);
+  } catch (const fs::filesystem_error& e) {
+    e1 = e.path1();
+    e2 = e.path2();
+    ec2 = e.code();
+  }
+  VERIFY( e1 == p );
+  VERIFY( e2.empty() );
+  VERIFY( ec == ec2 );
+#endif
+}
+
+
+void
+test03()
+{
+  std::error_code ec;
+  auto dir = __gnu_test::nonexistent_path();
+  fs::create_directory(dir);
+  fs::path foo = dir/"foo", bar = dir/"bar";
+  fs::create_directory(foo);
+  fs::create_directory(bar);
+  fs::create_symlink("../bar", foo/"baz");
+
+  auto dirc = canonical(dir);
+  auto barc = canonical(bar);
+
+  auto p1 = fs::canonical(dir/"foo//.///..//./");
+  VERIFY( p1 == dirc );
+  auto p2 = fs::canonical(dir/"foo//./baz///..//./");
+  VERIFY( p2 == dirc );
+  auto p3 = fs::canonical(dir/"foo//./baz////./");
+  VERIFY( p3 == barc );
+  auto p4 = fs::canonical(dir/"foo//./baz///..//./bar");
+  VERIFY( p4 == barc );
+  auto p5 = fs::canonical(dir/"foo//./baz///..//./bar/");
+  VERIFY( p5 == p4 );
+  auto p6 = fs::canonical(dir/"foo//./baz///..//./bar/.");
+  VERIFY( p6 == p4 );
+
+  remove_all(dir);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
new file mode 100644 (file)
index 0000000..7825a4e
--- /dev/null
@@ -0,0 +1,200 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 15.3 Copy [fs.op.copy]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+// Test error conditions.
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+
+  VERIFY( !fs::exists(p) );
+  fs::copy(p, ".", fs::copy_options::none, ec);
+  VERIFY( ec );
+
+  ec.clear();
+  fs::copy(".", ".", fs::copy_options::none, ec);
+  VERIFY( ec );
+
+  __gnu_test::scoped_file f(p);
+  VERIFY( fs::is_directory(".") );
+  VERIFY( fs::is_regular_file(p) );
+  ec.clear();
+  fs::copy(".", p, fs::copy_options::none, ec);
+  VERIFY( ec );
+
+  auto to = __gnu_test::nonexistent_path();
+  ec.clear();
+  auto opts = fs::copy_options::create_symlinks;
+  fs::copy("/", to, opts, ec);
+  VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+  VERIFY( !exists(to) );
+
+  ec.clear();
+  opts != fs::copy_options::recursive;
+  fs::copy("/", to, opts, ec);
+  VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+  VERIFY( !exists(to) );
+}
+
+// Test is_symlink(f) case.
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  auto from = __gnu_test::nonexistent_path();
+  auto to = __gnu_test::nonexistent_path();
+  std::error_code ec;
+
+  ec = bad_ec;
+  fs::create_symlink(".", from, ec);
+  VERIFY( !ec );
+  VERIFY( fs::exists(from) );
+
+  ec = bad_ec;
+  fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
+  VERIFY( !ec );
+  VERIFY( !fs::exists(to) );
+
+  ec = bad_ec;
+  fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
+  VERIFY( !ec );
+  VERIFY( !fs::exists(to) );
+
+  ec = bad_ec;
+  fs::copy(from, to,
+           fs::copy_options::skip_symlinks|fs::copy_options::copy_symlinks,
+           ec);
+  VERIFY( !ec );
+  VERIFY( !fs::exists(to) );
+
+  ec = bad_ec;
+  fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
+  VERIFY( !ec );
+  VERIFY( fs::exists(to) );
+  VERIFY( is_symlink(to) );
+
+  ec.clear();
+  fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
+  VERIFY( ec );
+
+  remove(from, ec);
+  remove(to, ec);
+}
+
+// Test is_regular_file(f) case.
+void
+test03()
+{
+  auto from = __gnu_test::nonexistent_path();
+  auto to = __gnu_test::nonexistent_path();
+
+  // test empty file
+  std::ofstream{from.native()};
+  VERIFY( fs::exists(from) );
+  VERIFY( fs::file_size(from) == 0 );
+  fs::copy(from, to);
+  VERIFY( fs::exists(to) );
+  VERIFY( fs::file_size(to) == 0 );
+
+  remove(to);
+  VERIFY( !fs::exists(to) );
+  std::ofstream{from.native()} << "Hello, filesystem!";
+  VERIFY( fs::file_size(from) != 0 );
+  fs::copy(from, to);
+  VERIFY( fs::exists(to) );
+  VERIFY( fs::file_size(to) == fs::file_size(from) );
+
+  remove(from);
+  remove(to);
+}
+
+// Test is_directory(f) case.
+void
+test04()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  auto from = __gnu_test::nonexistent_path();
+  auto to = __gnu_test::nonexistent_path();
+  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);
+
+  ec = bad_ec;
+  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.
+void
+test05()
+{
+  auto to = __gnu_test::nonexistent_path();
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+
+  fs::copy("/", to, fs::copy_options::copy_symlinks, ec);
+  VERIFY( !ec );  // Previous value should be cleared (LWG 2683)
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
new file mode 100644 (file)
index 0000000..69ab7fb
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 15.4 Copy [fs.op.copy_file]
+
+#include <filesystem>
+#include <fstream>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using std::filesystem::copy_options;
+  std::error_code ec;
+
+  auto from = __gnu_test::nonexistent_path();
+  auto to = __gnu_test::nonexistent_path();
+
+  // test non-existent file
+  bool b = copy_file(from, to, ec);
+  VERIFY( !b );
+  VERIFY( ec );
+  VERIFY( !exists(to) );
+
+  // test empty file
+  std::ofstream{from.native()};
+  VERIFY( exists(from) );
+  VERIFY( file_size(from) == 0 );
+
+  b = copy_file(from, to);
+  VERIFY( b );
+  VERIFY( exists(to) );
+  VERIFY( file_size(to) == 0 );
+  remove(to);
+  VERIFY( !exists(to) );
+  b = copy_file(from, to, copy_options::none, ec);
+  VERIFY( b );
+  VERIFY( !ec );
+  VERIFY( exists(to) );
+  VERIFY( file_size(to) == 0 );
+
+  std::ofstream{from.native()} << "Hello, filesystem!";
+  VERIFY( file_size(from) != 0 );
+  remove(to);
+  VERIFY( !exists(to) );
+  b = copy_file(from, to);
+  VERIFY( b );
+  VERIFY( exists(to) );
+  VERIFY( file_size(to) == file_size(from) );
+  remove(to);
+  VERIFY( !exists(to) );
+  b = copy_file(from, to);
+  VERIFY( b );
+  VERIFY( exists(to) );
+  VERIFY( file_size(to) == file_size(from) );
+
+  remove(from);
+  remove(to);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
new file mode 100644 (file)
index 0000000..9459678
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  // Test empty path.
+  bool b = fs::create_directories( "", ec );
+  VERIFY( ec );
+  VERIFY( !b );
+
+  // Test existing path.
+  ec = bad_ec;
+  b = fs::create_directories( fs::current_path(), ec );
+  VERIFY( !ec );
+  VERIFY( !b );
+
+  // Test non-existent path.
+  const auto p = __gnu_test::nonexistent_path();
+  ec = bad_ec;
+  b = fs::create_directories( p, ec );
+  VERIFY( !ec );
+  VERIFY( b );
+  VERIFY( is_directory(p) );
+
+  ec = bad_ec;
+  b = fs::create_directories( p/".", ec );
+  VERIFY( !ec );
+  VERIFY( !b );
+
+  ec = bad_ec;
+  b = fs::create_directories( p/"..", ec );
+  VERIFY( !ec );
+  VERIFY( !b );
+
+  ec = bad_ec;
+  b = fs::create_directories( p/"d1/d2/d3", ec );
+  VERIFY( !ec );
+  VERIFY( b );
+  VERIFY( is_directory(p/"d1/d2/d3") );
+
+  ec = bad_ec;
+  b = fs::create_directories( p/"./d4/../d5", ec );
+  VERIFY( !ec );
+  VERIFY( b );
+  VERIFY( is_directory(p/"./d4/../d5") );
+
+  std::uintmax_t count = remove_all(p, ec);
+  VERIFY( count == 6 );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc
new file mode 100644 (file)
index 0000000..927a97c
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  // Test empty path.
+  fs::path p;
+  bool b = create_directory( p, ec );
+  VERIFY( ec );
+  VERIFY( !b );
+
+  // Test non-existent path
+  p = __gnu_test::nonexistent_path();
+  VERIFY( !exists(p) );
+
+  ec = bad_ec;
+  b = create_directory(p, ec); // create the directory once
+  VERIFY( !ec );
+  VERIFY( b );
+  VERIFY( exists(p) );
+
+  // Test existing path (libstdc++/71036).
+  ec = bad_ec;
+  b = create_directory(p, ec);
+  VERIFY( !ec );
+  VERIFY( !b );
+  b = create_directory(p);
+  VERIFY( !b );
+
+  remove_all(p, ec);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc
new file mode 100644 (file)
index 0000000..7eff356
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::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::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == tgt );
+    VERIFY( ex.path2() == p );
+  }
+  VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  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) );
+
+  ec = bad_ec;
+  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) );
+
+  ec.clear();
+  create_symlink(tgt, p, ec); // Try to create existing symlink
+  VERIFY( ec );
+  try
+  {
+    create_symlink(tgt, p);
+  }
+  catch (const std::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == tgt );
+    VERIFY( ex.path2() == p );
+  }
+  VERIFY( ec2 == ec );
+
+  remove(p);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc
new file mode 100644 (file)
index 0000000..2ba3ff9
--- /dev/null
@@ -0,0 +1,58 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 15.11 Current path [fs.op.current_path]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  fs::path dot(".");
+  fs::path cwd = fs::current_path();
+  std::error_code ec;
+  fs::path cwd2 = fs::current_path(ec);
+  VERIFY( cwd == cwd2 );
+}
+
+void
+test02()
+{
+  auto oldwd = fs::current_path();
+  auto tmpdir = fs::temp_directory_path();
+  current_path(tmpdir);
+  VERIFY( canonical(fs::current_path()) == canonical(tmpdir) );
+  std::error_code ec;
+  current_path(oldwd, ec);
+  VERIFY( canonical(fs::current_path()) == canonical(oldwd) );
+  VERIFY( canonical(fs::current_path(ec)) == canonical(oldwd) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc
new file mode 100644 (file)
index 0000000..92d69c6
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  auto p1 = __gnu_test::nonexistent_path();
+  auto p2 = __gnu_test::nonexistent_path();
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+  bool result;
+
+  result = equivalent(p1, p2, ec);
+  VERIFY( ec );
+  VERIFY( !result );
+
+  __gnu_test::scoped_file f1(p1);
+  ec = bad_ec;
+  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();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
new file mode 100644 (file)
index 0000000..0775eff
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+
+  VERIFY( exists(path{"/"}) );
+  VERIFY( exists(path{"/."}) );
+  VERIFY( exists(path{"."}) );
+  VERIFY( exists(path{".."}) );
+  VERIFY( exists(std::filesystem::current_path()) );
+
+  std::error_code ec;
+  ec = bad_ec;
+  VERIFY( exists(path{"/"}, ec) );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( exists(path{"/."}, ec) );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( exists(path{"."}, ec) );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( exists(path{".."}, ec) );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( exists(std::filesystem::current_path(), ec) );
+  VERIFY( !ec );
+}
+
+void
+test02()
+{
+  path rel = __gnu_test::nonexistent_path();
+  VERIFY( !exists(rel) );
+
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+  VERIFY( !exists(rel, ec) );
+  VERIFY( !ec ); // DR 2725
+}
+
+void
+test03()
+{
+  path abs = absolute(__gnu_test::nonexistent_path());
+  VERIFY( !exists(abs) );
+
+  std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+  VERIFY( !exists(abs, ec) );
+  VERIFY( !ec ); // DR 2725
+}
+
+void
+test04()
+{
+  using std::filesystem::perms;
+  using std::filesystem::perm_options;
+  path p = __gnu_test::nonexistent_path();
+  create_directory(p);
+  permissions(p, perms::all, perm_options::remove);
+
+  auto unr = p / "unreachable";
+  std::error_code ec;
+  VERIFY( !exists(unr, ec) );
+  VERIFY( ec == std::errc::permission_denied );
+  ec.clear();
+  try
+  {
+    exists(unr);
+  }
+  catch(const std::filesystem::filesystem_error& ex)
+  {
+    ec = ex.code();
+    VERIFY( ex.path1() == unr );
+  }
+  VERIFY( ec == std::errc::permission_denied );
+
+  permissions(p, perms::owner_all);
+  remove(p);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc
new file mode 100644 (file)
index 0000000..250d318
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  std::error_code ec;
+  size_t size = fs::file_size(".", ec);
+  VERIFY( ec == std::errc::is_a_directory );
+  VERIFY( size == -1 );
+
+  try {
+    size = fs::file_size(".");
+    ec.clear();
+  } catch (const fs::filesystem_error& e) {
+    ec = e.code();
+  }
+  VERIFY( ec == std::errc::is_a_directory );
+  VERIFY( size == -1 );
+}
+
+void
+test02()
+{
+  fs::path p = __gnu_test::nonexistent_path();
+
+  std::error_code ec;
+  size_t size = fs::file_size(p, ec);
+  VERIFY( ec );
+  VERIFY( size == -1 );
+
+  try {
+    size = fs::file_size(p);
+    ec.clear();
+  } catch (const fs::filesystem_error& e) {
+    ec = e.code();
+  }
+  VERIFY( ec );
+  VERIFY( size == -1 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
new file mode 100644 (file)
index 0000000..6d79a91
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::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();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
new file mode 100644 (file)
index 0000000..ecef3f8
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 15.25 Permissions [fs.op.last_write_time]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+using time_type = std::filesystem::file_time_type;
+
+void
+test01()
+{
+  // read times
+
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+  time_type mtime = last_write_time(p, ec);
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#if __cpp_exceptions
+  bool caught = false;
+  try {
+    mtime = last_write_time(p);
+  } catch (std::system_error const& e) {
+    caught = true;
+    ec = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#endif
+
+  __gnu_test::scoped_file file(p);
+  VERIFY( exists(p) );
+  mtime = last_write_time(p, ec);
+  VERIFY( !ec );
+  VERIFY( mtime <= time_type::clock::now() );
+  VERIFY( mtime == last_write_time(p) );
+
+  auto end_of_time = time_type::duration::max();
+  auto last_second
+    = std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
+  if (last_second > std::numeric_limits<std::time_t>::max())
+    return; // can't test overflow
+
+#if _GLIBCXX_USE_UTIMENSAT
+  struct ::timespec ts[2];
+  ts[0].tv_sec = 0;
+  ts[0].tv_nsec = UTIME_NOW;
+  ts[1].tv_sec = std::numeric_limits<std::time_t>::max() - 1;
+  ts[1].tv_nsec = 0;
+  VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) );
+#elif _GLIBCXX_HAVE_UTIME_H
+  ::utimbuf times;
+  times.modtime = std::numeric_limits<std::time_t>::max() - 1;
+  times.actime = std::numeric_limits<std::time_t>::max() - 1;
+  VERIFY( !::utime(p.c_str(), &times) );
+#else
+  return;
+#endif
+
+  mtime = last_write_time(p, ec);
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+  VERIFY( mtime == time_type::min() );
+
+#if __cpp_exceptions
+  caught = false;
+  try {
+    mtime = last_write_time(p);
+  } catch (std::system_error const& e) {
+    caught = true;
+    ec = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec );
+  VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+#endif
+}
+
+bool approx_equal(time_type file_time, time_type expected)
+{
+  auto delta = expected - file_time;
+  if (delta < delta.zero())
+    delta = -delta;
+  return delta < std::chrono::seconds(1);
+}
+
+void
+test02()
+{
+  // write times
+
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  __gnu_test::scoped_file f;
+  std::error_code ec;
+  time_type time;
+
+  time = last_write_time(f.path);
+  ec = bad_ec;
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  ec = bad_ec;
+  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  ec = bad_ec;
+  time += std::chrono::milliseconds(1000 * 60 * 20 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  ec = bad_ec;
+  time = time_type();
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+
+  ec = bad_ec;
+  time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+  last_write_time(f.path, time, ec);
+  VERIFY( !ec );
+  VERIFY( approx_equal(last_write_time(f.path), time) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc
new file mode 100644 (file)
index 0000000..97b7a78
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// C++17 30.10.14.26 Permissions [fs.op.permissions]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using std::filesystem::perms;
+  using std::filesystem::perm_options;
+
+  auto p = __gnu_test::nonexistent_path();
+
+  __gnu_test::scoped_file f(p);
+  VERIFY( exists(p) );
+  permissions(p, perms::owner_all);
+  VERIFY( status(p).permissions() == perms::owner_all );
+  permissions(p, perms::group_read, perm_options::add);
+  VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
+  permissions(p, perms::group_read, perm_options::remove);
+  VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  using std::filesystem::perms;
+  using std::filesystem::perm_options;
+
+  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 = bad_ec;
+  permissions(p, perms::owner_all, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == perms::owner_all );
+  ec = bad_ec;
+  permissions(p, perms::group_read, perm_options::add, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
+  ec = bad_ec;
+  permissions(p, perms::group_read, perm_options::remove, ec);
+  VERIFY( !ec );
+  VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test03()
+{
+  using std::filesystem::perms;
+  using std::filesystem::perm_options;
+
+  __gnu_test::scoped_file f;
+  VERIFY( exists(f.path) );
+
+  auto p = __gnu_test::nonexistent_path();
+  create_symlink(f.path, p);
+
+  std::error_code ec = make_error_code(std::errc::no_such_file_or_directory);
+  std::error_code ec2 = make_error_code(std::errc::invalid_argument);
+  permissions(p, perms::owner_all,
+             perm_options::replace|perm_options::nofollow, ec);
+  try
+  {
+    permissions(p, perms::owner_all,
+               perm_options::replace|perm_options::nofollow);
+  }
+  catch (const std::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::filesystem::perms;
+
+  auto p = __gnu_test::nonexistent_path();
+  create_symlink(__gnu_test::nonexistent_path(), p);
+
+  std::error_code ec = make_error_code(std::errc::no_such_file_or_directory);
+  std::error_code ec2 = make_error_code(std::errc::invalid_argument);
+  permissions(p, perms::owner_all, ec);
+  VERIFY( ec );
+  try
+  {
+    permissions(p, perms::owner_all);
+  }
+  catch (const std::filesystem::filesystem_error& ex)
+  {
+    ec2 = ex.code();
+    VERIFY( ex.path1() == p );
+  }
+  VERIFY( ec == ec2 );
+
+  remove(p);
+}
+
+void
+test05()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  using std::filesystem::perms;
+  using std::filesystem::perm_options;
+  std::error_code ec;
+
+  __gnu_test::scoped_file f;
+  auto p = perms::owner_write;
+
+  // symlink_nofollow should not give an error for non-symlinks
+  ec = bad_ec;
+  permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec);
+  VERIFY( !ec );
+  auto st = status(f.path);
+  VERIFY( st.permissions() == p );
+  p |= perms::owner_read;
+  ec = bad_ec;
+  permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec);
+  VERIFY( !ec );
+  st = status(f.path);
+  VERIFY( st.permissions() == p );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc
new file mode 100644 (file)
index 0000000..02da250
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::proximate;
+
+void
+test01()
+{
+  VERIFY( proximate("/a/d", "/a/b/c") == "../../d" );
+  VERIFY( proximate("/a/b/c", "/a/d") == "../b/c" );
+  VERIFY( proximate("a/b/c", "a") == "b/c" );
+  VERIFY( proximate("a/b/c", "a/b/c/x/y") == "../.." );
+  VERIFY( proximate("a/b/c", "a/b/c") == "." );
+  VERIFY( proximate("a/b", "c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec = bad_ec;
+  VERIFY( proximate("/a/d", "/a/b/c", ec) == "../../d" );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( proximate("/a/b/c", "/a/d", ec) == "../b/c" );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( proximate("a/b/c", "a", ec) == "b/c" );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( proximate("a/b/c", "a/b/c/x/y", ec) == "../.." );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( proximate("a/b/c", "a/b/c", ec) == "." );
+  VERIFY( !ec );
+  ec = bad_ec;
+  VERIFY( proximate("a/b", "c/d", ec) == "../../a/b" );
+  VERIFY( !ec );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc
new file mode 100644 (file)
index 0000000..067a609
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+
+  read_symlink(p, ec);
+  VERIFY( ec );
+
+  fs::path tgt = ".";
+  create_symlink(tgt, p);
+
+  auto result = read_symlink(p, ec);
+  VERIFY( !ec );
+  VERIFY( result == tgt );
+
+  remove(p);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc
new file mode 100644 (file)
index 0000000..c9765fa
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  auto q = __gnu_test::nonexistent_path();
+
+  auto r = relative(p, q);
+  VERIFY( r == ".."/p );
+
+  r = relative(p, p/q);
+  VERIFY( r == ".." );
+
+  r = relative(p/q, p);
+  VERIFY( r == q );
+
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  ec = bad_ec;
+  r = relative(p, q, ec);
+  VERIFY( !ec );
+  VERIFY( r == ".."/p );
+
+  ec = bad_ec;
+  r = relative(p, p/q, ec);
+  VERIFY( !ec );
+  VERIFY( r == ".." );
+
+  ec = bad_ec;
+  r = relative(p/q, p, ec);
+  VERIFY( !ec );
+  VERIFY( r == q );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
new file mode 100644 (file)
index 0000000..3f68f17
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::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();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
new file mode 100644 (file)
index 0000000..7b61135
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 30.10.14.3 Permissions [fs.op.space]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::filesystem::space_info s = std::filesystem::space("/");
+  std::error_code ec = make_error_code(std::errc::invalid_argument);
+  s = std::filesystem::space("/", ec);
+  VERIFY( !ec );
+  s = std::filesystem::space(__gnu_test::nonexistent_path(), ec);
+  VERIFY( ec );
+  VERIFY( s.capacity ==  static_cast<uintmax_t>(-1) );
+  VERIFY( s.free ==  static_cast<uintmax_t>(-1) );
+  VERIFY( s.available ==  static_cast<uintmax_t>(-1) );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
new file mode 100644 (file)
index 0000000..efe92b2
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  std::error_code ec = make_error_code(std::errc::invalid_argument);
+  fs::path dot = ".";
+
+  fs::file_status st1 = fs::status(dot, ec);
+  VERIFY( !ec );
+  VERIFY( st1.type() == fs::file_type::directory );
+
+  fs::file_status st2 = fs::status(dot);
+  VERIFY( st2.type() == fs::file_type::directory );
+}
+
+void
+test02()
+{
+  fs::path p = __gnu_test::nonexistent_path();
+
+  std::error_code ec;
+  fs::file_status st1 = fs::status(p, ec);
+  VERIFY( ec );
+  VERIFY( st1.type() == fs::file_type::not_found );
+
+  fs::file_status st2 = fs::status(p);
+  VERIFY( st2.type() == fs::file_type::not_found );
+}
+
+void
+test03()
+{
+  fs::path dir = __gnu_test::nonexistent_path();
+  fs::create_directory(dir);
+  __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file);
+  __gnu_test::scoped_file f(dir / "file");
+  fs::permissions(dir, fs::perms::none);
+
+  std::error_code ec;
+  fs::file_status st = fs::status(f.path, ec);
+  VERIFY( ec.value() == (int)std::errc::permission_denied );
+  VERIFY( st.type() == fs::file_type::none );
+
+#if __cpp_exceptions
+  bool caught = false;
+  std::error_code ec2;
+  fs::path p, p2;
+  try {
+    fs::symlink_status(f.path);
+  } catch (const fs::filesystem_error& e) {
+    caught = true;
+    p = e.path1();
+    p2 = e.path2();
+    ec2 = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec2 == ec );
+  VERIFY( p == f.path );
+  VERIFY( p2.empty() );
+#endif
+
+  fs::permissions(dir, fs::perms::owner_all, ec);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
new file mode 100644 (file)
index 0000000..ae7a76b
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec = bad_ec;
+  fs::path dot = ".";
+
+  fs::file_status st1 = fs::symlink_status(dot, ec);
+  VERIFY( !ec );
+  VERIFY( st1.type() == fs::file_type::directory );
+
+  fs::file_status st2 = fs::symlink_status(dot);
+  VERIFY( st2.type() == fs::file_type::directory );
+
+  fs::path link = __gnu_test::nonexistent_path();
+  create_directory_symlink(dot, link);
+
+  st1 = fs::symlink_status(link);
+  VERIFY( st1.type() == fs::file_type::symlink );
+  ec = bad_ec;
+  st2 = fs::symlink_status(link, ec);
+  VERIFY( !ec );
+  VERIFY( st2.type() == fs::file_type::symlink );
+}
+
+void
+test02()
+{
+  fs::path p = __gnu_test::nonexistent_path();
+
+  std::error_code ec;
+  fs::file_status st1 = fs::symlink_status(p, ec);
+  VERIFY( ec );
+  VERIFY( st1.type() == fs::file_type::not_found );
+
+  fs::file_status st2 = fs::symlink_status(p);
+  VERIFY( st2.type() == fs::file_type::not_found );
+}
+
+void
+test03()
+{
+  fs::path dir = __gnu_test::nonexistent_path();
+  fs::create_directory(dir);
+  __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file);
+  __gnu_test::scoped_file f(dir / "file");
+  fs::permissions(dir, fs::perms::none);
+  auto link = __gnu_test::nonexistent_path();
+  fs::create_symlink(f.path, link);
+  __gnu_test::scoped_file l(link, __gnu_test::scoped_file::adopt_file);
+
+  std::error_code ec;
+  fs::file_status st = fs::symlink_status(f.path, ec);
+  VERIFY( ec.value() == (int)std::errc::permission_denied );
+  VERIFY( st.type() == fs::file_type::none );
+
+  st = fs::symlink_status(link, ec);
+  VERIFY( !ec );
+  VERIFY( st.type() == fs::file_type::symlink );
+
+#if __cpp_exceptions
+  bool caught = false;
+  std::error_code ec2;
+  fs::path p, p2;
+  try {
+    fs::symlink_status(f.path);
+  } catch (const fs::filesystem_error& e) {
+    caught = true;
+    p = e.path1();
+    p2 = e.path2();
+    ec2 = e.code();
+  }
+  VERIFY( caught );
+  VERIFY( ec2.value() == (int)std::errc::permission_denied );
+  VERIFY( p == f.path );
+  VERIFY( p2.empty() );
+#endif
+
+  fs::file_status st2 = symlink_status(link);
+  VERIFY( st2.type() == fs::file_type::symlink );
+
+  fs::permissions(dir, fs::perms::owner_all, ec);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
new file mode 100644 (file)
index 0000000..ee065f0
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright (C) 2015-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <stdlib.h>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+void
+clean_env()
+{
+  ::unsetenv("TMPDIR");
+  ::unsetenv("TMP");
+  ::unsetenv("TEMPDIR");
+  ::unsetenv("TEMP");
+}
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  clean_env();
+
+  if (!fs::exists("/tmp"))
+    return; // just give up
+
+  std::error_code ec = make_error_code(std::errc::invalid_argument);
+  fs::path p1 = fs::temp_directory_path(ec);
+  VERIFY( !ec );
+  VERIFY( exists(p1) );
+
+  fs::path p2 = fs::temp_directory_path();
+  VERIFY( p1 == p2 );
+}
+
+void
+test02()
+{
+  clean_env();
+
+  if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
+    return; // just give up
+
+  std::error_code ec;
+  fs::path p = fs::temp_directory_path(ec);
+  VERIFY( ec );
+  VERIFY( p == fs::path() );
+
+  std::error_code ec2;
+  try {
+    p = fs::temp_directory_path();
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+}
+
+void
+test03()
+{
+  auto p = __gnu_test::nonexistent_path();
+  create_directories(p/"tmp");
+  permissions(p, fs::perms::none);
+  setenv("TMPDIR", (p/"tmp").c_str(), 1);
+  std::error_code ec;
+  auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
+  VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+  VERIFY( r == fs::path() );
+
+  std::error_code ec2;
+  try {
+    fs::temp_directory_path();
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+
+  permissions(p, fs::perms::owner_all, ec);
+  remove_all(p, ec);
+}
+
+void
+test04()
+{
+  __gnu_test::scoped_file f;
+  setenv("TMPDIR", f.path.c_str(), 1);
+  std::error_code ec;
+  auto r = fs::temp_directory_path(ec);
+  VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
+  VERIFY( r == fs::path() );
+
+  std::error_code ec2;
+  try {
+    fs::temp_directory_path();
+  } catch (const fs::filesystem_error& e) {
+    ec2 = e.code();
+  }
+  VERIFY( ec2 == ec );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc
new file mode 100644 (file)
index 0000000..0f285e2
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+  auto dir = __gnu_test::nonexistent_path();
+  fs::create_directory(dir);
+  const auto dirc = canonical(dir);
+  fs::path foo = dir/"foo", bar = dir/"bar";
+  fs::create_directory(foo);
+  fs::create_directory(bar);
+  fs::create_directory(bar/"baz");
+  fs::create_symlink("../bar", foo/"bar");
+
+  auto p = fs::weakly_canonical(dir/"foo//./bar///../biz/.");
+  VERIFY( p == dirc/"biz/" );
+  p = fs::weakly_canonical(dir/"foo/.//bar/././baz/.");
+  VERIFY( p == dirc/"bar/baz" );
+  p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz");
+  VERIFY( p == dirc/"bar/baz" );
+
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  std::error_code ec;
+
+  ec = bad_ec;
+  p = fs::weakly_canonical(dir/"foo//./bar///../biz/.", ec);
+  VERIFY( !ec );
+  VERIFY( p == dirc/"biz/" );
+  ec = bad_ec;
+  p = fs::weakly_canonical(dir/"foo/.//bar/././baz/.", ec);
+  VERIFY( !ec );
+  VERIFY( p == dirc/"bar/baz" );
+  ec = bad_ec;
+  p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz", ec);
+  VERIFY( !ec );
+  VERIFY( p == dirc/"bar/baz" );
+
+  fs::remove_all(dir, ec);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
new file mode 100644 (file)
index 0000000..64c638e
--- /dev/null
@@ -0,0 +1,87 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.3 path appends [path.append]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const path p("/foo/bar");
+
+  path pp = p;
+  pp /= p;
+  VERIFY( pp.native() == p.native() );
+
+  path q("baz");
+
+  path qq = q;
+  qq /= q;
+  VERIFY( qq.native() == "baz/baz" );
+
+  q /= p;
+  VERIFY( q.native() == p.native() );
+
+  path r = "";
+  r /= path();
+  VERIFY( r.empty() );
+
+  r /= path("rel");
+  VERIFY( !r.is_absolute() );
+
+  path s = "dir/";
+  s /= path("/file");
+  VERIFY( s.native() == "/file" );
+
+  s = "dir/";
+  s /= path("file");
+  VERIFY( s.native() == "dir/file" );
+}
+
+void
+test02()
+{
+  // C++17 [fs.path.append] p4
+
+  path p = path("//host") / "foo";
+  VERIFY( p == "//host/foo" );
+
+  path pp = path("//host/") / "foo";
+  VERIFY( pp == "//host/foo" );
+
+  path q = path("foo") / "";
+  VERIFY( q == "foo/" );
+
+  path qq = path("foo") / "/bar";
+  VERIFY( qq == "/bar" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc
new file mode 100644 (file)
index 0000000..d8797ca
--- /dev/null
@@ -0,0 +1,94 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+  for (std::string s : __gnu_test::test_paths)
+  {
+    path p0 = s, p1, p2, p3, p4;
+
+    p1 = s;
+    compare_paths(p0, p1);
+
+    p2 = s.c_str();
+    compare_paths(p0, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring ws(s.begin(), s.end());
+
+    p3 = ws;
+    compare_paths(p0, p3);
+
+    p4 = ws.c_str();
+    compare_paths(p0, p4);
+#endif
+  }
+}
+
+void
+test02()
+{
+  for (std::string s : __gnu_test::test_paths)
+  {
+    path p0 = s, p1, p2, p3, p4, p5, p6, p7, p8;
+
+    p1.assign(s);
+    compare_paths(p0, p1);
+
+    p2.assign( s.begin(), s.end() );
+    compare_paths(p0, p2);
+
+    p3.assign( s.c_str() );
+    compare_paths(p0, p3);
+
+    p4.assign( s.c_str(), s.c_str() + s.size() );
+    compare_paths(p0, p4);
+
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring ws(s.begin(), s.end());
+
+    p5.assign(ws);
+    compare_paths(p0, p5);
+
+    p6.assign( ws.begin(), ws.end() );
+    compare_paths(p0, p6);
+
+    p7.assign( ws.c_str() );
+    compare_paths(p0, p7);
+
+    p8.assign( ws.c_str(), ws.c_str() + ws.size() );
+    compare_paths(p0, p8);
+#endif
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
new file mode 100644 (file)
index 0000000..27bf00a
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+#include <filesystem>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path copy;
+    copy = p;
+    __gnu_test::compare_paths(p, copy);
+  }
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path copy = p;
+    path move;
+    move = std::move(copy);
+    __gnu_test::compare_paths(p, move);
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc
new file mode 100644 (file)
index 0000000..e444220
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p("/foo/bar");
+  VERIFY( p.compare(p) == 0 );
+  VERIFY( p.compare("/foo//bar") == 0 );
+
+  path q("/foo/baz");
+  VERIFY( p.compare(q) < 0 );
+  VERIFY( q.compare(p) > 0 );
+
+  path r("/foo/bar/.");
+  VERIFY( p.compare(r) < 0 );
+
+  VERIFY( path("a/b/").compare("a/b//") == 0 );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc
new file mode 100644 (file)
index 0000000..4bed5a2
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const path p0 = "/a/a/b/b";
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.compare(p) == 0 );
+    int cmp = p.compare(p0);
+    if (cmp == 0)
+      VERIFY( p0.compare(p) == 0 );
+    else if (cmp < 0)
+      VERIFY( p0.compare(p) > 0 );
+    else if (cmp > 0)
+      VERIFY( p0.compare(p) < 0 );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc
new file mode 100644 (file)
index 0000000..be8f8b0
--- /dev/null
@@ -0,0 +1,49 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const std::string s0 = "/a/a/b/b";
+  const path p0 = s0;
+  for (const std::string& s : __gnu_test::test_paths)
+  {
+    path p(s);
+    VERIFY( p.compare(s) == 0 );
+    VERIFY( p.compare(s.c_str()) == 0 );
+    VERIFY( p.compare(p0) == p.compare(s0) );
+    VERIFY( p.compare(p0) == p.compare(s0.c_str()) );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc
new file mode 100644 (file)
index 0000000..46cf09a
--- /dev/null
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.4 path concatenation [path.concat]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const path p("/foo/bar");
+
+  path pp = p;
+  pp += p;
+  VERIFY( pp.native() == "/foo/bar/foo/bar" );
+  VERIFY( std::distance(pp.begin(), pp.end()) == 5 );
+
+  path q("foo/bar");
+
+  path qq = q;
+  qq += q;
+  VERIFY( qq.native() == "foo/barfoo/bar" );
+  VERIFY( std::distance(qq.begin(), qq.end()) == 3 );
+
+  q += p;
+  VERIFY( q.native() == "foo/bar/foo/bar" );
+  VERIFY( std::distance(q.begin(), q.end()) == 4 );
+}
+
+void
+test02()
+{
+  for (path p : __gnu_test::test_paths)
+  {
+    auto prior_native = p.native();
+    path x("//blah/di/blah");
+    p += x;
+    VERIFY( p.native() == prior_native + x.native() );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc
new file mode 100644 (file)
index 0000000..3eb4d1a
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.4 path concatenation [path.concat]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p("/");
+  p += path::string_type("foo");
+  VERIFY( p.filename() == "foo" );
+  p += "bar";
+  VERIFY( p.filename() == "foobar" );
+  p += '/';
+  VERIFY( p.parent_path() == "/foobar" && p.filename() == "" );
+#if _GLIBCXX_USE_WCHAR_T
+  p += L"baz.txt";
+#else
+  p += "baz.txt";
+#endif
+  VERIFY( p.filename() == "baz.txt" );
+  p.concat("/dir/");
+  VERIFY( p.parent_path() == "/foobar/baz.txt/dir" && p.filename() == "" );
+  std::string file = "file";
+  p.concat(file.begin(), file.end());
+  VERIFY( p.filename() == "file" );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc
new file mode 100644 (file)
index 0000000..cb084bd
--- /dev/null
@@ -0,0 +1,55 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path copy = p;
+    __gnu_test::compare_paths(p, copy);
+  }
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path copy = p;
+    path move = std::move(copy);
+    __gnu_test::compare_paths(p, move);
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc
new file mode 100644 (file)
index 0000000..85ce129
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p;
+  VERIFY(  p.empty() );
+  VERIFY( !p.has_root_path() );
+  VERIFY( !p.has_root_name() );
+  VERIFY( !p.has_root_directory() );
+  VERIFY( !p.has_relative_path() );
+  VERIFY( !p.has_parent_path() );
+  VERIFY( !p.has_filename() );
+  VERIFY( !p.has_stem() );
+  VERIFY( !p.has_extension() );
+  VERIFY( !p.is_absolute() );
+  VERIFY(  p.is_relative() );
+  VERIFY( std::distance(p.begin(), p.end()) == 0 );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
new file mode 100644 (file)
index 0000000..e313412
--- /dev/null
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p("/foo/bar", std::locale::classic());
+  VERIFY( p.string() == "/foo/bar" );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc
new file mode 100644 (file)
index 0000000..ad2cc18
--- /dev/null
@@ -0,0 +1,112 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <string>
+#include <testsuite_fs.h>
+#include <testsuite_iterators.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+  for (std::string s : __gnu_test::test_paths)
+  {
+    path p1 = s;
+    path p2( s.begin(), s.end() );
+    path p3( s.c_str() );
+    path p4( s.c_str(), s.c_str() + s.size() );
+
+    compare_paths(p1, p2);
+    compare_paths(p1, p3);
+    compare_paths(p1, p4);
+
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring ws(s.begin(), s.end());
+    path p5 = ws;
+    path p6( ws.begin(), ws.end() );
+    path p7( ws.c_str() );
+    path p8( ws.c_str(), ws.c_str() + ws.size() );
+
+    compare_paths(p1, p5);
+    compare_paths(p1, p6);
+    compare_paths(p1, p7);
+    compare_paths(p1, p8);
+#endif
+
+    using __gnu_test::test_container;
+    using __gnu_test::input_iterator_wrapper;
+    // Test with input iterators and const value_types
+
+    test_container<char, input_iterator_wrapper>
+      r1((char*)s.c_str(), (char*)s.c_str() + s.size());
+    path p9(r1.begin(), r1.end());
+    compare_paths(p1, p9);
+
+    test_container<char, input_iterator_wrapper>
+      r2((char*)s.c_str(), (char*)s.c_str() + s.size() + 1); // includes null-terminator
+    path p10(r2.begin());
+    compare_paths(p1, p10);
+
+    test_container<const char, input_iterator_wrapper>
+      r3(s.c_str(), s.c_str() + s.size());
+    path p11(r3.begin(), r3.end());
+    compare_paths(p1, p11);
+
+    test_container<const char, input_iterator_wrapper>
+      r4(s.c_str(), s.c_str() + s.size() + 1); // includes null-terminator
+    path p12(r4.begin());
+    compare_paths(p1, p12);
+
+#if _GLIBCXX_USE_WCHAR_T
+    // Test with input iterators and const value_types
+    test_container<wchar_t, input_iterator_wrapper>
+      r5((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size());
+    path p13(r5.begin(), r5.end());
+    compare_paths(p1, p13);
+
+    test_container<wchar_t, input_iterator_wrapper>
+      r6((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size() + 1); // includes null-terminator
+    path p14(r6.begin());
+    compare_paths(p1, p14);
+
+    test_container<const wchar_t, input_iterator_wrapper>
+      r7(ws.c_str(), ws.c_str() + ws.size());
+    path p15(r7.begin(), r7.end());
+    compare_paths(p1, p15);
+
+    test_container<const wchar_t, input_iterator_wrapper>
+      r8(ws.c_str(), ws.c_str() + ws.size() + 1); // includes null-terminator
+    path p16(r8.begin());
+    compare_paths(p1, p16);
+#endif
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc
new file mode 100644 (file)
index 0000000..b9a5205
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-options "-lstdc++fs -std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2016-2017 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/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <string_view>
+#include <string>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+  for (std::string s : __gnu_test::test_paths)
+  {
+    path p1 = s;
+    std::string_view sv(s);
+    path p2 = sv;
+    compare_paths(p1, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+    std::wstring ws(s.begin(), s.end());
+    path p3 = ws;
+    std::wstring_view wsv(ws);
+    path p4 = wsv;
+    compare_paths(p1, p4);
+#endif
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc
new file mode 100644 (file)
index 0000000..13c9db2
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path("/foo/bar.txt").extension() == path(".txt") );
+  VERIFY( path("/foo/bar.baz.txt").extension() == path(".txt") );
+  VERIFY( path(".bar.baz.txt").extension() == path(".txt") );
+
+  VERIFY( path(".profile").extension() == path("") );
+  VERIFY( path(".profile.old").extension() == path(".old") );
+  VERIFY( path("..abc").extension() == path(".abc") );
+  VERIFY( path("...abc").extension() == path(".abc") );
+  VERIFY( path("abc..def").extension() == path(".def") );
+  VERIFY( path("abc...def").extension() == path(".def") );
+  VERIFY( path("abc.").extension() == path(".") );
+  VERIFY( path("abc..").extension() == path(".") );
+  VERIFY( path("abc.d.").extension() == path(".") );
+  VERIFY( path("..").extension() == path("") );
+  VERIFY( path(".").extension() == path("") );
+
+  VERIFY( path().extension() == path() );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    auto stem = p.stem();
+    auto ext = p.extension();
+    auto file = p.filename();
+    VERIFY( stem.native() + ext.native() == file.native() );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc
new file mode 100644 (file)
index 0000000..8ba0fcc
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.7.4.9 path decomposition [fs.path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path("/foo/bar.txt").filename() == "bar.txt" );
+  VERIFY( path("/foo/bar").filename()     == "bar"     );
+  VERIFY( path("/foo/bar/").filename()    == ""        );
+  VERIFY( path("/").filename()            == ""        );
+#ifdef __CYGWIN__
+  VERIFY( path("//host").filename()       == ""        );
+#else
+  VERIFY( path("//host").filename()       == "host"    );
+#endif
+  VERIFY( path(".").filename()            == "."       );
+  VERIFY( path("..").filename()           == ".."      );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path f = p.filename();
+    if (p.empty())
+      VERIFY( f.empty() );
+    else
+    {
+      const path back = *--p.end();
+      if (back.has_root_path())
+       VERIFY( f.empty() );
+      else
+       VERIFY( f == back );
+    }
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc
new file mode 100644 (file)
index 0000000..c46566d
--- /dev/null
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p0;
+  VERIFY( p0.parent_path() == p0 );
+  path p1 = "foo";
+  VERIFY( p1.parent_path() == p0 );
+  path p2 = "foo/bar";
+  VERIFY( p2.parent_path() == p1 );
+  path p3 = "/foo/bar";
+  VERIFY( p3.parent_path() == path("/foo") );
+  VERIFY( p3.parent_path().parent_path() == path("/") );
+  VERIFY( p3.parent_path().parent_path().parent_path() == path("/") );
+  path p4 = "/";
+  VERIFY( p4.parent_path() == p4 );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    if (p.begin() == p.end())
+      continue;
+    if (p.has_relative_path())
+    {
+      path pp;
+      for (auto i = p.begin(), end = --p.end(); i != end; ++i)
+      {
+       pp /= *i;
+      }
+      VERIFY( p.parent_path() == pp );
+    }
+    else
+      VERIFY( p.parent_path() == p );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc
new file mode 100644 (file)
index 0000000..c864972
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p1 = "foo";
+  VERIFY( p1.relative_path() == p1 );
+  path p2 = "foo/bar";
+  VERIFY( p2.relative_path() == p2 );
+  path p3 = "/foo/bar";
+  VERIFY( p3.relative_path() == p2 );
+}
+
+#include <iostream> // XXX
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    bool after_root = false;
+    const path prel = p.relative_path();
+    VERIFY( !prel.has_root_name() );
+    path rel;
+    for (const auto& cmpt : p)
+    {
+      if (!cmpt.has_root_path())
+        after_root = true;
+      if (after_root)
+        rel /= cmpt;
+    }
+    if (prel != rel)
+      std::cout << prel << ' ' << rel << '\n';
+    VERIFY( prel == rel );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
new file mode 100644 (file)
index 0000000..8220c58
--- /dev/null
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p1 = "foo/bar";
+  VERIFY( p1.root_directory() == path() );
+  path p2 = "/foo/bar";
+  VERIFY( p2.root_directory() == path("/") );
+  path p3 = "//foo";
+  VERIFY( p3.root_directory() == path("/") );
+  path p4 = "///foo";
+  VERIFY( p4.root_directory() == path("/") );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path rootdir = p.root_directory();
+    VERIFY( !rootdir.has_relative_path() );
+    VERIFY( rootdir.empty() || rootdir.native() == "/");
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc
new file mode 100644 (file)
index 0000000..5bb2ccd
--- /dev/null
@@ -0,0 +1,43 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path("/foo/bar.txt").extension() == ".txt" );
+  VERIFY( path("/foo/bar.baz.txt").extension() == ".txt" );
+  VERIFY( path(".").extension().empty() );
+  VERIFY( path("..").extension().empty() );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc
new file mode 100644 (file)
index 0000000..bce0134
--- /dev/null
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.7.4.9 path decomposition [fs.path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p1 = "foo/bar";
+  VERIFY( p1.root_path() == path() );
+  path p2 = "/foo/bar";
+  VERIFY( p2.root_path() == path("/") );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y, Z) do { if (!(Y == Z)) { __builtin_printf("%s %s %s\n", X.c_str(), Y.c_str(), Z.c_str()); } } while(false)
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path rootp = p.root_path();
+    path rootn = p.root_name();
+    path rootd = p.root_directory();
+    VERIFY( rootp == (rootn / rootd) );
+    DUMP(p,  rootp , (rootn / rootd) );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
new file mode 100644 (file)
index 0000000..aec64e1
--- /dev/null
@@ -0,0 +1,62 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path("/foo/bar.txt").stem() == path("bar") );
+  path p = "foo.bar.baz.tar";
+  std::vector<std::string> v;
+  for (; !p.extension().empty(); p = p.stem())
+    v.push_back(p.extension().native());
+  VERIFY( v.at(0) == ".tar" );
+  VERIFY( v.at(1) == ".baz" );
+  VERIFY( v.at(2) == ".bar" );
+
+  VERIFY( path(".profile").stem() == path(".profile") );
+  VERIFY( path(".profile.old").stem() == path(".profile") );
+  VERIFY( path("..abc").stem() == path(".") );
+  VERIFY( path("...abc").stem() == path("..") );
+  VERIFY( path("abc..def").stem() == path("abc.") );
+  VERIFY( path("abc...def").stem() == path("abc..") );
+  VERIFY( path("abc.").stem() == path("abc") );
+  VERIFY( path("abc..").stem() == path("abc.") );
+  VERIFY( path("abc.d.").stem() == path("abc.d") );
+  VERIFY( path("..").stem() == path("..") );
+  VERIFY( path(".").stem() == path(".") );
+
+  VERIFY( path().stem() == path() );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
new file mode 100644 (file)
index 0000000..2e4ec5b
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  // C++17 [fs.path.gen] p2
+  VERIFY( path("foo/./bar/..").lexically_normal() == "foo/" );
+  VERIFY( path("foo/.///bar/../").lexically_normal() == "foo/" );
+}
+
+void
+test02()
+{
+  VERIFY( path("foo/../bar").lexically_normal() == "bar" );
+  VERIFY( path("../foo/../bar").lexically_normal() == "../bar" );
+  VERIFY( path("foo/../").lexically_normal() == "." );
+  VERIFY( path("../../").lexically_normal() == "../.." );
+  VERIFY( path("../").lexically_normal() == ".." );
+  VERIFY( path("./").lexically_normal() == "." );
+  VERIFY( path().lexically_normal() == "" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc
new file mode 100644 (file)
index 0000000..7a25f7b
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  // C++17 [fs.path.gen] p5
+  VERIFY( path("/a/d").lexically_proximate("/a/b/c") == "../../d" );
+  VERIFY( path("/a/b/c").lexically_proximate("/a/d") == "../b/c" );
+  VERIFY( path("a/b/c").lexically_proximate("a") == "b/c" );
+  VERIFY( path("a/b/c").lexically_proximate("a/b/c/x/y") == "../.." );
+  VERIFY( path("a/b/c").lexically_proximate("a/b/c") == "." );
+  VERIFY( path("a/b").lexically_proximate("c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+  path p = "a/b/c";
+  VERIFY( p.lexically_proximate(p) == "." );
+  VERIFY( p.lexically_proximate("a/../a/b/../b/c/../c/.") == "../../b/c" );
+  VERIFY( p.lexically_proximate("../../../") == p );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
new file mode 100644 (file)
index 0000000..64770fb
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) 2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  // C++17 [fs.path.gen] p5
+  VERIFY( path("/a/d").lexically_relative("/a/b/c") == "../../d" );
+  VERIFY( path("/a/b/c").lexically_relative("/a/d") == "../b/c" );
+  VERIFY( path("a/b/c").lexically_relative("a") == "b/c" );
+  VERIFY( path("a/b/c").lexically_relative("a/b/c/x/y") == "../.." );
+  VERIFY( path("a/b/c").lexically_relative("a/b/c") == "." );
+  VERIFY( path("a/b").lexically_relative("c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+  path p = "a/b/c";
+  VERIFY( p.lexically_relative(p) == "." );
+  VERIFY( p.lexically_relative("a/../a/b/../b/c/../c/.") == "../../b/c" );
+  VERIFY( p.lexically_relative("../../../") == "" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc
new file mode 100644 (file)
index 0000000..d25d505
--- /dev/null
@@ -0,0 +1,55 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2017 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/>.
+
+// C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path().generic_string() == "" );
+  VERIFY( path("/").generic_string() == "/" );
+  VERIFY( path("////").generic_string() == "/" );
+#ifdef __CYGWIN__
+  VERIFY( path("//a").generic_string() == "//a" );
+  VERIFY( path("//a/").generic_string() == "//a/" );
+  VERIFY( path("//a/b").generic_string() == "//a/b" );
+#else
+  VERIFY( path("//a").generic_string() == "/a" );
+  VERIFY( path("//a/").generic_string() == "/a/" );
+  VERIFY( path("//a/b").generic_string() == "/a/b" );
+#endif
+  VERIFY( path("/a//b").generic_string() == "/a/b" );
+  VERIFY( path("/a//b/").generic_string() == "/a/b/" );
+  VERIFY( path("/a//b//").generic_string() == "/a/b/" );
+  VERIFY( path("/a//b//.").generic_string() == "/a/b/." );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
new file mode 100644 (file)
index 0000000..7754140
--- /dev/null
@@ -0,0 +1,127 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.7.5 path iterators [fs.path.itr]
+
+#include <filesystem>
+#include <vector>
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  path p;
+  VERIFY( p.begin() == p.end() );
+
+  std::vector<path> v, v2;
+
+  p = "/";
+  v.assign(p.begin(), p.end());
+  v2 = { "/" };
+  VERIFY( v == v2 );
+
+  p = "filename";
+  v.assign(p.begin(), p.end());
+  v2 = { "filename" };
+  VERIFY( v == v2 );
+
+  p = "dir/.";
+  v.assign(p.begin(), p.end());
+  v2 = { "dir", "." };
+  VERIFY( v == v2 );
+
+  p = "dir/";
+  v.assign(p.begin(), p.end());
+  v2 = { "dir", "" };
+  VERIFY( v == v2 );
+
+  p = "//rootname/dir/.";
+  v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+  v2 = { "//rootname", "/", "dir", "." };
+#else
+  v2 = { "/", "rootname", "dir", "." };
+#endif
+  VERIFY( v == v2 );
+
+  p = "//rootname/dir/";
+  v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+  v2 = { "//rootname", "/", "dir", "" };
+#else
+  v2 = { "/", "rootname", "dir", "" };
+#endif
+  VERIFY( v == v2 );
+
+  p = "//rootname/dir/filename";
+  v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+  v2 = { "//rootname", "/", "dir", "filename" };
+#else
+  v2 = { "/", "rootname", "dir", "filename" };
+#endif
+  VERIFY( v == v2 );
+}
+
+void
+test02()
+{
+  using reverse_iterator = std::reverse_iterator<path::iterator>;
+  std::vector<path> fwd, rev;
+
+  for (const path& p : __gnu_test::test_paths)
+  {
+    const auto begin = p.begin(), end = p.end();
+    fwd.assign(begin, end);
+    rev.assign(reverse_iterator(end), reverse_iterator(begin));
+    VERIFY( fwd.size() == rev.size() );
+    VERIFY( std::equal(fwd.begin(), fwd.end(), rev.rbegin()) );
+  }
+}
+
+void
+test03()
+{
+  path paths[] = { "single", "multiple/elements" };
+  for (const path& p : paths)
+    for (auto iter = p.begin(); iter != p.end(); ++iter)
+    {
+      auto iter2 = iter;
+      ++iter;
+      iter2++;
+      VERIFY( iter2 == iter );
+      --iter;
+      iter2--;
+      VERIFY( iter2 == iter );
+    }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc
new file mode 100644 (file)
index 0000000..31d984f
--- /dev/null
@@ -0,0 +1,46 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (path p : __gnu_test::test_paths)
+  {
+    path empty;
+    p.clear();
+    VERIFY( p.empty() );
+    __gnu_test::compare_paths(p, empty);
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc
new file mode 100644 (file)
index 0000000..1df1009
--- /dev/null
@@ -0,0 +1,64 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+template<typename T, T sep>
+struct checker
+{
+  static void check(const char* s) { }
+};
+
+template<>
+struct checker<char, '/'>
+{
+  static void check()
+  {
+    VERIFY( path("foo/bar").make_preferred() == "foo/bar" );
+  }
+};
+
+template<>
+struct checker<wchar_t, L'\\'>
+{
+  static void check()
+  {
+    VERIFY( path("foo/bar").make_preferred() == L"foo\\bar" );
+  }
+};
+
+void
+test01()
+{
+  checker<path::value_type, path::preferred_separator>::check();
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc
new file mode 100644 (file)
index 0000000..02e1b05
--- /dev/null
@@ -0,0 +1,62 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  // C++17 [fs.path.modifiers] p8
+  VERIFY( path("foo/bar").remove_filename() == "foo/" );
+  VERIFY( path("foo/").remove_filename()    == "foo/" );
+  VERIFY( path("/foo").remove_filename()    == "/" );
+  VERIFY( path("/").remove_filename()       == "/" );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false)
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path p2(p);
+    p2.remove_filename();
+    p2 /= p.filename();
+    VERIFY( p2 == p );
+    DUMP( p2 , p );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc
new file mode 100644 (file)
index 0000000..cf7ca09
--- /dev/null
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( path("/foo.txt").replace_extension("cpp") == "/foo.cpp" );
+  VERIFY( path("/foo.txt").replace_extension(".cpp") == "/foo.cpp" );
+  VERIFY( path("/").replace_extension("bar") == "/.bar" );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path p2 = p;
+    VERIFY(p2.replace_extension(p2.extension()) == p);
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc
new file mode 100644 (file)
index 0000000..6d3b9b7
--- /dev/null
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  // C++17 [fs.path.modifiers] p11
+  VERIFY( path("/foo").replace_filename("bar") == "/bar" );
+  VERIFY( path("/").replace_filename("bar")    == "/bar" );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false)
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path p2(p);
+    p2.replace_filename(p.filename());
+    VERIFY( p2 == p );
+    DUMP( p2 , p );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc
new file mode 100644 (file)
index 0000000..f127604
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  const path p("/foo/bar");
+  path p1;
+  path p2 = p;
+  p1.swap(p2);
+  VERIFY( p2.empty() );
+  __gnu_test::compare_paths(p1, p);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
new file mode 100644 (file)
index 0000000..23d7970
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2016-2017 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 "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <string>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using namespace std::filesystem;
+  const std::string s = "abc";
+  path p(s);
+
+  VERIFY( p.native() == s );
+  VERIFY( p.c_str() == s );
+  VERIFY( static_cast<std::string>(p) == s );
+
+  std::string s2 = p; // implicit conversion
+  VERIFY( s2 == p.native() );
+}
+
+void
+test02()
+{
+  using namespace std::filesystem;
+  const char* s = "abc";
+  path p(s);
+
+  auto str = p.string<char>();
+  VERIFY( str == u"abc" );
+  VERIFY( str == p.string() );
+
+  auto strw = p.string<wchar_t>();
+  VERIFY( strw == L"abc" );
+  VERIFY( strw == p.wstring() );
+
+  auto str16 = p.string<char16_t>();
+  VERIFY( str16 == u"abc" );
+  VERIFY( str16 == p.u16string() );
+
+  auto str32 = p.string<char32_t>();
+  VERIFY( str32 == U"abc" );
+  VERIFY( str32 == p.u32string() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc
new file mode 100644 (file)
index 0000000..20f42ac
--- /dev/null
@@ -0,0 +1,52 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.6 path non-member functions [path.non-member]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  VERIFY( hash_value(path("a//b")) == hash_value(path("a/b")) );
+  VERIFY( hash_value(path("a/")) == hash_value(path("a//")) );
+}
+
+void
+test02()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    path pp = p.native();
+    VERIFY( hash_value(p) == hash_value(pp) );
+  }
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc
new file mode 100644 (file)
index 0000000..76277a0
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const std::string& s : __gnu_test::test_paths)
+  {
+    VERIFY( s.empty() == path(s).empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc
new file mode 100644 (file)
index 0000000..693bd38
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_extension() == !p.extension().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc
new file mode 100644 (file)
index 0000000..ce99af3
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_filename() == !p.filename().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc
new file mode 100644 (file)
index 0000000..4e23b24
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_parent_path() == !p.parent_path().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc
new file mode 100644 (file)
index 0000000..25e2dd5
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_relative_path() == !p.relative_path().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc
new file mode 100644 (file)
index 0000000..66c8df2
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_root_directory() == !p.root_directory().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc
new file mode 100644 (file)
index 0000000..f9d7157
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_root_name() == !p.root_name().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc
new file mode 100644 (file)
index 0000000..f0bdb81
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_root_path() == !p.root_path().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc
new file mode 100644 (file)
index 0000000..18bf015
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.has_stem() == !p.stem().empty() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc
new file mode 100644 (file)
index 0000000..c6f6c7f
--- /dev/null
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 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/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+  for (const path& p : __gnu_test::test_paths)
+  {
+    VERIFY( p.is_relative() == !p.is_absolute() );
+  }
+}
+
+int
+main()
+{
+  test01();
+}
index fbf8bd4..6879909 100644 (file)
@@ -24,6 +24,7 @@
 #include <experimental/filesystem>
 #include <string_view>
 #include <string>
+#define USE_FILESYSTEM_TS
 #include <testsuite_fs.h>
 
 using std::experimental::filesystem::path;
index 38ebd4f..e0db46c 100644 (file)
 #ifndef _TESTSUITE_FS_H
 #define _TESTSUITE_FS_H 1
 
+// Assume we want std::filesystem in C++17, unless USE_FILESYSTEM_TS defined:
+#if __cplusplus >= 201703L && ! defined USE_FILESYSTEM_TS
+#include <filesystem>
+namespace test_fs = std::filesystem;
+#else
 #include <experimental/filesystem>
+namespace test_fs = std::experimental::filesystem;
+#endif
 #include <fstream>
 #include <string>
 #include <cstdio>
@@ -33,12 +40,12 @@ namespace __gnu_test
 {
 #define PATH_CHK(p1, p2, fn) \
     if ( p1.fn() != p2.fn() ) \
-      throw std::experimental::filesystem::filesystem_error( #fn, p1, p2, \
+      throw test_fs::filesystem_error( #fn, p1, p2, \
          std::make_error_code(std::errc::invalid_argument) )
 
   void
-  compare_paths(const std::experimental::filesystem::path& p1,
-               const std::experimental::filesystem::path& p2)
+  compare_paths(const test_fs::path& p1,
+               const test_fs::path& p2)
   {
     PATH_CHK( p1, p2, string );
     PATH_CHK( p1, p2, empty );
@@ -55,7 +62,7 @@ namespace __gnu_test
     auto d1 = std::distance(p1.begin(), p1.end());
     auto d2 = std::distance(p2.begin(), p2.end());
     if( d1 != d2 )
-      throw std::experimental::filesystem::filesystem_error(
+      throw test_fs::filesystem_error(
          "distance(begin, end)", p1, p2,
          std::make_error_code(std::errc::invalid_argument) );
   }
@@ -67,15 +74,15 @@ namespace __gnu_test
 
   // This is NOT supposed to be a secure way to get a unique name!
   // We just need a path that doesn't exist for testing purposes.
-  std::experimental::filesystem::path
+  test_fs::path
   nonexistent_path()
   {
-    std::experimental::filesystem::path p;
+    test_fs::path p;
 #if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
-    char tmp[] = "filesystem-ts-test.XXXXXX";
+    char tmp[] = "filesystem-test.XXXXXX";
     int fd = ::mkstemp(tmp);
     if (fd == -1)
-      throw std::experimental::filesystem::filesystem_error("mkstemp failed",
+      throw test_fs::filesystem_error("mkstemp failed",
          std::error_code(errno, std::generic_category()));
     ::unlink(tmp);
     ::close(fd);
@@ -88,7 +95,7 @@ namespace __gnu_test
 #else
     std::sprintf(buf,
 #endif
-      "filesystem-ts-test.%d.%lu", counter++, (unsigned long) ::getpid());
+      "filesystem-test.%d.%lu", counter++, (unsigned long) ::getpid());
     p = buf;
 #endif
     return p;
@@ -97,7 +104,7 @@ namespace __gnu_test
   // RAII helper to remove a file on scope exit.
   struct scoped_file
   {
-    using path_type = std::experimental::filesystem::path;
+    using path_type = test_fs::path;
 
     enum adopt_file_t { adopt_file };