mirror of
https://git.mirrors.martin98.com/https://github.com/gulrak/filesystem
synced 2025-07-20 20:04:26 +08:00
Merge remote-tracking branch 'origin/master' into development-v1.1
# Conflicts: # .travis.yml # README.md # examples/du.cpp # include/ghc/filesystem.hpp # test/filesystem_test.cpp
This commit is contained in:
commit
3b5c3d4317
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.7.2)
|
||||||
project(ghcfilesystem)
|
project(ghcfilesystem)
|
||||||
|
|
||||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||||
@ -32,3 +32,19 @@ if(NOT hasParent)
|
|||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
set(PACKAGECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||||
|
|
||||||
|
configure_package_config_file(cmake/config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||||
|
INSTALL_DESTINATION ${PACKAGECONFIG_INSTALL_DIR}
|
||||||
|
PATH_VARS INCLUDE_INSTALL_DIR)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||||
|
DESTINATION ${PACKAGECONFIG_INSTALL_DIR})
|
||||||
|
44
README.md
44
README.md
@ -1,7 +1,7 @@
|
|||||||

|

|
||||||
[](https://travis-ci.org/gulrak/filesystem)
|
[](https://travis-ci.org/gulrak/filesystem)
|
||||||
[](https://ci.appveyor.com/project/gulrak/filesystem)
|
[](https://ci.appveyor.com/project/gulrak/filesystem)
|
||||||

|
[](https://github.com/gulrak/filesystem/tree/v1.1.4)
|
||||||
|
|
||||||
# Filesystem
|
# Filesystem
|
||||||
|
|
||||||
@ -97,6 +97,11 @@ in the standard, and there might be issues in these implementations too.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Downloads
|
||||||
|
|
||||||
|
The latest release version is [v1.1.4](https://github.com/gulrak/filesystem/tree/v1.1.4) and
|
||||||
|
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.1.4).
|
||||||
|
|
||||||
### Using it as Single-File-Header
|
### Using it as Single-File-Header
|
||||||
|
|
||||||
As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
|
As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
|
||||||
@ -291,18 +296,20 @@ between this and the standard C++17 API.
|
|||||||
### LWG Defects
|
### LWG Defects
|
||||||
|
|
||||||
This implementation has switchable behavior for the LWG defects
|
This implementation has switchable behavior for the LWG defects
|
||||||
|
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
|
||||||
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
|
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
|
||||||
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
|
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
|
||||||
The currently selected behavior is following
|
The currently selected behavior is following
|
||||||
|
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
|
||||||
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
|
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
|
||||||
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
|
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
|
||||||
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
|
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
|
||||||
where a regular file of the same name prohibits the creation of a directory and forces
|
where a regular file of the same name prohibits the creation of a directory and forces
|
||||||
the user of those functions to double-check via `fs::is_directory` if it really worked.
|
the user of those functions to double-check via `fs::is_directory` if it really worked.
|
||||||
|
The more intuitive approach to directory creation of treating a file with that name as an
|
||||||
Update: The more intuitive approach to directory creation of treating a file with that name as an
|
|
||||||
error is also advocated by the newer paper
|
error is also advocated by the newer paper
|
||||||
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf)
|
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison
|
||||||
|
P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
|
||||||
and GCC by now switched to following its proposal
|
and GCC by now switched to following its proposal
|
||||||
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
|
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
|
||||||
|
|
||||||
@ -438,6 +445,35 @@ to the expected behavior.
|
|||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
|
### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4)
|
||||||
|
|
||||||
|
* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
|
||||||
|
error in old unified `readdir/readdir_r` code of `fs::directory_iterator`;
|
||||||
|
as `readdir_r` is now depricated, I decided to drop it and the resulting
|
||||||
|
code is much easier, shorter and due to more refactoring faster
|
||||||
|
* Fix for crashing unit tests against MSVC C++17 std::filesystem
|
||||||
|
* Travis-CI now additionally test with Xcode 10.2 on macOS
|
||||||
|
* Some minor refactorings
|
||||||
|
|
||||||
|
### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2)
|
||||||
|
|
||||||
|
* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)),
|
||||||
|
`fs::path::lexically_normal()` had some issues with `".."`-sequences.
|
||||||
|
* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
|
||||||
|
`fs::recursive_directory_iterator` could run into endless loops,
|
||||||
|
the methods depth() and pop() had issues and the copy behaviour and
|
||||||
|
`input_iterator_tag` conformance was broken, added tests
|
||||||
|
* Restructured some CMake code into a macro to ease the support for
|
||||||
|
C++17 std::filesystem builds of tests and examples for interoperability
|
||||||
|
checks.
|
||||||
|
* Some fixes on Windows tests to ease interoperability test runs.
|
||||||
|
* Reduced noise on `fs::weakly_canonical()` tests against `std::fs`
|
||||||
|
* Added simple `du` example showing the `recursive_directory_iterator`
|
||||||
|
used to add the sizes of files in a directory tree.
|
||||||
|
* Added error checking in `fs::file_time_type` test helpers
|
||||||
|
* `fs::copy()` now conforms LWG #2682, disallowing the use of
|
||||||
|
`copy_option::create_symlinks' to be used on directories
|
||||||
|
|
||||||
### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
|
### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
|
||||||
|
|
||||||
* Restructuring of the project directory. The header files are now using
|
* Restructuring of the project directory. The header files are now using
|
||||||
|
5
cmake/config.cmake.in
Normal file
5
cmake/config.cmake.in
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||||
|
|
||||||
|
check_required_components(ghcfilesystem)
|
@ -29,11 +29,22 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t totalSize = 0;
|
uint64_t totalSize = 0;
|
||||||
|
int totalDirs = 0;
|
||||||
|
int totalFiles = 0;
|
||||||
|
int maxDepth = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for(auto de : fs::recursive_directory_iterator(dir)) {
|
auto rdi = fs::recursive_directory_iterator(dir);
|
||||||
|
for(auto de : rdi) {
|
||||||
|
if(rdi.depth() > maxDepth) {
|
||||||
|
maxDepth = rdi.depth();
|
||||||
|
}
|
||||||
if(de.is_regular_file()) {
|
if(de.is_regular_file()) {
|
||||||
totalSize += de.file_size();
|
totalSize += de.file_size();
|
||||||
|
++totalFiles;
|
||||||
|
}
|
||||||
|
else if(de.is_directory()) {
|
||||||
|
++totalDirs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +52,6 @@ int main(int argc, char* argv[])
|
|||||||
std::cerr << "Error: " << fe.what() << std::endl;
|
std::cerr << "Error: " << fe.what() << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
std::cout << totalSize << std::endl;
|
std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
#include <stack>
|
#include <stack>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -143,13 +144,23 @@
|
|||||||
#include <system_error>
|
#include <system_error>
|
||||||
#endif // GHC_EXPAND_IMPL
|
#endif // GHC_EXPAND_IMPL
|
||||||
|
|
||||||
// configure LWG conformance (see README.md)
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
|
||||||
|
// configure LWG conformance ()
|
||||||
#define LWG_2682_BEHAVIOUR
|
#define LWG_2682_BEHAVIOUR
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
|
||||||
|
// file with that name, it is superceded by P1164R1, so only activate if really needed
|
||||||
// #define LWG_2935_BEHAVIOUR
|
// #define LWG_2935_BEHAVIOUR
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
|
||||||
#define LWG_2937_BEHAVIOUR
|
#define LWG_2937_BEHAVIOUR
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
|
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
|
||||||
#define GHC_FILESYSTEM_VERSION 10103L
|
#define GHC_FILESYSTEM_VERSION 10105L
|
||||||
|
|
||||||
namespace ghc {
|
namespace ghc {
|
||||||
namespace filesystem {
|
namespace filesystem {
|
||||||
@ -332,6 +343,8 @@ public:
|
|||||||
iterator end() const;
|
iterator end() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class directory_iterator;
|
||||||
|
void append_name(const char* name);
|
||||||
static constexpr value_type generic_separator = '/';
|
static constexpr value_type generic_separator = '/';
|
||||||
template <typename InputIterator>
|
template <typename InputIterator>
|
||||||
class input_iterator_range
|
class input_iterator_range
|
||||||
@ -727,13 +740,14 @@ public:
|
|||||||
void swap(recursive_directory_iterator& rhs);
|
void swap(recursive_directory_iterator& rhs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct recursive_directory_iterator_impl {
|
struct recursive_directory_iterator_impl
|
||||||
|
{
|
||||||
directory_options _options;
|
directory_options _options;
|
||||||
bool _recursion_pending;
|
bool _recursion_pending;
|
||||||
std::stack<directory_iterator> _dir_iter_stack;
|
std::stack<directory_iterator> _dir_iter_stack;
|
||||||
recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
|
recursive_directory_iterator_impl(directory_options options, bool recursion_pending)
|
||||||
: _options(options)
|
: _options(options)
|
||||||
, _recursion_pending(recursion_pending)
|
, _recursion_pending(recursion_pending)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1042,7 +1056,11 @@ GHC_INLINE std::error_code make_error_code(portable_error err)
|
|||||||
case portable_error::invalid_argument:
|
case portable_error::invalid_argument:
|
||||||
return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());
|
return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());
|
||||||
case portable_error::is_a_directory:
|
case portable_error::is_a_directory:
|
||||||
|
#ifdef ERROR_DIRECTORY_NOT_SUPPORTED
|
||||||
return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());
|
return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());
|
||||||
|
#else
|
||||||
|
return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
switch (err) {
|
switch (err) {
|
||||||
@ -1198,7 +1216,7 @@ inline StringType fromUtf8(const std::string& utf8String, const typename StringT
|
|||||||
unsigned utf8_state = S_STRT;
|
unsigned utf8_state = S_STRT;
|
||||||
std::uint32_t codepoint = 0;
|
std::uint32_t codepoint = 0;
|
||||||
while (iter < utf8String.end()) {
|
while (iter < utf8String.end()) {
|
||||||
if (!(utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint))) {
|
if ((utf8_state = consumeUtf8Fragment(utf8_state, (uint8_t)*iter++, codepoint)) == S_STRT) {
|
||||||
if (sizeof(typename StringType::value_type) == 4) {
|
if (sizeof(typename StringType::value_type) == 4) {
|
||||||
result += codepoint;
|
result += codepoint;
|
||||||
}
|
}
|
||||||
@ -1899,7 +1917,8 @@ inline path& path::assign(const Source& source)
|
|||||||
template <>
|
template <>
|
||||||
inline path& path::assign<path>(const path& source)
|
inline path& path::assign<path>(const path& source)
|
||||||
{
|
{
|
||||||
return assign(source._path);
|
_path = source._path;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
@ -1949,6 +1968,19 @@ GHC_INLINE path& path::operator/=(const path& p)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GHC_INLINE void path::append_name(const char* name)
|
||||||
|
{
|
||||||
|
if (_path.empty()) {
|
||||||
|
this->operator/=(path(name));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (_path.back() != path::generic_separator) {
|
||||||
|
_path.push_back(path::generic_separator);
|
||||||
|
}
|
||||||
|
_path += name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // GHC_EXPAND_IMPL
|
#endif // GHC_EXPAND_IMPL
|
||||||
|
|
||||||
template <class Source>
|
template <class Source>
|
||||||
@ -2401,7 +2433,7 @@ GHC_INLINE path path::lexically_normal() const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (*(--dest.end()) != "..") {
|
else if (*(--dest.end()) != "..") {
|
||||||
if(dest._path.back() == generic_separator) {
|
if (dest._path.back() == generic_separator) {
|
||||||
dest._path.pop_back();
|
dest._path.pop_back();
|
||||||
}
|
}
|
||||||
dest.remove_filename();
|
dest.remove_filename();
|
||||||
@ -2988,7 +3020,7 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef LWG_2682_BEHAVIOUR
|
#ifdef LWG_2682_BEHAVIOUR
|
||||||
else if(is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) {
|
else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) {
|
||||||
ec = detail::make_error_code(detail::portable_error::is_a_directory);
|
ec = detail::make_error_code(detail::portable_error::is_a_directory);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -4527,7 +4559,8 @@ public:
|
|||||||
if (_dirHandle != INVALID_HANDLE_VALUE) {
|
if (_dirHandle != INVALID_HANDLE_VALUE) {
|
||||||
do {
|
do {
|
||||||
if (FindNextFileW(_dirHandle, &_findData)) {
|
if (FindNextFileW(_dirHandle, &_findData)) {
|
||||||
_current = _base / std::wstring(_findData.cFileName);
|
_current = _base;
|
||||||
|
_current.append_name(detail::toUtf8(_findData.cFileName).c_str());
|
||||||
copyToDirEntry(ec);
|
copyToDirEntry(ec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -4574,32 +4607,16 @@ public:
|
|||||||
// POSIX implementation
|
// POSIX implementation
|
||||||
class directory_iterator::impl
|
class directory_iterator::impl
|
||||||
{
|
{
|
||||||
size_t directory_entry_buffer_size(DIR* d)
|
|
||||||
{
|
|
||||||
size_t result = std::max(sizeof(::dirent), sizeof(::dirent) - sizeof(::dirent::d_name) + NAME_MAX) + 1;
|
|
||||||
if (d) {
|
|
||||||
long rc = ::fpathconf(dirfd(d), _PC_NAME_MAX);
|
|
||||||
if (rc > long(result)) {
|
|
||||||
result = static_cast<size_t>(rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
impl(const path& path, directory_options options)
|
impl(const path& path, directory_options options)
|
||||||
: _base(path)
|
: _base(path)
|
||||||
, _options(options)
|
, _options(options)
|
||||||
, _dir((path.empty() ? nullptr : ::opendir(path.native().c_str())),
|
, _dir(nullptr)
|
||||||
[](DIR* d) {
|
, _entry(nullptr)
|
||||||
if (d) {
|
|
||||||
::closedir(d);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
, _bufferSize(directory_entry_buffer_size(_dir.get()))
|
|
||||||
, _buffer(new char[_bufferSize])
|
|
||||||
, _entry(reinterpret_cast<::dirent*>(&_buffer[0]))
|
|
||||||
{
|
{
|
||||||
|
if (!path.empty()) {
|
||||||
|
_dir = ::opendir(path.native().c_str());
|
||||||
|
}
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
if (!_dir) {
|
if (!_dir) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
@ -4614,40 +4631,30 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl(const impl& other) = delete;
|
impl(const impl& other) = delete;
|
||||||
int i_readdir_r(DIR* dir, struct dirent* entry, struct dirent** result)
|
~impl()
|
||||||
{
|
{
|
||||||
#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 24))
|
if (_dir) {
|
||||||
errno = 0;
|
::closedir(_dir);
|
||||||
auto de = readdir(dir);
|
|
||||||
if (de) {
|
|
||||||
*entry = *de;
|
|
||||||
*result = entry;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return errno;
|
|
||||||
#else
|
|
||||||
return ::readdir_r(dir, entry, result);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
void increment(std::error_code& ec)
|
void increment(std::error_code& ec)
|
||||||
{
|
{
|
||||||
if (_dir) {
|
if (_dir) {
|
||||||
do {
|
do {
|
||||||
dirent* result = 0;
|
errno = 0;
|
||||||
if (0 == i_readdir_r(_dir.get(), _entry, &result)) {
|
_entry = readdir(_dir);
|
||||||
if (result) {
|
if (_entry) {
|
||||||
_current = _base / path(_entry->d_name);
|
_current = _base;
|
||||||
_dir_entry = directory_entry(_current, ec);
|
_current.append_name(_entry->d_name);
|
||||||
}
|
_dir_entry = directory_entry(_current, ec);
|
||||||
else {
|
|
||||||
_dir.reset();
|
|
||||||
_current = path();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
::closedir(_dir);
|
||||||
|
_dir = nullptr;
|
||||||
_current = path();
|
_current = path();
|
||||||
ec = std::error_code(errno, std::system_category());
|
if (errno) {
|
||||||
|
ec = std::error_code(errno, std::system_category());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
|
} while (std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0);
|
||||||
@ -4656,9 +4663,7 @@ public:
|
|||||||
path _base;
|
path _base;
|
||||||
directory_options _options;
|
directory_options _options;
|
||||||
path _current;
|
path _current;
|
||||||
std::shared_ptr<DIR> _dir;
|
DIR* _dir;
|
||||||
size_t _bufferSize;
|
|
||||||
std::unique_ptr<char[]> _buffer;
|
|
||||||
struct ::dirent* _entry;
|
struct ::dirent* _entry;
|
||||||
directory_entry _dir_entry;
|
directory_entry _dir_entry;
|
||||||
std::error_code _ec;
|
std::error_code _ec;
|
||||||
@ -4883,9 +4888,14 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment
|
|||||||
else {
|
else {
|
||||||
_impl->_dir_iter_stack.top().increment(ec);
|
_impl->_dir_iter_stack.top().increment(ec);
|
||||||
}
|
}
|
||||||
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
|
if (!ec) {
|
||||||
|
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
|
||||||
|
_impl->_dir_iter_stack.pop();
|
||||||
|
_impl->_dir_iter_stack.top().increment(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!_impl->_dir_iter_stack.empty()) {
|
||||||
_impl->_dir_iter_stack.pop();
|
_impl->_dir_iter_stack.pop();
|
||||||
_impl->_dir_iter_stack.top().increment(ec);
|
|
||||||
}
|
}
|
||||||
_impl->_recursion_pending = true;
|
_impl->_recursion_pending = true;
|
||||||
return *this;
|
return *this;
|
||||||
@ -4906,10 +4916,10 @@ GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)
|
|||||||
*this = recursive_directory_iterator();
|
*this = recursive_directory_iterator();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {
|
do {
|
||||||
_impl->_dir_iter_stack.pop();
|
_impl->_dir_iter_stack.pop();
|
||||||
_impl->_dir_iter_stack.top().increment(ec);
|
_impl->_dir_iter_stack.top().increment(ec);
|
||||||
}
|
} while (depth() && _impl->_dir_iter_stack.top() == directory_iterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
||||||
// fs_std.hpp - The dynamic switching header for that includes std::filesystem if detected
|
// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
|
||||||
// or ghc::filesystem if not, and makes the resulting API available in the
|
// or ghc::filesystem if not, and makes the resulting API available in the
|
||||||
// namespace fs.
|
// namespace fs.
|
||||||
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -87,28 +88,34 @@ using fstream = ghc::filesystem::fstream;
|
|||||||
#endif
|
#endif
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// Behaviour Switches (should match the config in ghc/filesystem.hpp):
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories
|
||||||
#define TEST_LWG_2682_BEHAVIOUR
|
#define TEST_LWG_2682_BEHAVIOUR
|
||||||
//#define TEST_LWG_2935_BEHAVIOUR
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
|
||||||
|
// file with that name, it is superceded by P1164R1, so only activate if really needed
|
||||||
|
// #define TEST_LWG_2935_BEHAVIOUR
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
|
||||||
#define TEST_LWG_2937_BEHAVIOUR
|
#define TEST_LWG_2937_BEHAVIOUR
|
||||||
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
template <typename TP>
|
template <typename TP>
|
||||||
std::time_t to_time_t(TP tp)
|
std::time_t to_time_t(TP tp)
|
||||||
{
|
{
|
||||||
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
|
auto sctp = time_point_cast<system_clock::duration>(tp - TP::clock::now() + system_clock::now());
|
||||||
//system_clock::duration dt = duration_cast<system_clock::duration>(tp - TP::clock::now());
|
|
||||||
return system_clock::to_time_t(sctp);
|
return system_clock::to_time_t(sctp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TP>
|
template <typename TP>
|
||||||
TP from_time_t(std::time_t t)
|
TP from_time_t(std::time_t t)
|
||||||
{
|
{
|
||||||
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
auto sctp = system_clock::from_time_t(t);
|
auto sctp = system_clock::from_time_t(t);
|
||||||
auto tp = time_point_cast<TP::duration>(sctp - system_clock::now() + TP::clock::now());
|
auto tp = time_point_cast<TP::duration>(sctp - system_clock::now() + TP::clock::now());
|
||||||
// system_clock::duration dt = duration_cast<system_clock::duration>(tp - TP::clock::now());
|
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +295,7 @@ bool operator!=(TestAllocator<T> const& x, TestAllocator<U> const& y) noexcept
|
|||||||
return !(x == y);
|
return !(x == y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Temporary Directory", "[temp dir]")
|
TEST_CASE("Temporary Directory", "[fs.test.tempdir]")
|
||||||
{
|
{
|
||||||
fs::path tempPath;
|
fs::path tempPath;
|
||||||
{
|
{
|
||||||
@ -300,6 +307,21 @@ TEST_CASE("Temporary Directory", "[temp dir]")
|
|||||||
REQUIRE(!fs::exists(tempPath));
|
REQUIRE(!fs::exists(tempPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef GHC_FILESYSTEM_VERSION
|
||||||
|
TEST_CASE("fs::detail::fromUf88", "[filesystem][fs.detail.utf8]")
|
||||||
|
{
|
||||||
|
CHECK(fs::detail::fromUtf8<std::wstring>("foobar").length() == 6);
|
||||||
|
CHECK(fs::detail::fromUtf8<std::wstring>("foobar") == L"foobar");
|
||||||
|
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar").length() == 6);
|
||||||
|
CHECK(fs::detail::fromUtf8<std::wstring>(u8"föobar") == L"föobar");
|
||||||
|
|
||||||
|
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")).length() == 6);
|
||||||
|
CHECK(fs::detail::toUtf8(std::wstring(L"foobar")) == "foobar");
|
||||||
|
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")).length() == 7);
|
||||||
|
CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef GHC_OS_WINDOWS
|
#ifndef GHC_OS_WINDOWS
|
||||||
TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
|
TEST_CASE("30.10.8.1 path(\"//host\").has_root_name()", "[filesystem][path][fs.path.generic]")
|
||||||
{
|
{
|
||||||
@ -1228,29 +1250,73 @@ TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive
|
|||||||
fs::recursive_directory_iterator rd5;
|
fs::recursive_directory_iterator rd5;
|
||||||
rd5 = rd4;
|
rd5 = rd4;
|
||||||
}
|
}
|
||||||
/*
|
{
|
||||||
if(1) {
|
TemporaryDirectory t(TempOpt::change_path);
|
||||||
fs::path d = "..";
|
generateFile("a");
|
||||||
int maxDepth = 2;
|
fs::create_directory("d1");
|
||||||
fs::recursive_directory_iterator dit(d);
|
fs::create_directory("d1/d2");
|
||||||
std::cout << d << std::endl;
|
generateFile("d1/b");
|
||||||
for(auto & f : dit) {
|
generateFile("d1/c");
|
||||||
#if 1
|
generateFile("d1/d2/d");
|
||||||
if(dit.depth()<=maxDepth) {
|
generateFile("e");
|
||||||
std::cout << dit.depth() << ": " << f.path() << std::endl;
|
auto iter = fs::recursive_directory_iterator(".");
|
||||||
|
std::multimap<std::string, int> result;
|
||||||
|
while(iter != fs::recursive_directory_iterator()) {
|
||||||
|
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
std::stringstream os;
|
||||||
|
for(auto p : result) {
|
||||||
|
os << "[" << p.first << "," << p.second << "],";
|
||||||
|
}
|
||||||
|
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
TemporaryDirectory t(TempOpt::change_path);
|
||||||
|
generateFile("a");
|
||||||
|
fs::create_directory("d1");
|
||||||
|
fs::create_directory("d1/d2");
|
||||||
|
generateFile("d1/d2/b");
|
||||||
|
generateFile("e");
|
||||||
|
auto iter = fs::recursive_directory_iterator(".");
|
||||||
|
std::multimap<std::string, int> result;
|
||||||
|
while(iter != fs::recursive_directory_iterator()) {
|
||||||
|
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
|
||||||
|
if(iter->path() == "./d1/d2") {
|
||||||
|
iter.disable_recursion_pending();
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
std::stringstream os;
|
||||||
|
for(auto p : result) {
|
||||||
|
os << "[" << p.first << "," << p.second << "],";
|
||||||
|
}
|
||||||
|
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
TemporaryDirectory t(TempOpt::change_path);
|
||||||
|
generateFile("a");
|
||||||
|
fs::create_directory("d1");
|
||||||
|
fs::create_directory("d1/d2");
|
||||||
|
generateFile("d1/d2/b");
|
||||||
|
generateFile("e");
|
||||||
|
auto iter = fs::recursive_directory_iterator(".");
|
||||||
|
std::multimap<std::string, int> result;
|
||||||
|
while(iter != fs::recursive_directory_iterator()) {
|
||||||
|
result.insert(std::make_pair(iter->path().generic_string(), iter.depth()));
|
||||||
|
if(iter->path() == "./d1/d2") {
|
||||||
|
iter.pop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dit.pop();
|
++iter;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
std::cout << dit.depth() << ": " << f.path() << std::endl;
|
|
||||||
if(dit.depth()>maxDepth) {
|
|
||||||
dit.disable_recursion_pending();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
std::stringstream os;
|
||||||
|
for(auto p : result) {
|
||||||
|
os << "[" << p.first << "," << p.second << "],";
|
||||||
|
}
|
||||||
|
CHECK(os.str() == "[./a,0],[./d1,0],[./d1/d2,1],[./e,0],");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]")
|
TEST_CASE("30.10.15.1 absolute", "[filesystem][operations][fs.op.absolute]")
|
||||||
@ -1447,7 +1513,7 @@ TEST_CASE("30.10.15.6 create_directories", "[filesystem][operations][fs.op.creat
|
|||||||
CHECK(!fs::is_directory(p));
|
CHECK(!fs::is_directory(p));
|
||||||
CHECK(!fs::create_directories(p, ec));
|
CHECK(!fs::create_directories(p, ec));
|
||||||
#else
|
#else
|
||||||
INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)");
|
INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
|
||||||
p = t.path() / "testfile";
|
p = t.path() / "testfile";
|
||||||
generateFile(p);
|
generateFile(p);
|
||||||
CHECK(fs::is_regular_file(p));
|
CHECK(fs::is_regular_file(p));
|
||||||
@ -1491,7 +1557,7 @@ TEST_CASE("30.10.15.7 create_directory", "[filesystem][operations][fs.op.create_
|
|||||||
CHECK(!fs::is_directory(p));
|
CHECK(!fs::is_directory(p));
|
||||||
CHECK(!fs::create_directories(p, ec));
|
CHECK(!fs::create_directories(p, ec));
|
||||||
#else
|
#else
|
||||||
INFO("This test expects conformance predating LWG #2935 result. (As suggested by WG21 P1164R0, implemented by GCC with issue #86910.)");
|
INFO("This test expects conformance with P1164R1. (implemented by GCC with issue #86910.)");
|
||||||
p = t.path() / "testfile";
|
p = t.path() / "testfile";
|
||||||
generateFile(p);
|
generateFile(p);
|
||||||
CHECK(fs::is_regular_file(p));
|
CHECK(fs::is_regular_file(p));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user