Updated library version selection to avoid ODR violations.

The previous strategy of force-inlining methods that are dependent
on the library version is not effective with MSVC in debug mode,
when linking the static library. The compiler does not inline
methods despite the markup, and during linking the static library
with the user's module the linker may or may not pick up user's
definitions of these methods.

When building the library, do not define path methods that depend
on the library version. Instead, explicitly call v4 internal methods
throughout the implementation. This way the compiled library does not
contain v4 versions of these methods, and therefore does not conflict
with user's definitions of these methods.

Fixes https://github.com/boostorg/filesystem/issues/279.
This commit is contained in:
Andrey Semashev 2023-02-06 02:58:53 +03:00
parent 5bebf7805a
commit 7509619c9e
11 changed files with 1162 additions and 937 deletions

View File

@ -264,7 +264,7 @@ jobs:
compiler: clang++-14 compiler: clang++-14
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu" cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,2b-gnu"
cxxflags: -stdlib=libc++ cxxflags: -stdlib=libc++
linkflags: -stdlib=libc++ linkflags: "-stdlib=libc++ -lubsan"
ubsan: 1 ubsan: 1
build_variant: debug build_variant: debug
os: ubuntu-22.04 os: ubuntu-22.04

View File

@ -73,6 +73,31 @@ endif()
add_library(boost_filesystem ${BOOST_FILESYSTEM_SOURCES}) add_library(boost_filesystem ${BOOST_FILESYSTEM_SOURCES})
add_library(Boost::filesystem ALIAS boost_filesystem) add_library(Boost::filesystem ALIAS boost_filesystem)
get_target_property(BOOST_FILESYSTEM_TARGET_TYPE boost_filesystem TYPE)
if(BOOST_FILESYSTEM_TARGET_TYPE STREQUAL "SHARED_LIBRARY")
set(CMAKE_REQUIRED_LIBRARIES "-Wl,--no-undefined")
check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_linkflag_no_undefined.cpp>" BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED)
unset(CMAKE_REQUIRED_LIBRARIES)
if(NOT BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED)
set(CMAKE_REQUIRED_LIBRARIES "-Wl,-undefined,error")
check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_linkflag_no_undefined.cpp>" BOOST_FILESYSTEM_HAS_LINKFLAG_UNDEFINED_ERROR)
unset(CMAKE_REQUIRED_LIBRARIES)
endif()
if(BOOST_FILESYSTEM_HAS_LINKFLAG_NO_UNDEFINED)
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
target_link_options(boost_filesystem PRIVATE "-Wl,--no-undefined")
else()
target_link_libraries(boost_filesystem PRIVATE "-Wl,--no-undefined")
endif()
elseif(BOOST_FILESYSTEM_HAS_LINKFLAG_UNDEFINED_ERROR)
if(NOT CMAKE_VERSION VERSION_LESS 3.13)
target_link_options(boost_filesystem PRIVATE "-Wl,-undefined,error")
else()
target_link_libraries(boost_filesystem PRIVATE "-Wl,-undefined,error")
endif()
endif()
endif()
target_include_directories(boost_filesystem PUBLIC include) target_include_directories(boost_filesystem PUBLIC include)
target_include_directories(boost_filesystem PRIVATE src) target_include_directories(boost_filesystem PRIVATE src)

View File

@ -101,6 +101,27 @@ rule check-cxx20-atomic-ref ( properties * )
return $(result) ; return $(result) ;
} }
# The rule checks if the linker supports requiring no unresolved symbols
rule check-linkflag-no-undefined ( properties * )
{
local result ;
if <link>shared in $(properties)
{
if [ configure.builds ../config//has_linkflag_no_undefined : $(properties) : "has -Wl,--no-undefined" ]
{
result = <linkflags>"-Wl,--no-undefined" ;
}
else if [ configure.builds ../config//has_linkflag_undefined_error : $(properties) : "has -Wl,-undefined,error" ]
{
result = <linkflags>"-Wl,-undefined,error" ;
}
}
#ECHO Result: $(result) ;
return $(result) ;
}
project boost/filesystem project boost/filesystem
: requirements : requirements
<host-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901 <host-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
@ -117,6 +138,8 @@ project boost/filesystem
<conditional>@check-statx <conditional>@check-statx
<conditional>@select-windows-crypto-api <conditional>@select-windows-crypto-api
<conditional>@check-cxx20-atomic-ref <conditional>@check-cxx20-atomic-ref
# Make sure no undefined references are left from the library
<conditional>@check-linkflag-no-undefined
<target-os>windows:<define>_SCL_SECURE_NO_WARNINGS <target-os>windows:<define>_SCL_SECURE_NO_WARNINGS
<target-os>windows:<define>_SCL_SECURE_NO_DEPRECATE <target-os>windows:<define>_SCL_SECURE_NO_DEPRECATE
<target-os>windows:<define>_CRT_SECURE_NO_WARNINGS <target-os>windows:<define>_CRT_SECURE_NO_WARNINGS
@ -131,6 +154,7 @@ project boost/filesystem
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105651 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105651
<toolset>gcc-12:<cxxflags>"-Wno-restrict" <toolset>gcc-12:<cxxflags>"-Wno-restrict"
: source-location ../src : source-location ../src
: usage-requirements # pass these requirement to dependents (i.e. users) : usage-requirements # pass these requirement to dependents (i.e. users)
<link>shared:<define>BOOST_FILESYSTEM_DYN_LINK=1 <link>shared:<define>BOOST_FILESYSTEM_DYN_LINK=1

View File

@ -39,3 +39,8 @@ exe has_bcrypt : has_bcrypt.cpp : <include>../src <library>bcrypt ;
explicit has_bcrypt ; explicit has_bcrypt ;
obj is_windows_ce : is_windows_ce.cpp ; obj is_windows_ce : is_windows_ce.cpp ;
explicit is_windows_ce ; explicit is_windows_ce ;
lib has_linkflag_no_undefined : has_linkflag_no_undefined.cpp : <link>shared <linkflags>"-Wl,--no-undefined" ;
explicit has_linkflag_no_undefined ;
lib has_linkflag_undefined_error : has_linkflag_no_undefined.cpp : <link>shared <linkflags>"-Wl,-undefined,error" ;
explicit has_linkflag_undefined_error ;

View File

@ -0,0 +1,18 @@
// Copyright 2023 Andrey Semashev
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
// See library home page at http://www.boost.org/libs/filesystem
#if defined(_MSC_VER)
// MSVC's link.exe does not support -Wl,... flags, but doesn't fail the linking.
// The linker may be used by different compilers, not only MSVC.
// Luckily, those compilers all pretend to be MSVC.
#error "MSVC and compatible compilers don't support -Wl,... flags"
#endif
int main()
{
return 0;
}

View File

@ -45,6 +45,7 @@
<li><b>v4:</b> <code>path::remove_filename</code> now presesrves the trailing directory separator. (<a href="https://github.com/boostorg/filesystem/issues/271">#271</a>)</li> <li><b>v4:</b> <code>path::remove_filename</code> now presesrves the trailing directory separator. (<a href="https://github.com/boostorg/filesystem/issues/271">#271</a>)</li>
<li>Added <code>path::remove_filename_and_trailing_separators</li>, which removes the filename and directory separators preceding it from the path. This behavior is similar to <code>path::remove_filename</code> in Filesystem <b>v3</b>, but is also usable in <b>v4</b>. <li>Added <code>path::remove_filename_and_trailing_separators</li>, which removes the filename and directory separators preceding it from the path. This behavior is similar to <code>path::remove_filename</code> in Filesystem <b>v3</b>, but is also usable in <b>v4</b>.
<li>Added <code>path::replace_filename</code>, which replaces filename in a path.</li> <li>Added <code>path::replace_filename</code>, which replaces filename in a path.</li>
<li>Updated implementation of the library version selection to avoid ODR violations. (<a href="https://github.com/boostorg/filesystem/issues/279">#279</a>)</li>
</ul> </ul>
<h2>1.81.0</h2> <h2>1.81.0</h2>

View File

@ -43,6 +43,8 @@
namespace boost { namespace boost {
namespace filesystem { namespace filesystem {
class path;
namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants
template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
@ -67,15 +69,83 @@ BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSepa
path_constants< Char, Separator, PreferredSeparator, Dot >::dot; path_constants< Char, Separator, PreferredSeparator, Dot >::dot;
#endif #endif
// A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view. class path_iterator;
struct substring class path_reverse_iterator;
{
std::size_t pos;
std::size_t size;
};
} // namespace path_detail } // namespace path_detail
namespace detail {
struct path_algorithms
{
// A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view.
struct substring
{
std::size_t pos;
std::size_t size;
};
typedef path_traits::path_native_char_type value_type;
typedef std::basic_string< value_type > string_type;
static bool has_filename_v3(path const& p);
static bool has_filename_v4(path const& p);
BOOST_FILESYSTEM_DECL static path filename_v3(path const& p);
static path filename_v4(path const& p);
BOOST_FILESYSTEM_DECL static path stem_v3(path const& p);
BOOST_FILESYSTEM_DECL static path stem_v4(path const& p);
BOOST_FILESYSTEM_DECL static path extension_v3(path const& p);
static path extension_v4(path const& p);
BOOST_FILESYSTEM_DECL static void remove_filename_v3(path& p);
BOOST_FILESYSTEM_DECL static void remove_filename_v4(path& p);
BOOST_FILESYSTEM_DECL static void replace_extension_v3(path& p, path const& new_extension);
BOOST_FILESYSTEM_DECL static void replace_extension_v4(path& p, path const& new_extension);
BOOST_FILESYSTEM_DECL static path lexically_normal_v3(path const& p);
BOOST_FILESYSTEM_DECL static path lexically_normal_v4(path const& p);
BOOST_FILESYSTEM_DECL static int compare_v3(path const& left, path const& right);
BOOST_FILESYSTEM_DECL static int compare_v4(path const& left, path const& right);
BOOST_FILESYSTEM_DECL static void append_v3(path& p, const value_type* b, const value_type* e);
BOOST_FILESYSTEM_DECL static void append_v4(path& p, const value_type* b, const value_type* e);
static void append_v4(path& left, path const& right);
// Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
// Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
BOOST_FILESYSTEM_DECL static string_type::size_type append_separator_if_needed(path& p);
BOOST_FILESYSTEM_DECL static void erase_redundant_separator(path& p, string_type::size_type sep_pos);
BOOST_FILESYSTEM_DECL static string_type::size_type find_root_name_size(path const& p);
BOOST_FILESYSTEM_DECL static string_type::size_type find_root_path_size(path const& p);
BOOST_FILESYSTEM_DECL static substring find_root_directory(path const& p);
BOOST_FILESYSTEM_DECL static substring find_relative_path(path const& p);
BOOST_FILESYSTEM_DECL static string_type::size_type find_parent_path_size(path const& p);
BOOST_FILESYSTEM_DECL static string_type::size_type find_filename_v4_size(path const& p);
BOOST_FILESYSTEM_DECL static string_type::size_type find_extension_v4_size(path const& p);
BOOST_FILESYSTEM_DECL static int lex_compare_v3
(
path_detail::path_iterator first1, path_detail::path_iterator const& last1,
path_detail::path_iterator first2, path_detail::path_iterator const& last2
);
BOOST_FILESYSTEM_DECL static int lex_compare_v4
(
path_detail::path_iterator first1, path_detail::path_iterator const& last1,
path_detail::path_iterator first2, path_detail::path_iterator const& last2
);
BOOST_FILESYSTEM_DECL static void increment_v3(path_detail::path_iterator& it);
BOOST_FILESYSTEM_DECL static void increment_v4(path_detail::path_iterator& it);
BOOST_FILESYSTEM_DECL static void decrement_v3(path_detail::path_iterator& it);
BOOST_FILESYSTEM_DECL static void decrement_v4(path_detail::path_iterator& it);
};
} // namespace detail
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
// // // //
// class path // // class path //
@ -91,12 +161,16 @@ class path :
#endif #endif
> >
{ {
friend class path_detail::path_iterator;
friend class path_detail::path_reverse_iterator;
friend struct detail::path_algorithms;
public: public:
// value_type is the character type used by the operating system API to // value_type is the character type used by the operating system API to
// represent paths. // represent paths.
typedef path_constants_base::value_type value_type; typedef detail::path_algorithms::value_type value_type;
typedef std::basic_string< value_type > string_type; typedef detail::path_algorithms::string_type string_type;
typedef detail::path_traits::codecvt_type codecvt_type; typedef detail::path_traits::codecvt_type codecvt_type;
// ----- character encoding conversions ----- // ----- character encoding conversions -----
@ -245,10 +319,9 @@ private:
}; };
public: public:
class iterator; typedef path_detail::path_iterator iterator;
friend class iterator;
typedef iterator const_iterator; typedef iterator const_iterator;
class reverse_iterator; typedef path_detail::path_reverse_iterator reverse_iterator;
typedef reverse_iterator const_reverse_iterator; typedef reverse_iterator const_reverse_iterator;
public: public:
@ -725,11 +798,7 @@ public:
return append(source); return append(source);
} }
BOOST_FORCEINLINE path& append(path const& p) path& append(path const& p);
{
BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
return *this;
}
template< typename Source > template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c< BOOST_FORCEINLINE typename boost::enable_if_c<
@ -754,11 +823,7 @@ public:
return *this; return *this;
} }
BOOST_FORCEINLINE path& append(path const& p, codecvt_type const&) path& append(path const& p, codecvt_type const&);
{
BOOST_FILESYSTEM_VERSIONED_SYM(append)(p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
return *this;
}
template< typename Source > template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c< BOOST_FORCEINLINE typename boost::enable_if_c<
@ -783,11 +848,7 @@ public:
return *this; return *this;
} }
BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end) path& append(const value_type* begin, const value_type* end);
{
BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end);
return *this;
}
template< typename InputIterator > template< typename InputIterator >
BOOST_FORCEINLINE typename boost::enable_if_c< BOOST_FORCEINLINE typename boost::enable_if_c<
@ -803,11 +864,7 @@ public:
return *this; return *this;
} }
BOOST_FORCEINLINE path& append(const value_type* begin, const value_type* end, codecvt_type const&) path& append(const value_type* begin, const value_type* end, codecvt_type const&);
{
BOOST_FILESYSTEM_VERSIONED_SYM(append)(begin, end);
return *this;
}
template< typename InputIterator > template< typename InputIterator >
BOOST_FORCEINLINE typename boost::enable_if_c< BOOST_FORCEINLINE typename boost::enable_if_c<
@ -835,19 +892,12 @@ public:
#else // BOOST_WINDOWS_API #else // BOOST_WINDOWS_API
BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes BOOST_FILESYSTEM_DECL path& make_preferred(); // change slashes to backslashes
#endif #endif
BOOST_FORCEINLINE path& remove_filename() path& remove_filename();
{
BOOST_FILESYSTEM_VERSIONED_SYM(remove_filename)();
return *this;
}
BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators(); BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators();
BOOST_FILESYSTEM_DECL path& remove_trailing_separator(); BOOST_FILESYSTEM_DECL path& remove_trailing_separator();
BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement); BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement);
BOOST_FORCEINLINE path& replace_extension(path const& new_extension = path()) path& replace_extension(path const& new_extension = path());
{
BOOST_FILESYSTEM_VERSIONED_SYM(replace_extension)(new_extension);
return *this;
}
void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); } void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); }
// ----- observers ----- // ----- observers -----
@ -953,10 +1003,7 @@ public:
// ----- compare ----- // ----- compare -----
BOOST_FORCEINLINE int compare(path const& p) const // generic, lexicographical int compare(path const& p) const; // generic, lexicographical
{
return BOOST_FILESYSTEM_VERSIONED_SYM(compare)(p);
}
template< typename Source > template< typename Source >
BOOST_FORCEINLINE typename boost::enable_if_c< BOOST_FORCEINLINE typename boost::enable_if_c<
@ -1002,42 +1049,42 @@ public:
// ----- decomposition ----- // ----- decomposition -----
path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_root_path_size()); } path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_path_size(*this)); }
// returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths // returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths
path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_root_name_size()); } path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_name_size(*this)); }
// returns 0 or 1 element path // returns 0 or 1 element path
path root_directory() const path root_directory() const
{ {
path_detail::substring root_dir = find_root_directory(); detail::path_algorithms::substring root_dir = detail::path_algorithms::find_root_directory(*this);
const value_type* p = m_pathname.c_str() + root_dir.pos; const value_type* p = m_pathname.c_str() + root_dir.pos;
return path(p, p + root_dir.size); return path(p, p + root_dir.size);
} }
path relative_path() const path relative_path() const
{ {
path_detail::substring rel_path = find_relative_path(); detail::path_algorithms::substring rel_path = detail::path_algorithms::find_relative_path(*this);
const value_type* p = m_pathname.c_str() + rel_path.pos; const value_type* p = m_pathname.c_str() + rel_path.pos;
return path(p, p + rel_path.size); return path(p, p + rel_path.size);
} }
path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + find_parent_path_size()); } path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_parent_path_size(*this)); }
BOOST_FORCEINLINE path filename() const { return BOOST_FILESYSTEM_VERSIONED_SYM(filename)(); } // returns 0 or 1 element path path filename() const; // returns 0 or 1 element path
BOOST_FORCEINLINE path stem() const { return BOOST_FILESYSTEM_VERSIONED_SYM(stem)(); } // returns 0 or 1 element path path stem() const; // returns 0 or 1 element path
BOOST_FORCEINLINE path extension() const { return BOOST_FILESYSTEM_VERSIONED_SYM(extension)(); } // returns 0 or 1 element path path extension() const; // returns 0 or 1 element path
// ----- query ----- // ----- query -----
bool empty() const BOOST_NOEXCEPT { return m_pathname.empty(); } bool empty() const BOOST_NOEXCEPT { return m_pathname.empty(); }
bool filename_is_dot() const; bool filename_is_dot() const;
bool filename_is_dot_dot() const; bool filename_is_dot_dot() const;
bool has_root_path() const { return find_root_path_size() > 0; } bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; }
bool has_root_name() const { return find_root_name_size() > 0; } bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; }
bool has_root_directory() const { return find_root_directory().size > 0; } bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; }
bool has_relative_path() const { return find_relative_path().size > 0; } bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; }
bool has_parent_path() const { return find_parent_path_size() > 0; } bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; }
BOOST_FORCEINLINE bool has_filename() const { return BOOST_FILESYSTEM_VERSIONED_SYM(has_filename)(); } bool has_filename() const;
bool has_stem() const { return !stem().empty(); } bool has_stem() const { return !stem().empty(); }
bool has_extension() const { return !extension().empty(); } bool has_extension() const { return !extension().empty(); }
bool is_relative() const { return !is_absolute(); } bool is_relative() const { return !is_absolute(); }
@ -1053,7 +1100,7 @@ public:
// ----- lexical operations ----- // ----- lexical operations -----
BOOST_FORCEINLINE path lexically_normal() const { return BOOST_FILESYSTEM_VERSIONED_SYM(lexically_normal)(); } path lexically_normal() const;
BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const; BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const;
path lexically_proximate(path const& base) const; path lexically_proximate(path const& base) const;
@ -1110,56 +1157,6 @@ public:
//--------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------//
// class path private members // // class path private members //
//--------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------//
private:
bool has_filename_v3() const { return !m_pathname.empty(); }
bool has_filename_v4() const { return find_filename_v4_size() > 0; }
BOOST_FILESYSTEM_DECL path filename_v3() const;
path filename_v4() const
{
string_type::size_type filename_size = find_filename_v4_size();
string_type::size_type pos = m_pathname.size() - filename_size;
const value_type* p = m_pathname.c_str() + pos;
return path(p, p + filename_size);
}
BOOST_FILESYSTEM_DECL path stem_v3() const;
BOOST_FILESYSTEM_DECL path stem_v4() const;
BOOST_FILESYSTEM_DECL path extension_v3() const;
path extension_v4() const
{
string_type::size_type extension_size = find_extension_v4_size();
string_type::size_type pos = m_pathname.size() - extension_size;
const value_type* p = m_pathname.c_str() + pos;
return path(p, p + extension_size);
}
BOOST_FILESYSTEM_DECL void remove_filename_v3();
BOOST_FILESYSTEM_DECL void remove_filename_v4();
BOOST_FILESYSTEM_DECL void replace_extension_v3(path const& new_extension);
BOOST_FILESYSTEM_DECL void replace_extension_v4(path const& new_extension);
BOOST_FILESYSTEM_DECL path lexically_normal_v3() const;
BOOST_FILESYSTEM_DECL path lexically_normal_v4() const;
BOOST_FILESYSTEM_DECL int compare_v3(path const& p) const;
BOOST_FILESYSTEM_DECL int compare_v4(path const& p) const;
BOOST_FILESYSTEM_DECL void append_v3(const value_type* b, const value_type* e);
BOOST_FILESYSTEM_DECL void append_v4(const value_type* b, const value_type* e);
// Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
// Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
BOOST_FILESYSTEM_DECL string_type::size_type append_separator_if_needed();
BOOST_FILESYSTEM_DECL void erase_redundant_separator(string_type::size_type sep_pos);
BOOST_FILESYSTEM_DECL string_type::size_type find_root_name_size() const;
BOOST_FILESYSTEM_DECL string_type::size_type find_root_path_size() const;
BOOST_FILESYSTEM_DECL path_detail::substring find_root_directory() const;
BOOST_FILESYSTEM_DECL path_detail::substring find_relative_path() const;
BOOST_FILESYSTEM_DECL string_type::size_type find_parent_path_size() const;
BOOST_FILESYSTEM_DECL string_type::size_type find_filename_v4_size() const;
BOOST_FILESYSTEM_DECL string_type::size_type find_extension_v4_size() const;
private: private:
/* /*
* m_pathname has the type, encoding, and format required by the native * m_pathname has the type, encoding, and format required by the native
@ -1174,8 +1171,6 @@ private:
}; };
namespace detail { namespace detail {
BOOST_FILESYSTEM_DECL int lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2);
BOOST_FILESYSTEM_DECL int lex_compare_v4(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2);
BOOST_FILESYSTEM_DECL path const& dot_path(); BOOST_FILESYSTEM_DECL path const& dot_path();
BOOST_FILESYSTEM_DECL path const& dot_dot_path(); BOOST_FILESYSTEM_DECL path const& dot_dot_path();
} // namespace detail } // namespace detail
@ -1184,13 +1179,15 @@ BOOST_FILESYSTEM_DECL path const& dot_dot_path();
typedef path wpath; typedef path wpath;
#endif #endif
namespace path_detail {
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
// class path::iterator // // class path::iterator //
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
class path::iterator : class path_iterator :
public boost::iterator_facade< public boost::iterator_facade<
path::iterator, path_iterator,
const path, const path,
boost::bidirectional_traversal_tag boost::bidirectional_traversal_tag
> >
@ -1198,24 +1195,18 @@ class path::iterator :
private: private:
friend class boost::iterator_core_access; friend class boost::iterator_core_access;
friend class boost::filesystem::path; friend class boost::filesystem::path;
friend class boost::filesystem::path::reverse_iterator; friend class path_reverse_iterator;
friend BOOST_FILESYSTEM_DECL int detail::lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2); friend struct boost::filesystem::detail::path_algorithms;
path const& dereference() const { return m_element; } path const& dereference() const { return m_element; }
bool equal(iterator const& rhs) const bool equal(path_iterator const& rhs) const BOOST_NOEXCEPT
{ {
return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos;
} }
BOOST_FORCEINLINE void increment() { BOOST_FILESYSTEM_VERSIONED_SYM(increment)(); } void increment();
BOOST_FORCEINLINE void decrement() { BOOST_FILESYSTEM_VERSIONED_SYM(decrement)(); } void decrement();
private:
BOOST_FILESYSTEM_DECL void increment_v3();
BOOST_FILESYSTEM_DECL void increment_v4();
BOOST_FILESYSTEM_DECL void decrement_v3();
BOOST_FILESYSTEM_DECL void decrement_v4();
private: private:
// current element // current element
@ -1227,22 +1218,22 @@ private:
// position of the last separator in the path. // position of the last separator in the path.
// end() iterator is indicated by // end() iterator is indicated by
// m_pos == m_path_ptr->m_pathname.size() // m_pos == m_path_ptr->m_pathname.size()
string_type::size_type m_pos; path::string_type::size_type m_pos;
}; };
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
// class path::reverse_iterator // // class path::reverse_iterator //
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
class path::reverse_iterator : class path_reverse_iterator :
public boost::iterator_facade< public boost::iterator_facade<
path::reverse_iterator, path_reverse_iterator,
const path, const path,
boost::bidirectional_traversal_tag boost::bidirectional_traversal_tag
> >
{ {
public: public:
explicit reverse_iterator(iterator itr) : explicit path_reverse_iterator(path_iterator itr) :
m_itr(itr) m_itr(itr)
{ {
if (itr != itr.m_path_ptr->begin()) if (itr != itr.m_path_ptr->begin())
@ -1254,14 +1245,14 @@ private:
friend class boost::filesystem::path; friend class boost::filesystem::path;
path const& dereference() const { return m_element; } path const& dereference() const { return m_element; }
bool equal(reverse_iterator const& rhs) const { return m_itr == rhs.m_itr; } bool equal(path_reverse_iterator const& rhs) const BOOST_NOEXCEPT { return m_itr == rhs.m_itr; }
void increment() void increment()
{ {
--m_itr; --m_itr;
if (m_itr != m_itr.m_path_ptr->begin()) if (m_itr != m_itr.m_path_ptr->begin())
{ {
iterator tmp = m_itr; path_iterator tmp = m_itr;
m_element = *--tmp; m_element = *--tmp;
} }
} }
@ -1273,38 +1264,24 @@ private:
} }
private: private:
iterator m_itr; path_iterator m_itr;
path m_element; path m_element;
}; };
// std::lexicographical_compare would infinitely recurse because path iterators
// yield paths, so provide a path aware version
bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2);
} // namespace path_detail
using path_detail::lexicographical_compare;
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
// // // //
// non-member functions // // non-member functions //
// // // //
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
// std::lexicographical_compare would infinitely recurse because path iterators
// yield paths, so provide a path aware version
BOOST_FORCEINLINE bool lexicographical_compare(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2)
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::lex_compare)(first1, last1, first2, last2) < 0;
}
BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const value_type* source, const value_type* source_end, const codecvt_type*) const
{
path src;
src.m_pathname.assign(source, source_end);
return m_self.compare(src);
}
template< typename OtherChar >
BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt) const
{
path src;
detail::path_traits::convert(source, source_end, src.m_pathname, cvt);
return m_self.compare(src);
}
BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs) BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs)
{ {
return lhs.compare(rhs) == 0; return lhs.compare(rhs) == 0;
@ -1545,6 +1522,41 @@ inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT
// class path miscellaneous function implementations // // class path miscellaneous function implementations //
//------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------//
namespace detail {
inline bool path_algorithms::has_filename_v3(path const& p)
{
return !p.m_pathname.empty();
}
inline bool path_algorithms::has_filename_v4(path const& p)
{
return path_algorithms::find_filename_v4_size(p) > 0;
}
inline path path_algorithms::filename_v4(path const& p)
{
string_type::size_type filename_size = path_algorithms::find_filename_v4_size(p);
string_type::size_type pos = p.m_pathname.size() - filename_size;
const value_type* ptr = p.m_pathname.c_str() + pos;
return path(ptr, ptr + filename_size);
}
inline path path_algorithms::extension_v4(path const& p)
{
string_type::size_type extension_size = path_algorithms::find_extension_v4_size(p);
string_type::size_type pos = p.m_pathname.size() - extension_size;
const value_type* ptr = p.m_pathname.c_str() + pos;
return path(ptr, ptr + extension_size);
}
inline void path_algorithms::append_v4(path& left, path const& right)
{
path_algorithms::append_v4(left, right.m_pathname.c_str(), right.m_pathname.c_str() + right.m_pathname.size());
}
} // namespace detail
// Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept, // Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept,
// any non-template function call that requires a check whether the source argument (which may be fs::path) // any non-template function call that requires a check whether the source argument (which may be fs::path)
// is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload // is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload
@ -1552,6 +1564,21 @@ inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT
// is not defined and defined, which causes compilation errors with gcc 11 and later. // is not defined and defined, which causes compilation errors with gcc 11 and later.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106808 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106808
BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const value_type* source, const value_type* source_end, const codecvt_type*) const
{
path src;
src.m_pathname.assign(source, source_end);
return m_self.compare(src);
}
template< typename OtherChar >
BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt) const
{
path src;
detail::path_traits::convert(source, source_end, src.m_pathname, cvt);
return m_self.compare(src);
}
inline path& path::operator=(path const& p) inline path& path::operator=(path const& p)
{ {
return assign(p); return assign(p);
@ -1608,7 +1635,7 @@ inline bool path::filename_is_dot_dot() const
#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) #if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::lexically_normal() instead") BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use path::lexically_normal() instead")
inline path& path::normalize() BOOST_FORCEINLINE path& path::normalize()
{ {
path tmp(lexically_normal()); path tmp(lexically_normal());
m_pathname.swap(tmp.m_pathname); m_pathname.swap(tmp.m_pathname);
@ -1617,6 +1644,100 @@ inline path& path::normalize()
#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) #endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
// The following functions are defined differently, depending on Boost.Filesystem version in use.
// To avoid ODR violation, these functions are not defined when the library itself is built.
// This makes sure they are not compiled when the library is built, and the only version there is
// is the one in user's code. Users are supposed to consistently use the same Boost.Filesystem version
// in all their translation units.
#if !defined(BOOST_FILESYSTEM_SOURCE)
BOOST_FORCEINLINE path& path::append(path const& p)
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
return *this;
}
BOOST_FORCEINLINE path& path::append(path const& p, codecvt_type const&)
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
return *this;
}
BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end)
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end);
return *this;
}
BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end, codecvt_type const&)
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end);
return *this;
}
BOOST_FORCEINLINE path& path::remove_filename()
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::remove_filename)(*this);
return *this;
}
BOOST_FORCEINLINE path& path::replace_extension(path const& new_extension)
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::replace_extension)(*this, new_extension);
return *this;
}
BOOST_FORCEINLINE int path::compare(path const& p) const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::compare)(*this, p);
}
BOOST_FORCEINLINE path path::filename() const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::filename)(*this);
}
BOOST_FORCEINLINE path path::stem() const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::stem)(*this);
}
BOOST_FORCEINLINE path path::extension() const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::extension)(*this);
}
BOOST_FORCEINLINE bool path::has_filename() const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::has_filename)(*this);
}
BOOST_FORCEINLINE path path::lexically_normal() const
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lexically_normal)(*this);
}
namespace path_detail {
BOOST_FORCEINLINE void path_iterator::increment()
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::increment)(*this);
}
BOOST_FORCEINLINE void path_iterator::decrement()
{
BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::decrement)(*this);
}
BOOST_FORCEINLINE bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2)
{
return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lex_compare)(first1, last1, first2, last2) < 0;
}
} // namespace path_detail
#endif // !defined(BOOST_FILESYSTEM_SOURCE)
//--------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------//
// class path member template specializations // // class path member template specializations //
//--------------------------------------------------------------------------------------// //--------------------------------------------------------------------------------------//

View File

@ -1109,7 +1109,18 @@ void directory_iterator_construct(directory_iterator& it, path const& p, unsigne
&& (filename_str[1] == static_cast< path::string_type::value_type >('\0') || && (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'))))) (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0')))))
{ {
imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat); path full_path(p);
path_algorithms::append_v4(full_path, filename);
imp->dir_entry.assign
(
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
static_cast< path&& >(full_path),
#else
full_path,
#endif
file_stat,
symlink_file_stat
);
it.m_imp.swap(imp); it.m_imp.swap(imp);
return; return;
} }

View File

@ -1116,7 +1116,7 @@ uintmax_t remove_all_impl
count += fs::detail::remove_all_impl count += fs::detail::remove_all_impl
( (
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) #if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
itr->path().filename(), path_algorithms::filename_v4(itr->path()),
#else #else
itr->path(), itr->path(),
#endif #endif
@ -2007,7 +2007,7 @@ uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec)
( (
hh.handle, hh.handle,
h, h,
nested_path.filename(), path_algorithms::filename_v4(nested_path),
0u, // FileAttributes 0u, // FileAttributes
FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@ -2393,12 +2393,12 @@ path absolute(path const& p, path const& base, system::error_code* ec)
else else
{ {
res.concat(abs_base.root_directory()); res.concat(abs_base.root_directory());
res /= abs_base.relative_path(); path_algorithms::append_v4(res, abs_base.relative_path());
} }
path p_relative_path(p.relative_path()); path p_relative_path(p.relative_path());
if (!p_relative_path.empty()) if (!p_relative_path.empty())
res /= p_relative_path; path_algorithms::append_v4(res, p_relative_path);
return res; return res;
} }
@ -2445,13 +2445,13 @@ path canonical(path const& p, path const& base, system::error_code* ec)
path result; path result;
while (true) while (true)
{ {
for (path::iterator itr(source.begin()), end(source.end()); itr != end; ++itr) for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr))
{ {
if (*itr == dot_p) if (path_algorithms::compare_v4(*itr, dot_p) == 0)
continue; continue;
if (*itr == dot_dot_p) if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0)
{ {
if (result != root) if (path_algorithms::compare_v4(result, root) != 0)
result.remove_filename_and_trailing_separators(); result.remove_filename_and_trailing_separators();
continue; continue;
} }
@ -2467,7 +2467,7 @@ path canonical(path const& p, path const& base, system::error_code* ec)
continue; continue;
} }
result /= *itr; path_algorithms::append_v4(result, *itr);
// If we don't have an absolute path yet then don't check symlink status. // If we don't have an absolute path yet then don't check symlink status.
// This avoids checking "C:" which is "the current directory on drive C" // This avoids checking "C:" which is "the current directory on drive C"
@ -2496,10 +2496,10 @@ path canonical(path const& p, path const& base, system::error_code* ec)
if (link.is_absolute()) if (link.is_absolute())
{ {
for (++itr; itr != end; ++itr) for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
{ {
if (*itr != dot_p) if (path_algorithms::compare_v4(*itr, dot_p) != 0)
link /= *itr; path_algorithms::append_v4(link, *itr);
} }
source = link; source = link;
root = source.root_path(); root = source.root_path();
@ -2507,15 +2507,15 @@ path canonical(path const& p, path const& base, system::error_code* ec)
else // link is relative else // link is relative
{ {
link.remove_trailing_separator(); link.remove_trailing_separator();
if (link == dot_p) if (path_algorithms::compare_v4(link, dot_p) == 0)
continue; continue;
path new_source(result); path new_source(result);
new_source /= link; path_algorithms::append_v4(new_source, link);
for (++itr; itr != end; ++itr) for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
{ {
if (*itr != dot_p) if (path_algorithms::compare_v4(*itr, dot_p) != 0)
new_source /= *itr; path_algorithms::append_v4(new_source, *itr);
} }
source = new_source; source = new_source;
} }
@ -2611,10 +2611,10 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
relative_from = detail::relative(abs_from, abs_to, ec); relative_from = detail::relative(abs_from, abs_to, ec);
if (ec && *ec) if (ec && *ec)
return; return;
if (relative_from != dot_path()) if (path_algorithms::compare_v4(relative_from, dot_path()) != 0)
relative_from /= from.filename(); path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from));
else else
relative_from = from.filename(); relative_from = path_algorithms::filename_v4(from);
pfrom = &relative_from; pfrom = &relative_from;
} }
detail::create_symlink(*pfrom, to, ec); detail::create_symlink(*pfrom, to, ec);
@ -2650,7 +2650,11 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
} }
if (is_directory(to_stat)) if (is_directory(to_stat))
detail::copy_file(from, to / from.filename(), options, ec); {
path target(to);
path_algorithms::append_v4(target, path_algorithms::filename_v4(from));
detail::copy_file(from, target, options, ec);
}
else else
detail::copy_file(from, to, options, ec); detail::copy_file(from, to, options, ec);
} }
@ -2705,8 +2709,12 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
while (itr != end_dit) while (itr != end_dit)
{ {
path const& p = itr->path(); path const& p = itr->path();
// Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none {
detail::copy(p, to / p.filename(), options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); path target(to);
path_algorithms::append_v4(target, path_algorithms::filename_v4(p));
// Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none
detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec);
}
if (ec && *ec) if (ec && *ec)
return; return;
@ -3096,9 +3104,9 @@ bool create_directories(path const& p, system::error_code* ec)
error_code local_ec; error_code local_ec;
// Find the initial part of the path that exists // Find the initial part of the path that exists
for (path fname = parent.filename(); parent.has_relative_path(); fname = parent.filename()) for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent))
{ {
if (!fname.empty() && fname != dot_p && fname != dot_dot_p) if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0)
{ {
file_status existing_status = detail::status_impl(parent, &local_ec); file_status existing_status = detail::status_impl(parent, &local_ec);
@ -3115,17 +3123,17 @@ bool create_directories(path const& p, system::error_code* ec)
} }
} }
--it; path_algorithms::decrement_v4(it);
parent.remove_filename_and_trailing_separators(); parent.remove_filename_and_trailing_separators();
} }
// Create missing directories // Create missing directories
bool created = false; bool created = false;
for (; it != e; ++it) for (; it != e; path_algorithms::increment_v4(it))
{ {
path const& fname = *it; path const& fname = *it;
parent /= fname; path_algorithms::append_v4(parent, fname);
if (!fname.empty() && fname != dot_p && fname != dot_dot_p) if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0)
{ {
created = detail::create_directory(parent, NULL, &local_ec); created = detail::create_directory(parent, NULL, &local_ec);
if (BOOST_UNLIKELY(!!local_ec)) if (BOOST_UNLIKELY(!!local_ec))
@ -4318,11 +4326,8 @@ path temp_directory_path(system::error_code* ec)
#else // Windows #else // Windows
#if !defined(UNDER_CE) #if !defined(UNDER_CE)
const wchar_t* tmp_env = L"TMP"; static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" };
const wchar_t* temp_env = L"TEMP"; static const wchar_t temp_dir[] = L"Temp";
const wchar_t* localappdata_env = L"LOCALAPPDATA";
const wchar_t* userprofile_env = L"USERPROFILE";
const wchar_t* env_list[] = { tmp_env, temp_env, localappdata_env, userprofile_env };
path p; path p;
for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i)
@ -4332,7 +4337,7 @@ path temp_directory_path(system::error_code* ec)
{ {
p = env; p = env;
if (i >= 2) if (i >= 2)
p /= L"Temp"; path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u));
error_code lcl_ec; error_code lcl_ec;
if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec)
break; break;
@ -4357,7 +4362,7 @@ path temp_directory_path(system::error_code* ec)
goto getwindir_error; goto getwindir_error;
p = buf.get(); // do not depend on initial buf size, see ticket #10388 p = buf.get(); // do not depend on initial buf size, see ticket #10388
p /= L"Temp"; path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u));
} }
return p; return p;
@ -4403,7 +4408,12 @@ path system_complete(path const& p, system::error_code* ec)
{ {
#ifdef BOOST_POSIX_API #ifdef BOOST_POSIX_API
return (p.empty() || p.is_absolute()) ? p : current_path() / p; if (p.empty() || p.is_absolute())
return p;
path res(current_path());
path_algorithms::append_v4(res, p);
return res;
#else #else
if (p.empty()) if (p.empty())
@ -4440,7 +4450,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
path::iterator itr(p_end); path::iterator itr(p_end);
path head(p); path head(p);
for (; !head.empty(); --itr) for (; !head.empty(); path_algorithms::decrement_v4(itr))
{ {
file_status head_status(detail::status_impl(head, &local_ec)); file_status head_status(detail::status_impl(head, &local_ec));
if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
@ -4459,7 +4469,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
} }
if (head.empty()) if (head.empty())
return p.lexically_normal(); return path_algorithms::lexically_normal_v4(p);
path const& dot_p = dot_path(); path const& dot_p = dot_path();
path const& dot_dot_p = dot_dot_path(); path const& dot_dot_p = dot_dot_path();
@ -4482,7 +4492,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
{ {
BOOST_ASSERT(itr != p_end); BOOST_ASSERT(itr != p_end);
head = *itr; head = *itr;
++itr; path_algorithms::increment_v4(itr);
} }
if (p.has_root_directory()) if (p.has_root_directory())
@ -4491,7 +4501,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
// Convert generic separator returned by the iterator for the root directory to // Convert generic separator returned by the iterator for the root directory to
// the preferred separator. // the preferred separator.
head += path::preferred_separator; head += path::preferred_separator;
++itr; path_algorithms::increment_v4(itr);
} }
if (!head.empty()) if (!head.empty())
@ -4509,22 +4519,22 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (head_status.type() == fs::file_not_found) if (head_status.type() == fs::file_not_found)
{ {
// If the root path does not exist then no path element exists // If the root path does not exist then no path element exists
return p.lexically_normal(); return path_algorithms::lexically_normal_v4(p);
} }
} }
path const& dot_p = dot_path(); path const& dot_p = dot_path();
path const& dot_dot_p = dot_dot_path(); path const& dot_dot_p = dot_dot_path();
for (; itr != p_end; ++itr) for (; itr != p_end; path_algorithms::increment_v4(itr))
{ {
path const& p_elem = *itr; path const& p_elem = *itr;
// Avoid querying status of paths containing dot and dot-dot elements, as this will break // Avoid querying status of paths containing dot and dot-dot elements, as this will break
// if the root name starts with "\\?\". // if the root name starts with "\\?\".
if (p_elem == dot_p) if (path_algorithms::compare_v4(p_elem, dot_p) == 0)
continue; continue;
if (p_elem == dot_dot_p) if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0)
{ {
if (head.has_relative_path()) if (head.has_relative_path())
head.remove_filename_and_trailing_separators(); head.remove_filename_and_trailing_separators();
@ -4532,7 +4542,7 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
continue; continue;
} }
head /= p_elem; path_algorithms::append_v4(head, p_elem);
file_status head_status(detail::status_impl(head, &local_ec)); file_status head_status(detail::status_impl(head, &local_ec));
if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
@ -4552,18 +4562,18 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
} }
if (head.empty()) if (head.empty())
return p.lexically_normal(); return path_algorithms::lexically_normal_v4(p);
#endif #endif
path tail; path tail;
bool tail_has_dots = false; bool tail_has_dots = false;
for (; itr != p_end; ++itr) for (; itr != p_end; path_algorithms::increment_v4(itr))
{ {
path const& tail_elem = *itr; path const& tail_elem = *itr;
tail /= tail_elem; path_algorithms::append_v4(tail, tail_elem);
// for a later optimization, track if any dot or dot-dot elements are present // for a later optimization, track if any dot or dot-dot elements are present
if (!tail_has_dots && (tail_elem == dot_p || tail_elem == dot_dot_p)) if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0))
tail_has_dots = true; tail_has_dots = true;
} }
@ -4579,11 +4589,11 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (BOOST_LIKELY(!tail.empty())) if (BOOST_LIKELY(!tail.empty()))
{ {
head /= tail; path_algorithms::append_v4(head, tail);
// optimization: only normalize if tail had dot or dot-dot element // optimization: only normalize if tail had dot or dot-dot element
if (tail_has_dots) if (tail_has_dots)
return head.lexically_normal(); return path_algorithms::lexically_normal_v4(head);
} }
return head; return head;

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ inline boost::filesystem::perms make_permissions(boost::filesystem::path const&
boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read; boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read;
if ((attr & FILE_ATTRIBUTE_READONLY) == 0u) if ((attr & FILE_ATTRIBUTE_READONLY) == 0u)
prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write; prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write;
boost::filesystem::path ext = p.extension(); boost::filesystem::path ext = detail::path_algorithms::extension_v4(p);
wchar_t const* q = ext.c_str(); wchar_t const* q = ext.c_str();
if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD")) if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD"))
prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe; prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe;