diff --git a/doc/reference.html b/doc/reference.html index f971467..9fed19f 100644 --- a/doc/reference.html +++ b/doc/reference.html @@ -2543,23 +2543,48 @@ and permissions of a file.

// constructors and destructor directory_entry(); directory_entry(const directory_entry&); - explicit directory_entry(const path& p, file_status st=file_status(), + explicit directory_entry(const path& p); + directory_entry(const path& p, system::error_code& ec); // v4-only + directory_entry(const path& p, file_status st, // v3-only file_status symlink_st=file_status()); ~directory_entry(); // modifiers directory_entry& operator=(const directory_entry&); - void assign(const path& p, file_status st=file_status(), + void assign(const path& p); + void assign(const path& p, system::error_code& ec); // v4-only + void assign(const path& p, file_status st, // v3-only file_status symlink_st=file_status()); - void replace_filename(const path& p, file_status st=file_status(), + void replace_filename(const path& p); + void replace_filename(const path& p, system::error_code& ec); // v4-only + void replace_filename(const path& p, file_status st, // v3-only file_status symlink_st=file_status()); + void refresh(); + void refresh(system::error_code& ec); + // observers const path& path() const; + file_status status() const; file_status status(system::error_code& ec) const; file_status symlink_status() const; file_status symlink_status(system::error_code& ec) const; + file_type file_type() const; + file_type file_type(system::error_code& ec) const; + file_type symlink_file_type() const; + file_type symlink_file_type(system::error_code& ec) const; + + bool exists() const; + bool exists(system::error_code& ec) const; + bool is_regular_file() const; + bool is_regular_file(system::error_code& ec) const; + bool is_directory() const; + bool is_directory(system::error_code& ec) const; + bool is_symlink() const; + bool is_symlink(system::error_code& ec) const; + bool is_other() const; + bool is_other(system::error_code& ec) const; bool operator< (const directory_entry& rhs); bool operator==(const directory_entry& rhs); @@ -2577,10 +2602,12 @@ and permissions of a file.

} // namespace filesystem } // namespace boost -

A directory_entry object stores a path object, -a file_status object for non-symbolic link status, and a file_status object for symbolic link status. The file_status objects act as value caches.

+

A directory_entry object stores a path object, +as well as some amount of cached information about the file identified by the path. +Currently, the cached information includes a file_status object for non-symbolic +link status and a file_status object for symbolic link status.

-

[Note: Because status()on a pathname may be a relatively expensive operation, +

[Note: Because status() on a pathname may be a relatively expensive operation, some operating systems provide status information as a byproduct of directory iteration. Caching such status information can result is significant time savings. Cached and non-cached results may differ in the presence of file system races. —end note]

@@ -2589,8 +2616,14 @@ a directory with 15,047 entries was six seconds for non-cached status queries versus one second for cached status queries. Windows XP, 3.0 GHz processor, with a moderately fast hard-drive. Similar speedups are expected on Linux and BSD-derived systems that provide status as a by-product of directory iteration.

+

[Note: The exact set of cached information may vary from one Boost.Filesystem version +to another, and also between different operating systems and underlying file systems. Users' code +must not rely on whether a certain piece of information is cached or not. This means that calling +most observers and modifiers of directory_entry may or may not result in a filesystem +query that may potentially fail. Information caching is exclusively a performance feature aimed +at reducing the amount of such queries. —end note]

-

directory_entry constructors +

directory_entry constructors [directory_entry.cons]

directory_entry();
@@ -2614,9 +2647,18 @@ systems that provide status as a by-product of directory iteration.
-
explicit directory_entry(const path& p, file_status st=file_status(), file_status symlink_st=file_status());
+
explicit directory_entry(const path& p);
+directory_entry(const path& p, system::error_code& ec); // v4-only
-

Postcondition:

+

Effects:

+

v3: Initializes m_path from p and default-constructs m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Initializes m_path from p and calls refresh() or refresh(ec), respectively.

+

Postcondition: path() == p if no error occurs, otherwise path().empty() == true.

+
+
directory_entry(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

v3: Postcondition:

@@ -2636,11 +2678,20 @@ systems that provide status as a by-product of directory iteration.
Expression
-

directory_entry modifiers +

directory_entry modifiers [directory_entry.mods]

-
void assign(const path& p, file_status st=file_status(), file_status symlink_st=file_status());
+
void assign(const path& p);
+void assign(const path& p, system::error_code& ec); // v4-only
-

Postcondition:

+

Effects:

+

v3: Assigns p to m_path and file_status() to m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Assigns p to m_path and calls refresh() or refresh(ec), respectively. If an error + occurs, the value of the cached data is unspecified.

+
+
void assign(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

v3: Postcondition:

@@ -2660,27 +2711,25 @@ systems that provide status as a by-product of directory iteration.
Expression
-
void replace_filename(const path& p, file_status st=file_status(), file_status symlink_st=file_status());
+
void replace_filename(const path& p);
+void replace_filename(const path& p, system::error_code& ec); // v4-only
-

Postcondition:

- - - - - - - - - - - - - - - - - -
ExpressionValue
path()path().branch() / s
status()st
symlink_status()symlink_st
+

Effects:

+

v3: Calls m_path.replace_filename(p) and assigns file_status() to m_status and m_symlink_status.

+

[Note: The cached file statuses will be updated when queried by the caller or by an explicit call to refresh. —end note]

+

v4: Calls m_path.replace_filename(p) and then refresh() or refresh(ec), respectively. If an error + occurs, the value of the cached data is unspecified.

+
+
void replace_filename(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only
+
+

Effects: v3: Calls m_path.replace_filename(p) and assigns st to m_status and symlink_st + to m_symlink_status.

+
+
void refresh();
+void refresh(system::error_code& ec);
+
+

Effects: Updates any cached data by querying the filesystem about the file identified by m_path. If an error occurs, + the value of the cached data is unspecified.

directory_entry observers [directory_entry.obs]

@@ -2691,35 +2740,55 @@ systems that provide status as a by-product of directory iteration.file_status status() const; file_status status(system::error_code& ec) const;
-

Effects: As if,

-
-
if ( !status_known( m_status ) )
-{
-  if ( status_known(m_symlink_status) && !is_symlink(m_symlink_status) )
-    { m_status = m_symlink_status; }
-  else { m_status = status(m_path[, ec]); }
-}
-
+

Effects: If !status_known(m_status), calls refresh() or refresh(ec), respectively.

Returns: m_status

-

Throws: As specified in Error reporting.

-
file_status  symlink_status() const;
 file_status  symlink_status(system::error_code& ec) const;
-

- Effects: As if,

-
-
if ( !status_known( m_symlink_status ) )
-{
-  m_symlink_status = symlink_status(m_path[, ec]);
-}
-
+

Effects: If !status_known(m_symlink_status), calls refresh() or refresh(ec), respectively.

Returns: m_symlink_status

-

Throws: As specified in Error reporting.

- +
+
file_type file_type() const;
+file_type file_type(system::error_code& ec) const;
+
+

Effects: Equivalent to status().type() or status(ec).type(), respectively.

+

[Note: The implementation may be more efficient than calling status, if the information + about the file type is cached, but permissions are not. —end note]

+
+
file_type symlink_file_type() const;
+file_type symlink_file_type(system::error_code& ec) const;
+
+

Effects: Equivalent to symlink_status().type() or symlink_status(ec).type(), respectively.

+

[Note: The implementation may be more efficient than calling symlink_status, if the information + about the file type is cached, but permissions are not. —end note]

+
+
bool exists() const;
+bool exists(system::error_code& ec) const;
+
+

Effects: Equivalent to exists(status()) or exists(status(ec)), respectively.

+
+
bool is_regular_file() const;
+bool is_regular_file(system::error_code& ec) const;
+
+

Effects: Equivalent to is_regular_file(status()) or is_regular_file(status(ec)), respectively.

+
+
bool is_directory() const;
+bool is_directory(system::error_code& ec) const;
+
+

Effects: Equivalent to is_directory(status()) or is_directory(status(ec)), respectively.

+
+
bool is_symlink() const;
+bool is_symlink(system::error_code& ec) const;
+
+

Effects: Equivalent to is_symlink(symlink_status()) or is_symlink(symlink_status(ec)), respectively.

+
+
bool is_other() const;
+bool is_other(system::error_code& ec) const;
+
+

Effects: Equivalent to is_other(status()) or is_other(status(ec)), respectively.

bool operator==(const directory_entry& rhs);
diff --git a/doc/release_history.html b/doc/release_history.html index d85f457..734fc8e 100644 --- a/doc/release_history.html +++ b/doc/release_history.html @@ -41,6 +41,11 @@

1.83.0


-

© Copyright Andrey Semashev, 2021-2022

+

© Copyright Andrey Semashev, 2021-2023

Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt

diff --git a/include/boost/filesystem/directory.hpp b/include/boost/filesystem/directory.hpp index 91f6ca7..6687f2a 100644 --- a/include/boost/filesystem/directory.hpp +++ b/include/boost/filesystem/directory.hpp @@ -41,6 +41,17 @@ namespace boost { namespace filesystem { +class directory_iterator; + +namespace detail { + +struct directory_iterator_params; + +BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec); +BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); + +} // namespace detail + //--------------------------------------------------------------------------------------// // // // directory_entry // @@ -53,20 +64,30 @@ namespace filesystem { class directory_entry { + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, detail::directory_iterator_params* params, system::error_code* ec); + friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec); + public: typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry directory_entry() BOOST_NOEXCEPT {} - explicit directory_entry(boost::filesystem::path const& p) : - m_path(p), m_status(file_status()), m_symlink_status(file_status()) - { - } + explicit directory_entry(boost::filesystem::path const& p); +#if BOOST_FILESYSTEM_VERSION >= 4 + directory_entry(boost::filesystem::path const& p, system::error_code& ec) : + m_path(p) + { + refresh_impl(&ec); + if (ec) + m_path.clear(); + } +#else directory_entry(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) : m_path(p), m_status(st), m_symlink_status(symlink_st) { } +#endif directory_entry(directory_entry const& rhs) : m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status) @@ -101,7 +122,188 @@ public: return *this; } - void assign(boost::filesystem::path&& p, file_status st = file_status(), file_status symlink_st = file_status()) + void assign(boost::filesystem::path&& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path&& p, system::error_code& ec) + { + m_path = static_cast< boost::filesystem::path&& >(p); + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path&& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(static_cast< boost::filesystem::path&& >(p), st, symlink_st); + } +#endif +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + void assign(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void assign(boost::filesystem::path const& p, system::error_code& ec) + { + m_path = p; + refresh_impl(&ec); + } +#else + void assign(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + assign_with_status(p, st, symlink_st); + } +#endif + + void replace_filename(boost::filesystem::path const& p); + +#if BOOST_FILESYSTEM_VERSION >= 4 + void replace_filename(boost::filesystem::path const& p, system::error_code& ec) + { + m_path.replace_filename(p); + refresh_impl(&ec); + } +#else + void replace_filename(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) + { + replace_filename_with_status(p, st, symlink_st); + } + + BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead") + void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st) + { + replace_filename_with_status(p, st, symlink_st); + } +#endif + + boost::filesystem::path const& path() const BOOST_NOEXCEPT { return m_path; } + operator boost::filesystem::path const&() const BOOST_NOEXCEPT { return m_path; } + + void refresh() { refresh_impl(); } + void refresh(system::error_code& ec) BOOST_NOEXCEPT { refresh_impl(&ec); } + + file_status status() const + { + if (!filesystem::status_known(m_status)) + refresh_impl(); + return m_status; + } + + file_status status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_status)) + refresh_impl(&ec); + return m_status; + } + + file_status symlink_status() const + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(); + return m_symlink_status; + } + + file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::status_known(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status; + } + + filesystem::file_type file_type() const + { + if (!filesystem::type_present(m_status)) + refresh_impl(); + return m_status.type(); + } + + filesystem::file_type file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_status)) + refresh_impl(&ec); + return m_status.type(); + } + + filesystem::file_type symlink_file_type() const + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(); + return m_symlink_status.type(); + } + + filesystem::file_type symlink_file_type(system::error_code& ec) const BOOST_NOEXCEPT + { + if (!filesystem::type_present(m_symlink_status)) + refresh_impl(&ec); + return m_symlink_status.type(); + } + + bool exists() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool exists(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found; + } + + bool is_regular_file() const + { + return this->file_type() == filesystem::regular_file; + } + + bool is_regular_file(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::regular_file; + } + + bool is_directory() const + { + return this->file_type() == filesystem::directory_file; + } + + bool is_directory(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->file_type(ec) == filesystem::directory_file; + } + + bool is_symlink() const + { + return this->symlink_file_type() == filesystem::symlink_file; + } + + bool is_symlink(system::error_code& ec) const BOOST_NOEXCEPT + { + return this->symlink_file_type(ec) == filesystem::symlink_file; + } + + bool is_other() const + { + filesystem::file_type ft = this->file_type(); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool is_other(system::error_code& ec) const BOOST_NOEXCEPT + { + filesystem::file_type ft = this->file_type(ec); + return ft != filesystem::status_error && ft != filesystem::file_not_found && + ft != filesystem::regular_file && ft != filesystem::directory_file; + } + + bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; } + bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; } + bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; } + bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; } + bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; } + bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; } + +private: + BOOST_FILESYSTEM_DECL void refresh_impl(system::error_code* ec = NULL) const; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + void assign_with_status(boost::filesystem::path&& p, file_status st, file_status symlink_st) { m_path = static_cast< boost::filesystem::path&& >(p); m_status = static_cast< file_status&& >(st); @@ -109,7 +311,7 @@ public: } #endif - void assign(boost::filesystem::path const& p, file_status st = file_status(), file_status symlink_st = file_status()) + void assign_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) { m_path = p; #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -121,7 +323,7 @@ public: #endif } - void replace_filename(boost::filesystem::path const& p, file_status st = file_status(), file_status symlink_st = file_status()) + void replace_filename_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st) { m_path.replace_filename(p); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -133,40 +335,58 @@ public: #endif } -#ifndef BOOST_FILESYSTEM_NO_DEPRECATED - BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead") - void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st) - { - replace_filename(p, st, symlink_st); - } -#endif - - boost::filesystem::path const& path() const BOOST_NOEXCEPT - { - return m_path; - } - operator boost::filesystem::path const&() const BOOST_NOEXCEPT { return m_path; } - file_status status() const { return get_status(); } - file_status status(system::error_code& ec) const BOOST_NOEXCEPT { return get_status(&ec); } - file_status symlink_status() const { return get_symlink_status(); } - file_status symlink_status(system::error_code& ec) const BOOST_NOEXCEPT { return get_symlink_status(&ec); } - - bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; } - bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; } - bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; } - bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; } - bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; } - bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; } - -private: - BOOST_FILESYSTEM_DECL file_status get_status(system::error_code* ec = NULL) const; - BOOST_FILESYSTEM_DECL file_status get_symlink_status(system::error_code* ec = NULL) const; - private: boost::filesystem::path m_path; mutable file_status m_status; // stat()-like mutable file_status m_symlink_status; // lstat()-like -}; // directory_entry +}; + +#if !defined(BOOST_FILESYSTEM_SOURCE) + +inline directory_entry::directory_entry(boost::filesystem::path const& p) : + m_path(p) +{ +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#endif +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +inline void directory_entry::assign(boost::filesystem::path&& p) +{ + m_path = static_cast< boost::filesystem::path&& >(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +inline void directory_entry::assign(boost::filesystem::path const& p) +{ + m_path = p; +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +inline void directory_entry::replace_filename(boost::filesystem::path const& p) +{ + m_path.replace_filename(p); +#if BOOST_FILESYSTEM_VERSION >= 4 + refresh_impl(); +#else + m_status = file_status(); + m_symlink_status = file_status(); +#endif +} + +#endif // !defined(BOOST_FILESYSTEM_SOURCE) namespace detail { namespace path_traits { @@ -287,8 +507,6 @@ BOOST_SCOPED_ENUM_DECLARE_END(directory_options) BOOST_BITMASK(BOOST_SCOPED_ENUM_NATIVE(directory_options)) -class directory_iterator; - namespace detail { struct dir_itr_imp : @@ -318,11 +536,6 @@ struct dir_itr_imp : BOOST_FILESYSTEM_DECL static void operator delete(void* p) BOOST_NOEXCEPT; }; -struct directory_iterator_params; - -BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, unsigned int opts, directory_iterator_params* params, system::error_code* ec); -BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec); - } // namespace detail //--------------------------------------------------------------------------------------// diff --git a/src/directory.cpp b/src/directory.cpp index 0f4c184..e32690d 100644 --- a/src/directory.cpp +++ b/src/directory.cpp @@ -87,42 +87,32 @@ namespace filesystem { // // //--------------------------------------------------------------------------------------// -BOOST_FILESYSTEM_DECL -file_status directory_entry::get_status(system::error_code* ec) const +BOOST_FILESYSTEM_DECL void directory_entry::refresh_impl(system::error_code* ec) const { - if (!status_known(m_status)) + system::error_code local_ec; + m_symlink_status = detail::symlink_status(m_path, &local_ec); + + if (!filesystem::is_symlink(m_symlink_status)) { - // optimization: if the symlink status is known, and it isn't a symlink, - // then status and symlink_status are identical so just copy the - // symlink status to the regular status. - if (status_known(m_symlink_status) && !is_symlink(m_symlink_status)) + // Also works if symlink_status fails - set m_status to status_error as well + m_status = m_symlink_status; + + if (BOOST_UNLIKELY(!!local_ec)) { - m_status = m_symlink_status; - if (ec) - ec->clear(); - } - else - { - m_status = detail::status(m_path, ec); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_entry::refresh", m_path, local_ec)); + + *ec = local_ec; + return; } + + if (ec) + ec->clear(); } - else if (ec) + else { - ec->clear(); + m_status = detail::status(m_path, ec); } - - return m_status; -} - -BOOST_FILESYSTEM_DECL -file_status directory_entry::get_symlink_status(system::error_code* ec) const -{ - if (!status_known(m_symlink_status)) - m_symlink_status = detail::symlink_status(m_path, ec); - else if (ec) - ec->clear(); - - return m_symlink_status; } //--------------------------------------------------------------------------------------// @@ -1131,7 +1121,7 @@ void directory_iterator_construct(directory_iterator& it, path const& p, unsigne { path full_path(p); path_algorithms::append_v4(full_path, filename); - imp->dir_entry.assign + imp->dir_entry.assign_with_status ( #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) static_cast< path&& >(full_path), @@ -1200,7 +1190,7 @@ void directory_iterator_increment(directory_iterator& it, system::error_code* ec && (filename_str[1] == static_cast< path::string_type::value_type >('\0') || (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0'))))) { - it.m_imp->dir_entry.replace_filename(filename, file_stat, symlink_file_stat); + it.m_imp->dir_entry.replace_filename_with_status(filename, file_stat, symlink_file_stat); return; } } @@ -1364,14 +1354,14 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: return result; } - file_status symlink_stat; + file_type symlink_ft = status_error; // If we are not recursing into symlinks, we are going to have to know if the // stack top is a symlink, so get symlink_status and verify no error occurred. if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) == 0u || (imp->m_options & static_cast< unsigned int >(directory_options::skip_dangling_symlinks)) != 0u) { - symlink_stat = imp->m_stack.back()->symlink_status(ec); + symlink_ft = imp->m_stack.back()->symlink_file_type(ec); if (ec) return result; } @@ -1384,12 +1374,12 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: // The predicate code has since been rewritten to pass error_code arguments, // per ticket #5653. - if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) != 0u || !fs::is_symlink(symlink_stat)) + if ((imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink)) != 0u || symlink_ft != symlink_file) { - file_status stat = imp->m_stack.back()->status(ec); + file_type ft = imp->m_stack.back()->file_type(ec); if (BOOST_UNLIKELY(!!ec)) { - if (ec == make_error_condition(system::errc::no_such_file_or_directory) && fs::is_symlink(symlink_stat) && + if (ec == make_error_condition(system::errc::no_such_file_or_directory) && symlink_ft == symlink_file && (imp->m_options & static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == static_cast< unsigned int >(directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) { // Skip dangling symlink and continue iteration on the current depth level @@ -1399,7 +1389,7 @@ inline push_directory_result recursive_directory_iterator_push_directory(detail: return result; } - if (!fs::is_directory(stat)) + if (ft != directory_file) return result; if (BOOST_UNLIKELY((imp->m_stack.size() - 1u) >= static_cast< std::size_t >((std::numeric_limits< int >::max)()))) diff --git a/test/deprecated_test.cpp b/test/deprecated_test.cpp index 011fcea..7b11496 100644 --- a/test/deprecated_test.cpp +++ b/test/deprecated_test.cpp @@ -266,7 +266,16 @@ int cpp_main(int /*argc*/, char* /*argv*/[]) //path::default_name_check(fs::no_check); - fs::directory_entry de("foo/bar"); + fs::directory_entry de("foo.bar", fs::file_status(fs::regular_file, fs::owner_all), fs::file_status(fs::directory_file, fs::group_all)); + + BOOST_TEST(de.path() == "foo.bar"); + BOOST_TEST(de.status() == fs::file_status(fs::regular_file, fs::owner_all)); + BOOST_TEST(de.symlink_status() == fs::file_status(fs::directory_file, fs::group_all)); + BOOST_TEST(de < fs::directory_entry("goo.bar", fs::file_status(), fs::file_status())); + BOOST_TEST(de == fs::directory_entry("foo.bar", fs::file_status(), fs::file_status())); + BOOST_TEST(de != fs::directory_entry("goo.bar", fs::file_status(), fs::file_status())); + de.replace_filename("bar.foo", fs::file_status(), fs::file_status()); + BOOST_TEST(de.path() == "bar.foo"); de.replace_leaf("", fs::file_status(), fs::file_status()); diff --git a/test/operations_unit_test.cpp b/test/operations_unit_test.cpp index 1e94e66..e5c3c62 100644 --- a/test/operations_unit_test.cpp +++ b/test/operations_unit_test.cpp @@ -24,11 +24,15 @@ #endif #include // make sure filesystem.hpp works +#include // for BOOST_FILESYSTEM_C_STR #include #include #include #include +#include +#include +#include using namespace boost::filesystem; using namespace boost::system; @@ -41,6 +45,15 @@ using std::string; namespace { bool cleanup = true; +void create_file(const path& ph, const std::string& contents = std::string()) +{ + std::ofstream f(BOOST_FILESYSTEM_C_STR(ph)); + if (!f) + throw filesystem_error("operations_test create_file", ph, error_code(errno, system_category())); + if (!contents.empty()) + f << contents; +} + void check(bool ok, const char* file, int line) { if (ok) @@ -252,20 +265,32 @@ void operations_test() // directory_entry_test ------------------------------------------------------------// -void directory_entry_test() +void directory_entry_test(path const& temp_dir) { cout << "directory_entry test..." << endl; - directory_entry de("foo.bar", file_status(regular_file, owner_all), file_status(directory_file, group_all)); + create_file(temp_dir / "foo.bar"); + create_file(temp_dir / "goo.bar"); + create_directory(temp_dir / "bar.foo"); - CHECK(de.path() == "foo.bar"); - CHECK(de.status() == file_status(regular_file, owner_all)); - CHECK(de.symlink_status() == file_status(directory_file, group_all)); - CHECK(de < directory_entry("goo.bar")); - CHECK(de == directory_entry("foo.bar")); - CHECK(de != directory_entry("goo.bar")); + directory_entry de(temp_dir / "foo.bar"); + + CHECK(de.path() == temp_dir / "foo.bar"); + CHECK(de.status().type() == regular_file); + CHECK(de.symlink_status().type() == regular_file); + CHECK(de.is_regular_file()); + CHECK(de < directory_entry(temp_dir / "goo.bar")); + CHECK(de == directory_entry(temp_dir / "foo.bar")); + CHECK(de != directory_entry(temp_dir / "goo.bar")); de.replace_filename("bar.foo"); - CHECK(de.path() == "bar.foo"); + CHECK(de.path() == temp_dir / "bar.foo"); + CHECK(de.is_directory()); + CHECK(de.status().type() == directory_file); + CHECK(de.symlink_status().type() == directory_file); + + boost::filesystem::remove(temp_dir / "bar.foo"); + boost::filesystem::remove(temp_dir / "goo.bar"); + boost::filesystem::remove(temp_dir / "foo.bar"); } // directory_entry_overload_test ---------------------------------------------------// @@ -354,7 +379,7 @@ int cpp_main(int argc, char* argv[]) directory_iterator_test(); recursive_directory_iterator_test(); operations_test(); - directory_entry_test(); + directory_entry_test(temp_dir); directory_entry_overload_test(); error_handling_test();