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
@@ -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. +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][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
fromp
and default-constructsm_status
andm_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
fromp
and callsrefresh()
orrefresh(ec)
, respectively.Postcondition:
+path() == p
if no error occurs, otherwisepath().empty() == true
.
directory_entry(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only+
+-v3: Postcondition:
Expression @@ -2636,11 +2678,20 @@ systems that provide status as a by-product of directory iteration.
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
tom_path
andfile_status()
tom_status
andm_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
tom_path
and callsrefresh()
orrefresh(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:
Expression @@ -2660,27 +2711,25 @@ systems that provide status as a by-product of directory iteration.
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:
--
+- -Expression -Value -- -- path()
- path().branch() / s
- -- status()
- st
- -- symlink_status()
- symlink_st
Effects:
+v3: Calls
+m_path.replace_filename(p)
and assignsfile_status()
tom_status
andm_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 thenrefresh()
orrefresh(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 assignsst
tom_status
andsymlink_st
+ tom_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]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)
, callsrefresh()
orrefresh(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)
, callsrefresh()
orrefresh(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()
orstatus(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()
orsymlink_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())
orexists(status(ec))
, respectively.
bool is_regular_file() const; +bool is_regular_file(system::error_code& ec) const;+
++Effects: Equivalent to
+is_regular_file(status())
oris_regular_file(status(ec))
, respectively.
bool is_directory() const; +bool is_directory(system::error_code& ec) const;+
++Effects: Equivalent to
+is_directory(status())
oris_directory(status(ec))
, respectively.
bool is_symlink() const; +bool is_symlink(system::error_code& ec) const;+
++Effects: Equivalent to
+is_symlink(symlink_status())
oris_symlink(symlink_status(ec))
, respectively.
bool is_other() const; +bool is_other(system::error_code& ec) const;+
+Effects: Equivalent to
is_other(status())
oris_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
+
- Added
+directory_entry::refresh
method that updates internal cached file statuses for the directory entry identified by path.- v4:
+directory_entry
constructors and modifiers that initialize or modify the path now automatically callrefresh
. This may result in errors that were not indicated before and in v3, if querying the filesystem for file statuses fails (e.g. if the file does not exist). This new behavior is similar to std::filesystem.- v4:
+directory_entry
constructors and methods takingfile_status
parameters are removed. Users are recommended to remove these arguments and rely ondirectory_entry
callingrefresh
internally.- Added
+directory_entry
member methods for checking the file type of the file, similar to std::filesystem.recursive_directory_iterator
is now more likely to reuse information about the file type that is obtained during filesystem iteration. This may improve performance. (#288)- File streams defined in
boost/filesystem/fstream.hpp
are now movable, if the standard library file streams are. (#280)- Generic
path
comparison operators are now more restricted to avoid potential ambiguities when user's code contains ausing namespace boost::filesystem;
directive. (#285)- Fixed potential overload resolution ambiguity in users' code, where
diff --git a/doc/v4.html b/doc/v4.html index 4bd627a..41dfa83 100644 --- a/doc/v4.html +++ b/doc/v4.html @@ -54,10 +54,13 @@ It removes the features that were deprecated in Vepath
constructors from iterators could interfere with function overloads taking astd::initializer_list
argument. (#287)path
appends consider root name and root directory of the appended path. If the appended path is absolute, or root name is present and differs from the source path, the resulting path is equivalent to the appended path. If root directory is present, the result is the root directory and relative path rebased on top of the root name of the source path. Otherwise, the behavior is similar to v3. This behavior is similar to C++17 std::filesystem.path
no longer supports construction, assignment or appending from containers of characters. Use string types or iterators as the source for these opereations instead.- +
path::remove_filename
preserves the trailing directory separator, so thatpath::has_filename
returnsfalse
after a successful call topath::remove_filename
.- +
directory_entry
constructors and modifiers that initialize or modify path of the directory entry automatically calldirectory_entry::refresh
instead of clearing cached file statuses. This means that the file identified by the new path needs to be accessible in the filesystem at the point of the call.directory_entry
constructors and modifiers that acceptfile_status
arguments to initialize cached file statuses are removed. The amount of cached data + is an implementation detail ofdirectory_entry
, and in the future it may not be limited to just file statuses. Users should rely on automatic refreshes of the cached data.
-© 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();