aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/filesystem/src
diff options
context:
space:
mode:
authorAlexSm <alex@ydb.tech>2023-12-27 23:31:58 +0100
committerGitHub <noreply@github.com>2023-12-27 23:31:58 +0100
commitd67bfb4b4b7549081543e87a31bc6cb5c46ac973 (patch)
tree8674f2f1570877cb653e7ddcff37ba00288de15a /contrib/restricted/boost/filesystem/src
parent1f6bef05ed441c3aa2d565ac792b26cded704ac7 (diff)
downloadydb-d67bfb4b4b7549081543e87a31bc6cb5c46ac973.tar.gz
Import libs 4 (#758)
Diffstat (limited to 'contrib/restricted/boost/filesystem/src')
-rw-r--r--contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp2
-rw-r--r--contrib/restricted/boost/filesystem/src/directory.cpp209
-rw-r--r--contrib/restricted/boost/filesystem/src/operations.cpp356
-rw-r--r--contrib/restricted/boost/filesystem/src/path.cpp1055
-rw-r--r--contrib/restricted/boost/filesystem/src/path_traits.cpp66
-rw-r--r--contrib/restricted/boost/filesystem/src/windows_tools.hpp14
6 files changed, 863 insertions, 839 deletions
diff --git a/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp
index 72db677a09..a8d2a42732 100644
--- a/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp
+++ b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp
@@ -15,7 +15,7 @@
#include <boost/config/warning_disable.hpp>
#include <boost/filesystem/config.hpp>
-#include <boost/filesystem/path_traits.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
#include <boost/system/error_category.hpp>
#include <locale>
#include <string>
diff --git a/contrib/restricted/boost/filesystem/src/directory.cpp b/contrib/restricted/boost/filesystem/src/directory.cpp
index 6a3e1dc731..f769f8fc18 100644
--- a/contrib/restricted/boost/filesystem/src/directory.cpp
+++ b/contrib/restricted/boost/filesystem/src/directory.cpp
@@ -74,15 +74,6 @@
#include <boost/filesystem/detail/header.hpp> // must be the last #include
-// BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in
-// dir_itr_increment. The config tests are placed here because some of the
-// macros being tested come from dirent.h.
-//
-// TODO: find out what macros indicate dirent::d_type present in more libraries
-#if defined(BOOST_WINDOWS_API) || defined(_DIRENT_HAVE_D_TYPE) // defined by GNU C library if d_type present
-#define BOOST_FILESYSTEM_STATUS_CACHE
-#endif
-
namespace fs = boost::filesystem;
using boost::system::error_code;
using boost::system::system_category;
@@ -96,76 +87,34 @@ 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))
- {
- m_status = m_symlink_status;
- if (ec)
- ec->clear();
- }
- else
+ // 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 = 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;
-}
-
-// dispatch directory_entry supplied here rather than in
-// <boost/filesystem/path_traits.hpp>, thus avoiding header circularity.
-// test cases are in operations_unit_test.cpp
-
-namespace path_traits {
-
-BOOST_FILESYSTEM_DECL
-void dispatch(directory_entry const& de,
-#ifdef BOOST_WINDOWS_API
- std::wstring& to,
-#else
- std::string& to,
-#endif
- codecvt_type const&)
-{
- to = de.path().native();
-}
-
-BOOST_FILESYSTEM_DECL
-void dispatch(directory_entry const& de,
-#ifdef BOOST_WINDOWS_API
- std::wstring& to
-#else
- std::string& to
-#endif
-)
-{
- to = de.path().native();
-}
-
-} // namespace path_traits
-
//--------------------------------------------------------------------------------------//
// //
// directory_iterator //
@@ -353,24 +302,43 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
filename = result->d_name;
-#ifdef BOOST_FILESYSTEM_STATUS_CACHE
+#if defined(BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE)
if (result->d_type == DT_UNKNOWN) // filesystem does not supply d_type value
{
sf = symlink_sf = fs::file_status(fs::status_error);
}
else // filesystem supplies d_type value
{
- if (result->d_type == DT_DIR)
- sf = symlink_sf = fs::file_status(fs::directory_file);
- else if (result->d_type == DT_REG)
+ if (result->d_type == DT_REG)
sf = symlink_sf = fs::file_status(fs::regular_file);
+ else if (result->d_type == DT_DIR)
+ sf = symlink_sf = fs::file_status(fs::directory_file);
else if (result->d_type == DT_LNK)
{
sf = fs::file_status(fs::status_error);
symlink_sf = fs::file_status(fs::symlink_file);
}
else
- sf = symlink_sf = fs::file_status(fs::status_error);
+ {
+ switch (result->d_type)
+ {
+ case DT_SOCK:
+ sf = symlink_sf = fs::file_status(fs::socket_file);
+ break;
+ case DT_FIFO:
+ sf = symlink_sf = fs::file_status(fs::fifo_file);
+ break;
+ case DT_BLK:
+ sf = symlink_sf = fs::file_status(fs::block_file);
+ break;
+ case DT_CHR:
+ sf = symlink_sf = fs::file_status(fs::character_file);
+ break;
+ default:
+ sf = symlink_sf = fs::file_status(fs::status_error);
+ break;
+ }
+ }
}
#else
sf = symlink_sf = fs::file_status(fs::status_error);
@@ -599,9 +567,12 @@ extra_data_format g_extra_data_format = file_directory_information_format;
* \brief Extra buffer size for GetFileInformationByHandleEx-based or NtQueryDirectoryFile-based directory iterator.
*
* Must be large enough to accommodate at least one FILE_DIRECTORY_INFORMATION or *_DIR_INFO struct and one filename.
- * NTFS, VFAT, exFAT support filenames up to 255 UTF-16/UCS-2 characters. ReFS supports filenames up to 32768 UTF-16 characters.
+ * NTFS, VFAT, exFAT and ReFS support filenames up to 255 UTF-16/UCS-2 characters. (For ReFS, there is no information
+ * on the on-disk format, and it is possible that it supports longer filenames, up to 32768 UTF-16/UCS-2 characters.)
+ * The buffer cannot be larger than 64k, because up to Windows 8.1, NtQueryDirectoryFile and GetFileInformationByHandleEx
+ * fail with ERROR_INVALID_PARAMETER when trying to retrieve the filenames from a network share.
*/
-BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = sizeof(file_id_extd_dir_info) + 65536u;
+BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = 65536u;
inline system::error_code dir_itr_close(dir_itr_imp& imp) BOOST_NOEXCEPT
{
@@ -763,6 +734,28 @@ done:
return error_code();
}
+//! Returns \c true if the error code indicates that the OS or the filesystem does not support a particular directory info class
+inline bool is_dir_info_class_not_supported(DWORD error)
+{
+ // Some mounted filesystems may not support FILE_ID_128 identifiers, which will cause
+ // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER,
+ // even though in general the operation is supported by the kernel. SMBv1 returns a special error
+ // code ERROR_INVALID_LEVEL in this case.
+ // Some other filesystems also don't implement other info classes and return ERROR_INVALID_PARAMETER
+ // (e.g. see https://github.com/boostorg/filesystem/issues/266), ERROR_GEN_FAILURE, ERROR_INVALID_FUNCTION
+ // or ERROR_INTERNAL_ERROR (https://github.com/boostorg/filesystem/issues/286). Treat these error codes
+ // as "non-permanent", even though ERROR_INVALID_PARAMETER is also returned if GetFileInformationByHandleEx
+ // in general does not support a certain info class. Worst case, we will make extra syscalls on directory
+ // iterator construction.
+ // Also note that Wine returns ERROR_CALL_NOT_IMPLEMENTED for unimplemented info classes, and
+ // up until 7.21 it didn't implement FileIdExtdDirectoryRestartInfo and FileFullDirectoryRestartInfo.
+ // (https://bugs.winehq.org/show_bug.cgi?id=53590)
+ return error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER ||
+ error == ERROR_INVALID_LEVEL || error == ERROR_CALL_NOT_IMPLEMENTED ||
+ error == ERROR_GEN_FAILURE || error == ERROR_INVALID_FUNCTION ||
+ error == ERROR_INTERNAL_ERROR;
+}
+
error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, unsigned int opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf)
{
boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (dir_itr_extra_size) detail::dir_itr_imp());
@@ -828,9 +821,14 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
if (BOOST_UNLIKELY((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u))
return make_error_code(system::errc::not_a_directory);
- if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u)
+ if ((opts & static_cast< unsigned int >(directory_options::_detail_no_follow)) != 0u && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
{
- if ((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u && is_reparse_point_a_symlink_ioctl(h.handle))
+ error_code ec;
+ const ULONG reparse_point_tag = detail::get_reparse_point_tag_ioctl(h.handle, dir, &ec);
+ if (BOOST_UNLIKELY(!!ec))
+ return ec;
+
+ if (detail::is_reparse_point_tag_a_symlink(reparse_point_tag))
return make_error_code(system::errc::too_many_symbolic_link_levels);
}
}
@@ -845,14 +843,10 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
{
DWORD error = ::GetLastError();
- if (error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER)
+ if (is_dir_info_class_not_supported(error))
{
// Fall back to file_full_dir_info_format.
- // Note that some mounted filesystems may not support FILE_ID_128 identifiers, which will cause
- // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER,
- // even though in general the operation is supported by the kernel. So don't downgrade to
- // FileFullDirectoryRestartInfo permanently in this case - only for this particular iterator.
- if (error == ERROR_NOT_SUPPORTED)
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_full_dir_info_format);
goto fallback_to_file_full_dir_info_format;
}
@@ -879,11 +873,12 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
{
DWORD error = ::GetLastError();
- if (error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER)
+ if (is_dir_info_class_not_supported(error))
{
// Fall back to file_id_both_dir_info
- filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format);
- goto fallback_to_file_id_both_dir_info;
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format);
+ goto fallback_to_file_id_both_dir_info_format;
}
if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
@@ -902,12 +897,20 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
break;
case file_id_both_dir_info_format:
- fallback_to_file_id_both_dir_info:
+ fallback_to_file_id_both_dir_info_format:
{
if (!get_file_information_by_handle_ex(iterator_handle, file_id_both_directory_restart_info_class, extra_data, dir_itr_extra_size))
{
DWORD error = ::GetLastError();
+ if (is_dir_info_class_not_supported(error))
+ {
+ // Fall back to file_directory_information
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_directory_information_format);
+ goto fallback_to_file_directory_information_format;
+ }
+
if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
goto done;
@@ -924,6 +927,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
break;
default:
+ fallback_to_file_directory_information_format:
{
NtQueryDirectoryFile_t* nt_query_directory_file = filesystem::detail::atomic_load_relaxed(boost::filesystem::detail::nt_query_directory_file_api);
if (BOOST_UNLIKELY(!nt_query_directory_file))
@@ -1120,7 +1124,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] == 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_with_status
+ (
+#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);
return;
}
@@ -1180,7 +1195,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;
}
}
@@ -1344,14 +1359,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;
}
@@ -1364,12 +1379,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
@@ -1379,7 +1394,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/contrib/restricted/boost/filesystem/src/operations.cpp b/contrib/restricted/boost/filesystem/src/operations.cpp
index dd636e9063..c7808d5941 100644
--- a/contrib/restricted/boost/filesystem/src/operations.cpp
+++ b/contrib/restricted/boost/filesystem/src/operations.cpp
@@ -70,7 +70,7 @@
#include <unistd.h>
#include <fcntl.h>
-#if _POSIX_C_SOURCE < 200809L
+#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
#include <utime.h>
#endif
#include <limits.h>
@@ -1116,7 +1116,7 @@ uintmax_t remove_all_impl
count += fs::detail::remove_all_impl
(
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
- itr->path().filename(),
+ path_algorithms::filename_v4(itr->path()),
#else
itr->path(),
#endif
@@ -1511,50 +1511,36 @@ boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_ha
#endif // !defined(UNDER_CE)
-bool is_reparse_point_a_symlink_ioctl(HANDLE h)
+ULONG get_reparse_point_tag_ioctl(HANDLE h, path const& p, error_code* ec)
{
- boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage);
+ boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new (std::nothrow) reparse_data_buffer_with_storage);
+ if (BOOST_UNLIKELY(!buf.get()))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("Cannot allocate memory to query reparse point", p, make_error_code(system::errc::not_enough_memory)));
+
+ *ec = make_error_code(system::errc::not_enough_memory);
+ return 0u;
+ }
// Query the reparse data
DWORD dwRetLen = 0u;
BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL);
if (BOOST_UNLIKELY(!result))
- return false;
-
- return is_reparse_point_tag_a_symlink(buf->rdb.ReparseTag);
-}
-
-namespace {
-
-inline bool is_reparse_point_a_symlink(path const& p)
-{
- handle_wrapper h(create_file_handle(
- p,
- FILE_READ_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
- if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE))
- return false;
-
- GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
- if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
{
- file_attribute_tag_info info;
- BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
- if (BOOST_UNLIKELY(!result))
- return false;
-
- if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u)
- return false;
+ DWORD err = ::GetLastError();
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("Failed to query reparse point", p, error_code(err, system_category())));
- return is_reparse_point_tag_a_symlink(info.ReparseTag);
+ ec->assign(err, system_category());
+ return 0u;
}
- return is_reparse_point_a_symlink_ioctl(h.handle);
+ return buf->rdb.ReparseTag;
}
+namespace {
+
inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p)
{
return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p));
@@ -1590,6 +1576,7 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec)
{
fs::file_type ftype;
DWORD attrs;
+ ULONG reparse_tag = 0u;
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
{
@@ -1609,12 +1596,7 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec)
}
attrs = info.FileAttributes;
-
- if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
- {
- ftype = is_reparse_point_tag_a_symlink(info.ReparseTag) ? fs::symlink_file : fs::reparse_file;
- goto done;
- }
+ reparse_tag = info.ReparseTag;
}
else
{
@@ -1626,25 +1608,48 @@ fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec)
attrs = info.dwFileAttributes;
- if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
{
- ftype = is_reparse_point_a_symlink_ioctl(h) ? fs::symlink_file : fs::reparse_file;
- goto done;
+ reparse_tag = get_reparse_point_tag_ioctl(h, p, ec);
+ if (ec)
+ {
+ if (BOOST_UNLIKELY(!!ec))
+ return fs::file_status(fs::status_error);
+ }
}
}
- ftype = (attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file;
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
+ {
+ if (reparse_tag == IO_REPARSE_TAG_DEDUP)
+ ftype = fs::regular_file;
+ else if (is_reparse_point_tag_a_symlink(reparse_tag))
+ ftype = fs::symlink_file;
+ else
+ ftype = fs::reparse_file;
+ }
+ else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u)
+ {
+ ftype = fs::directory_file;
+ }
+ else
+ {
+ ftype = fs::regular_file;
+ }
-done:
return fs::file_status(ftype, make_permissions(p, attrs));
}
//! symlink_status() implementation
fs::file_status symlink_status_impl(path const& p, error_code* ec)
{
+ // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect
+ // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL
+ // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround.
+ // https://github.com/boostorg/filesystem/issues/282
handle_wrapper h(create_file_handle(
p.c_str(),
- FILE_READ_ATTRIBUTES, // dwDesiredAccess; attributes only
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, // lpSecurityAttributes
OPEN_EXISTING,
@@ -1688,7 +1693,7 @@ fs::file_status status_impl(path const& p, error_code* ec)
// Resolve the symlink
handle_wrapper h(create_file_handle(
p.c_str(),
- FILE_READ_ATTRIBUTES, // dwDesiredAccess; attributes only
+ FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // lpSecurityAttributes
OPEN_EXISTING,
@@ -1775,7 +1780,7 @@ DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl)
break;
err = ::GetLastError();
- if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED))
+ if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED))
{
// Downgrade to the older implementation
impl = remove_disp_ex_flag_posix_semantics;
@@ -1833,7 +1838,7 @@ DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl)
break;
}
- else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED))
+ else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED))
{
// Downgrade to the older implementation
impl = remove_disp;
@@ -1902,7 +1907,7 @@ inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec
{
handle_wrapper h(create_file_handle(
p,
- DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
@@ -1999,12 +2004,12 @@ uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec)
(
hh.handle,
h,
- nested_path.filename(),
+ path_algorithms::filename_v4(nested_path),
0u, // FileAttributes
- FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
- FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
);
if (!NT_SUCCESS(status))
@@ -2027,7 +2032,7 @@ uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec)
{
hh.handle = create_file_handle(
nested_path,
- FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
@@ -2144,7 +2149,7 @@ inline uintmax_t remove_all_impl(path const& p, error_code* ec)
{
handle_wrapper h(create_file_handle(
p,
- FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
@@ -2385,12 +2390,12 @@ path absolute(path const& p, path const& base, system::error_code* ec)
else
{
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());
if (!p_relative_path.empty())
- res /= p_relative_path;
+ path_algorithms::append_v4(res, p_relative_path);
return res;
}
@@ -2437,14 +2442,14 @@ path canonical(path const& p, path const& base, system::error_code* ec)
path result;
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;
- if (*itr == dot_dot_p)
+ if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0)
{
- if (result != root)
- result.remove_filename();
+ if (path_algorithms::compare_v4(result, root) != 0)
+ result.remove_filename_and_trailing_separators();
continue;
}
@@ -2459,7 +2464,7 @@ path canonical(path const& p, path const& base, system::error_code* ec)
continue;
}
- result /= *itr;
+ path_algorithms::append_v4(result, *itr);
// 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"
@@ -2484,14 +2489,14 @@ path canonical(path const& p, path const& base, system::error_code* ec)
path link(detail::read_symlink(result, ec));
if (ec && *ec)
goto return_empty_path;
- result.remove_filename();
+ result.remove_filename_and_trailing_separators();
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)
- link /= *itr;
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(link, *itr);
}
source = link;
root = source.root_path();
@@ -2499,15 +2504,15 @@ path canonical(path const& p, path const& base, system::error_code* ec)
else // link is relative
{
link.remove_trailing_separator();
- if (link == dot_p)
+ if (path_algorithms::compare_v4(link, dot_p) == 0)
continue;
path new_source(result);
- new_source /= link;
- for (++itr; itr != end; ++itr)
+ path_algorithms::append_v4(new_source, link);
+ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
{
- if (*itr != dot_p)
- new_source /= *itr;
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(new_source, *itr);
}
source = new_source;
}
@@ -2603,10 +2608,10 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
relative_from = detail::relative(abs_from, abs_to, ec);
if (ec && *ec)
return;
- if (relative_from != dot_path())
- relative_from /= from.filename();
+ if (path_algorithms::compare_v4(relative_from, dot_path()) != 0)
+ path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from));
else
- relative_from = from.filename();
+ relative_from = path_algorithms::filename_v4(from);
pfrom = &relative_from;
}
detail::create_symlink(*pfrom, to, ec);
@@ -2642,7 +2647,11 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
}
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
detail::copy_file(from, to, options, ec);
}
@@ -2697,8 +2706,12 @@ void copy(path const& from, path const& to, unsigned int options, system::error_
while (itr != end_dit)
{
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)
return;
@@ -2953,7 +2966,14 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod
// Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError
handle_wrapper hw_from, hw_to;
- hw_from.handle = create_file_handle(from.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS);
+ // See the comment in last_write_time regarding access rights used here for GetFileTime.
+ hw_from.handle = create_file_handle(
+ from.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS);
FILETIME lwt_from;
if (hw_from.handle == INVALID_HANDLE_VALUE)
@@ -2967,7 +2987,13 @@ bool copy_file(path const& from, path const& to, unsigned int options, error_cod
if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from))
goto fail_last_error;
- hw_to.handle = create_file_handle(to.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS);
+ hw_to.handle = create_file_handle(
+ to.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS);
if (hw_to.handle != INVALID_HANDLE_VALUE)
{
@@ -3088,9 +3114,9 @@ bool create_directories(path const& p, system::error_code* ec)
error_code local_ec;
// 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);
@@ -3107,19 +3133,19 @@ bool create_directories(path const& p, system::error_code* ec)
}
}
- --it;
- parent.remove_filename();
+ path_algorithms::decrement_v4(it);
+ parent.remove_filename_and_trailing_separators();
}
// Create missing directories
bool created = false;
- for (; it != e; ++it)
+ for (; it != e; path_algorithms::increment_v4(it))
{
path const& fname = *it;
- parent /= fname;
- if (!fname.empty() && fname != dot_p && fname != dot_dot_p)
+ path_algorithms::append_v4(parent, fname);
+ if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0)
{
- created = create_directory(parent, NULL, &local_ec);
+ created = detail::create_directory(parent, NULL, &local_ec);
if (BOOST_UNLIKELY(!!local_ec))
{
if (!ec)
@@ -3749,9 +3775,10 @@ std::time_t creation_time(path const& p, system::error_code* ec)
#else // defined(BOOST_POSIX_API)
+ // See the comment in last_write_time regarding access rights used here for GetFileTime.
handle_wrapper hw(create_file_handle(
p.c_str(),
- FILE_READ_ATTRIBUTES,
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
@@ -3765,7 +3792,6 @@ std::time_t creation_time(path const& p, system::error_code* ec)
}
FILETIME ct;
-
if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL)))
goto fail;
@@ -3807,9 +3833,12 @@ std::time_t last_write_time(path const& p, system::error_code* ec)
#else // defined(BOOST_POSIX_API)
+ // GetFileTime is documented to require GENERIC_READ access right, but this causes problems if the file
+ // is opened by another process without FILE_SHARE_READ. In practice, FILE_READ_ATTRIBUTES works, and
+ // FILE_READ_EA is also added for good measure, in case if it matters for SMBv1.
handle_wrapper hw(create_file_handle(
p.c_str(),
- FILE_READ_ATTRIBUTES,
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
@@ -3823,7 +3852,6 @@ std::time_t last_write_time(path const& p, system::error_code* ec)
}
FILETIME lwt;
-
if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt)))
goto fail;
@@ -4055,9 +4083,8 @@ path read_symlink(path const& p, system::error_code* ec)
DWORD error;
if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE))
{
+ return_last_error:
error = ::GetLastError();
-
- return_error:
emit_error(error, p, ec, "boost::filesystem::read_symlink");
return symlink_path;
}
@@ -4065,10 +4092,7 @@ path read_symlink(path const& p, system::error_code* ec)
boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage);
DWORD sz = 0u;
if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL)))
- {
- error = ::GetLastError();
- goto return_error;
- }
+ goto return_last_error;
const wchar_t* buffer;
std::size_t offset, len;
@@ -4310,11 +4334,8 @@ path temp_directory_path(system::error_code* ec)
#else // Windows
#if !defined(UNDER_CE)
- const wchar_t* tmp_env = L"TMP";
- const wchar_t* temp_env = 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 };
+ static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" };
+ static const wchar_t temp_dir[] = L"Temp";
path p;
for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i)
@@ -4324,7 +4345,7 @@ path temp_directory_path(system::error_code* ec)
{
p = env;
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;
if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec)
break;
@@ -4349,7 +4370,7 @@ path temp_directory_path(system::error_code* ec)
goto getwindir_error;
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;
@@ -4395,7 +4416,12 @@ path system_complete(path const& p, system::error_code* ec)
{
#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
if (p.empty())
@@ -4432,9 +4458,9 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
path::iterator itr(p_end);
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 (!ec)
@@ -4447,35 +4473,86 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (head_status.type() != fs::file_not_found)
break;
- head.remove_filename();
+ head.remove_filename_and_trailing_separators();
}
+ if (head.empty())
+ return path_algorithms::lexically_normal_v4(p);
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+
#else
- // On Windows, filesystem APIs such as GetFileAttributesW perform lexical path normalization internally.
- // As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would break
- // canonical, as symlink_status that it calls internally would report an error that the file at the intermediate
- // path does not exist. To avoid this, scan the initial path in the forward direction.
- // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW,
- // which is called in status() may return "file not found" for paths to network shares and mounted cloud
- // storages that have forward slashes as separators.
+ // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization
+ // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would
+ // break canonical, as symlink_status that it calls internally would report an error that the file at the
+ // intermediate path does not exist. To avoid this, scan the initial path in the forward direction.
+ // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW
+ // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and
+ // mounted cloud storages that have forward slashes as separators.
+ // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for
+ // such path. Querying the status of a root name such as c: is also not right as this path refers to the current
+ // directory on drive C:, which is not what we want to test for existence anyway.
path::iterator itr(p.begin());
path head;
- for (; itr != p_end; ++itr)
+ if (p.has_root_name())
{
- path const& p_elem = *itr;
- if (p_elem.size() == 1u && detail::is_directory_separator(p_elem.native()[0]))
+ BOOST_ASSERT(itr != p_end);
+ head = *itr;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (p.has_root_directory())
+ {
+ BOOST_ASSERT(itr != p_end);
+ // Convert generic separator returned by the iterator for the root directory to
+ // the preferred separator.
+ head += path::preferred_separator;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (!head.empty())
+ {
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
{
- // Convert generic separator returned by the iterator for the root directory to
- // the preferred separator.
- head += path::preferred_separator;
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ return path();
}
- else
+
+ if (head_status.type() == fs::file_not_found)
{
- head /= p_elem;
+ // If the root path does not exist then no path element exists
+ return path_algorithms::lexically_normal_v4(p);
}
+ }
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+ for (; itr != p_end; path_algorithms::increment_v4(itr))
+ {
+ path const& p_elem = *itr;
+
+ // Avoid querying status of paths containing dot and dot-dot elements, as this will break
+ // if the root name starts with "\\?\".
+ if (path_algorithms::compare_v4(p_elem, dot_p) == 0)
+ continue;
+
+ if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0)
+ {
+ if (head.has_relative_path())
+ head.remove_filename_and_trailing_separators();
- file_status head_status = detail::status_impl(head, &local_ec);
+ continue;
+ }
+
+ path_algorithms::append_v4(head, p_elem);
+
+ file_status head_status(detail::status_impl(head, &local_ec));
if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
{
if (!ec)
@@ -4487,38 +4564,27 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (head_status.type() == fs::file_not_found)
{
- head.remove_filename();
+ head.remove_filename_and_trailing_separators();
break;
}
}
+ if (head.empty())
+ return path_algorithms::lexically_normal_v4(p);
+
#endif
- path const& dot_p = dot_path();
- path const& dot_dot_p = dot_dot_path();
path tail;
bool tail_has_dots = false;
- for (; itr != p_end; ++itr)
+ for (; itr != p_end; path_algorithms::increment_v4(itr))
{
path const& tail_elem = *itr;
-#if defined(BOOST_WINDOWS_API)
- if (tail_elem.size() == 1u && detail::is_directory_separator(tail_elem.native()[0]))
- {
- // Convert generic separator returned by the iterator for the root directory to
- // the preferred separator.
- tail += path::preferred_separator;
- continue;
- }
-#endif
- tail /= tail_elem;
+ path_algorithms::append_v4(tail, tail_elem);
// 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;
}
- if (head.empty())
- return p.lexically_normal();
-
head = detail::canonical(head, base, &local_ec);
if (BOOST_UNLIKELY(!!local_ec))
{
@@ -4531,11 +4597,11 @@ path weakly_canonical(path const& p, path const& base, system::error_code* ec)
if (BOOST_LIKELY(!tail.empty()))
{
- head /= tail;
+ path_algorithms::append_v4(head, tail);
// optimization: only normalize if tail had dot or dot-dot element
if (tail_has_dots)
- return head.lexically_normal();
+ return path_algorithms::lexically_normal_v4(head);
}
return head;
diff --git a/contrib/restricted/boost/filesystem/src/path.cpp b/contrib/restricted/boost/filesystem/src/path.cpp
index 27b32e57c5..1d9748cac7 100644
--- a/contrib/restricted/boost/filesystem/src/path.cpp
+++ b/contrib/restricted/boost/filesystem/src/path.cpp
@@ -1,7 +1,7 @@
// filesystem path.cpp ------------------------------------------------------------- //
// Copyright Beman Dawes 2008
-// Copyright Andrey Semashev 2021
+// Copyright Andrey Semashev 2021-2023
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
@@ -12,7 +12,7 @@
#include <boost/filesystem/config.hpp>
#include <boost/filesystem/path.hpp>
-#include <boost/filesystem/path_traits.hpp> // codecvt_error_category()
+#include <boost/filesystem/detail/path_traits.hpp> // codecvt_error_category()
#include <boost/scoped_array.hpp>
#include <boost/system/error_category.hpp> // for BOOST_SYSTEM_HAS_CONSTEXPR
#include <boost/assert.hpp>
@@ -60,7 +60,6 @@ namespace {
typedef path::value_type value_type;
typedef path::string_type string_type;
typedef string_type::size_type size_type;
-using boost::filesystem::path_detail::substring;
#ifdef BOOST_WINDOWS_API
@@ -151,110 +150,247 @@ inline void first_element(string_type const& src, size_type& element_pos, size_t
namespace boost {
namespace filesystem {
+namespace detail {
-BOOST_FILESYSTEM_DECL void path::append_v3(path const& p)
+// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier
+// standard libraries didn't, so provide this needed functionality.
+inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end)
{
- if (!p.empty())
+ for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;)
{
- if (BOOST_LIKELY(this != &p))
- {
- if (!detail::is_directory_separator(*p.m_pathname.begin()))
- append_separator_if_needed();
- m_pathname += p.m_pathname;
- }
- else
- {
- // self-append
- path rhs(p);
- append_v3(rhs);
- }
+ path_algorithms::increment_v4(it1);
+ path_algorithms::increment_v4(it2);
}
+ return std::make_pair(it1, it2);
}
-BOOST_FILESYSTEM_DECL void path::append_v3(const value_type* begin, const value_type* end)
+// normal --------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p)
{
- if (begin != end)
+ const value_type* const pathname = p.m_pathname.c_str();
+ const size_type pathname_size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ path normal(pathname, pathname + root_name_size);
+
+#if defined(BOOST_WINDOWS_API)
+ for (size_type i = 0; i < root_name_size; ++i)
+ {
+ if (normal.m_pathname[i] == path::separator)
+ normal.m_pathname[i] = path::preferred_separator;
+ }
+#endif
+
+ size_type root_path_size = root_name_size;
+ if (root_dir_pos < pathname_size)
{
- if (BOOST_LIKELY(begin < m_pathname.data() || begin >= (m_pathname.data() + m_pathname.size())))
+ root_path_size = root_dir_pos + 1;
+ normal.m_pathname.push_back(path::preferred_separator);
+ }
+
+ size_type i = root_path_size;
+
+ // Skip redundant directory separators after the root directory
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i < pathname_size)
+ {
+ bool last_element_was_dot = false;
+ while (true)
{
- if (!detail::is_directory_separator(*begin))
- append_separator_if_needed();
- m_pathname.append(begin, end);
+ {
+ const size_type start_pos = i;
+
+ // Find next separator
+ i += find_separator(pathname + i, pathname_size - i);
+
+ const size_type size = i - start_pos;
+
+ // Skip dot elements
+ if (size == 1u && pathname[start_pos] == path::dot)
+ {
+ last_element_was_dot = true;
+ goto skip_append;
+ }
+
+ last_element_was_dot = false;
+
+ // Process dot dot elements
+ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size)
+ {
+ // Don't remove previous dot dot elements
+ const size_type normal_size = normal.m_pathname.size();
+ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
+ size_type pos = normal_size - filename_size;
+ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot)
+ {
+ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
+ --pos;
+ normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end());
+ goto skip_append;
+ }
+ }
+
+ // Append the element
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.append(pathname + start_pos, size);
+ }
+
+ skip_append:
+ if (i == pathname_size)
+ break;
+
+ // Skip directory separators, including duplicates
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i == pathname_size)
+ {
+ // If a path ends with a separator, add a trailing dot element
+ goto append_trailing_dot;
+ }
}
- else
+
+ if (normal.empty() || last_element_was_dot)
{
- // overlapping source
- path rhs(begin, end);
- append_v3(rhs);
+ append_trailing_dot:
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.push_back(path::dot);
}
}
+
+ return normal;
}
-BOOST_FILESYSTEM_DECL void path::append_v4(path const& p)
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p)
{
- if (!p.empty())
- {
- if (BOOST_LIKELY(this != &p))
- {
- const size_type that_size = p.m_pathname.size();
- size_type that_root_name_size = 0;
- size_type that_root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), that_size, that_root_name_size);
+ const value_type* const pathname = p.m_pathname.c_str();
+ const size_type pathname_size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ path normal(pathname, pathname + root_name_size);
- // if (p.is_absolute())
- if
- (
-#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE)
- that_root_name_size > 0 &&
+#if defined(BOOST_WINDOWS_API)
+ for (size_type i = 0; i < root_name_size; ++i)
+ {
+ if (normal.m_pathname[i] == path::separator)
+ normal.m_pathname[i] = path::preferred_separator;
+ }
#endif
- that_root_dir_pos < that_size
- )
+
+ size_type root_path_size = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ root_path_size = root_dir_pos + 1;
+ normal.m_pathname.push_back(path::preferred_separator);
+ }
+
+ size_type i = root_path_size;
+
+ // Skip redundant directory separators after the root directory
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i < pathname_size)
+ {
+ while (true)
+ {
+ bool last_element_was_dot = false;
{
- return_assign:
- assign(p);
- return;
- }
+ const size_type start_pos = i;
- size_type this_root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), m_pathname.size(), this_root_name_size);
+ // Find next separator
+ i += find_separator(pathname + i, pathname_size - i);
- if
- (
- that_root_name_size > 0 &&
- (that_root_name_size != this_root_name_size || std::memcmp(m_pathname.c_str(), p.m_pathname.c_str(), this_root_name_size * sizeof(value_type)) != 0)
- )
+ const size_type size = i - start_pos;
+
+ // Skip dot elements
+ if (size == 1u && pathname[start_pos] == path::dot)
+ {
+ last_element_was_dot = true;
+ goto skip_append;
+ }
+
+ // Process dot dot elements
+ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size)
+ {
+ // Don't remove previous dot dot elements
+ const size_type normal_size = normal.m_pathname.size();
+ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
+ size_type pos = normal_size - filename_size;
+ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot)
+ {
+ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
+ --pos;
+ normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end());
+ goto skip_append;
+ }
+ }
+
+ // Append the element
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.append(pathname + start_pos, size);
+ }
+
+ skip_append:
+ if (i == pathname_size)
{
- goto return_assign;
+ // If a path ends with a trailing dot after a directory element, add a trailing separator
+ if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot())
+ path_algorithms::append_separator_if_needed(normal);
+
+ break;
}
- if (that_root_dir_pos < that_size)
+ // Skip directory separators, including duplicates
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i == pathname_size)
{
- // Remove root directory (if any) and relative path to replace with those from p
- m_pathname.erase(m_pathname.begin() + this_root_name_size, m_pathname.end());
+ // If a path ends with a separator, add a trailing separator
+ if (!normal.empty() && !normal.filename_is_dot_dot())
+ path_algorithms::append_separator_if_needed(normal);
+ break;
}
+ }
- const value_type* const that_path = p.m_pathname.c_str() + that_root_name_size;
- if (!detail::is_directory_separator(*that_path))
- append_separator_if_needed();
- m_pathname.append(that_path, that_size - that_root_name_size);
+ // If the original path was not empty and normalized ended up being empty, make it a dot
+ if (normal.empty())
+ normal.m_pathname.push_back(path::dot);
+ }
+
+ return normal;
+}
+
+// append --------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end)
+{
+ if (begin != end)
+ {
+ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size())))
+ {
+ if (!detail::is_directory_separator(*begin))
+ path_algorithms::append_separator_if_needed(p);
+ p.m_pathname.append(begin, end);
}
else
{
- // self-append
- path rhs(p);
- append_v4(rhs);
+ // overlapping source
+ string_type rhs(begin, end);
+ path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size());
}
}
- else if (has_filename_v4())
- {
- m_pathname.push_back(preferred_separator);
- }
}
-BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_type* end)
+BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end)
{
if (begin != end)
{
- if (BOOST_LIKELY(begin < m_pathname.data() || begin >= (m_pathname.data() + m_pathname.size())))
+ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size())))
{
const size_type that_size = end - begin;
size_type that_root_name_size = 0;
@@ -270,17 +406,17 @@ BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_
)
{
return_assign:
- assign(begin, end);
+ p.assign(begin, end);
return;
}
size_type this_root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), m_pathname.size(), this_root_name_size);
+ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size);
if
(
that_root_name_size > 0 &&
- (that_root_name_size != this_root_name_size || std::memcmp(m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0)
+ (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0)
)
{
goto return_assign;
@@ -289,197 +425,219 @@ BOOST_FILESYSTEM_DECL void path::append_v4(const value_type* begin, const value_
if (that_root_dir_pos < that_size)
{
// Remove root directory (if any) and relative path to replace with those from p
- m_pathname.erase(m_pathname.begin() + this_root_name_size, m_pathname.end());
+ p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end());
}
const value_type* const that_path = begin + that_root_name_size;
if (!detail::is_directory_separator(*that_path))
- append_separator_if_needed();
- m_pathname.append(that_path, end);
+ path_algorithms::append_separator_if_needed(p);
+ p.m_pathname.append(that_path, end);
}
else
{
// overlapping source
- path rhs(begin, end);
- append_v4(rhs);
+ string_type rhs(begin, end);
+ path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size());
}
}
- else if (has_filename_v4())
+ else if (path_algorithms::has_filename_v4(p))
{
- m_pathname.push_back(preferred_separator);
+ p.m_pathname.push_back(path::preferred_separator);
}
}
-#ifdef BOOST_WINDOWS_API
+// compare -------------------------------------------------------------------------//
-BOOST_FILESYSTEM_DECL path path::generic_path() const
+BOOST_FILESYSTEM_DECL int path_algorithms::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
+)
{
- path tmp(*this);
- std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/');
- return tmp;
+ for (; first1 != last1 && first2 != last2;)
+ {
+ if (first1->native() < first2->native())
+ return -1;
+ if (first2->native() < first1->native())
+ return 1;
+ BOOST_ASSERT(first2->native() == first1->native());
+ path_algorithms::increment_v3(first1);
+ path_algorithms::increment_v3(first2);
+ }
+ if (first1 == last1 && first2 == last2)
+ return 0;
+ return first1 == last1 ? -1 : 1;
}
-#endif // BOOST_WINDOWS_API
+BOOST_FILESYSTEM_DECL int path_algorithms::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
+)
+{
+ for (; first1 != last1 && first2 != last2;)
+ {
+ if (first1->native() < first2->native())
+ return -1;
+ if (first2->native() < first1->native())
+ return 1;
+ BOOST_ASSERT(first2->native() == first1->native());
+ path_algorithms::increment_v4(first1);
+ path_algorithms::increment_v4(first2);
+ }
+ if (first1 == last1 && first2 == last2)
+ return 0;
+ return first1 == last1 ? -1 : 1;
+}
-BOOST_FILESYSTEM_DECL int path::compare_v3(path const& p) const BOOST_NOEXCEPT
+BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right)
{
- return detail::lex_compare_v3(begin(), end(), p.begin(), p.end());
+ return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end());
}
-BOOST_FILESYSTEM_DECL int path::compare_v4(path const& p) const BOOST_NOEXCEPT
+BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right)
{
- return detail::lex_compare_v4(begin(), end(), p.begin(), p.end());
+ return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end());
}
-// append_separator_if_needed ----------------------------------------------------//
+// append_separator_if_needed ------------------------------------------------------//
-BOOST_FILESYSTEM_DECL path::string_type::size_type path::append_separator_if_needed()
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p)
{
- if (!m_pathname.empty() &&
+ if (!p.m_pathname.empty() &&
#ifdef BOOST_WINDOWS_API
- *(m_pathname.end() - 1) != colon &&
+ *(p.m_pathname.end() - 1) != colon &&
#endif
- !detail::is_directory_separator(*(m_pathname.end() - 1)))
+ !detail::is_directory_separator(*(p.m_pathname.end() - 1)))
{
- string_type::size_type tmp(m_pathname.size());
- m_pathname += preferred_separator;
+ string_type::size_type tmp(p.m_pathname.size());
+ p.m_pathname.push_back(path::preferred_separator);
return tmp;
}
return 0;
}
-// erase_redundant_separator -----------------------------------------------------//
+// erase_redundant_separator -------------------------------------------------------//
-BOOST_FILESYSTEM_DECL void path::erase_redundant_separator(string_type::size_type sep_pos)
+BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos)
{
- if (sep_pos // a separator was added
- && sep_pos < m_pathname.size() // and something was appended
- && (m_pathname[sep_pos + 1] == separator // and it was also separator
+ if (sep_pos // a separator was added
+ && sep_pos < p.m_pathname.size() // and something was appended
+ && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator
#ifdef BOOST_WINDOWS_API
- || m_pathname[sep_pos + 1] == preferred_separator // or preferred_separator
+ || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator
#endif
))
{
- m_pathname.erase(m_pathname.begin() + sep_pos); // erase the added separator
+ p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator
}
}
// modifiers -----------------------------------------------------------------------//
-#ifdef BOOST_WINDOWS_API
-BOOST_FILESYSTEM_DECL path& path::make_preferred()
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p)
{
- std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
- return *this;
+ p.remove_filename_and_trailing_separators();
}
-#endif
-BOOST_FILESYSTEM_DECL path& path::remove_filename()
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p)
{
- size_type end_pos = find_parent_path_size();
- m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end());
- return *this;
+ size_type filename_size = path_algorithms::find_filename_v4_size(p);
+ p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end());
}
-BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator()
-{
- if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1]))
- m_pathname.erase(m_pathname.end() - 1);
- return *this;
-}
-
-BOOST_FILESYSTEM_DECL void path::replace_extension_v3(path const& new_extension)
+BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension)
{
// erase existing extension, including the dot, if any
- size_type ext_pos = m_pathname.size() - extension_v3().m_pathname.size();
- m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end());
+ size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size();
+ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end());
if (!new_extension.empty())
{
// append new_extension, adding the dot if necessary
- if (new_extension.m_pathname[0] != dot)
- m_pathname.push_back(dot);
- m_pathname.append(new_extension.m_pathname);
+ if (new_extension.m_pathname[0] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
}
}
-BOOST_FILESYSTEM_DECL void path::replace_extension_v4(path const& new_extension)
+BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension)
{
// erase existing extension, including the dot, if any
- size_type ext_pos = m_pathname.size() - find_extension_v4_size();
- m_pathname.erase(m_pathname.begin() + ext_pos, m_pathname.end());
+ size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p);
+ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end());
if (!new_extension.empty())
{
// append new_extension, adding the dot if necessary
- if (new_extension.m_pathname[0] != dot)
- m_pathname.push_back(dot);
- m_pathname.append(new_extension.m_pathname);
+ if (new_extension.m_pathname[0] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
}
}
// decomposition -------------------------------------------------------------------//
-BOOST_FILESYSTEM_DECL size_type path::find_root_name_size() const
+BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p)
{
size_type root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size);
+ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
return root_name_size;
}
-BOOST_FILESYSTEM_DECL size_type path::find_root_path_size() const
+BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p)
{
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size);
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
size_type size = root_name_size;
- if (root_dir_pos < m_pathname.size())
+ if (root_dir_pos < p.m_pathname.size())
size = root_dir_pos + 1;
return size;
}
-BOOST_FILESYSTEM_DECL substring path::find_root_directory() const
+BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p)
{
substring root_dir;
size_type root_name_size = 0;
- root_dir.pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size);
- root_dir.size = static_cast< std::size_t >(root_dir.pos < m_pathname.size());
+ root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
+ root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size());
return root_dir;
}
-BOOST_FILESYSTEM_DECL substring path::find_relative_path() const
+BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p)
{
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), m_pathname.size(), root_name_size);
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
// Skip root name, root directory and any duplicate separators
size_type size = root_name_size;
- if (root_dir_pos < m_pathname.size())
+ if (root_dir_pos < p.m_pathname.size())
{
size = root_dir_pos + 1;
- for (size_type n = m_pathname.size(); size < n; ++size)
+ for (size_type n = p.m_pathname.size(); size < n; ++size)
{
- if (!detail::is_directory_separator(m_pathname[size]))
+ if (!detail::is_directory_separator(p.m_pathname[size]))
break;
}
}
substring rel_path;
rel_path.pos = size;
- rel_path.size = m_pathname.size() - size;
+ rel_path.size = p.m_pathname.size() - size;
return rel_path;
}
-BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p)
{
- const size_type size = m_pathname.size();
+ const size_type size = p.m_pathname.size();
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
- size_type filename_size = find_filename_size(m_pathname, root_name_size, size);
+ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size);
size_type end_pos = size - filename_size;
while (true)
{
@@ -493,7 +651,7 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const
--end_pos;
- if (!detail::is_directory_separator(m_pathname[end_pos]))
+ if (!detail::is_directory_separator(p.m_pathname[end_pos]))
{
++end_pos;
break;
@@ -510,13 +668,13 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_parent_path_size() const
return end_pos;
}
-BOOST_FILESYSTEM_DECL path path::filename_v3() const
+BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p)
{
- const size_type size = m_pathname.size();
+ const size_type size = p.m_pathname.size();
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
size_type filename_size, pos;
- if (root_dir_pos < size && detail::is_directory_separator(m_pathname[size - 1]) && is_root_separator(m_pathname, root_dir_pos, size - 1))
+ if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1))
{
// Return root directory
pos = root_dir_pos;
@@ -530,77 +688,77 @@ BOOST_FILESYSTEM_DECL path path::filename_v3() const
}
else
{
- filename_size = find_filename_size(m_pathname, root_name_size, size);
+ filename_size = find_filename_size(p.m_pathname, root_name_size, size);
pos = size - filename_size;
- if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(m_pathname[pos - 1]) && !is_root_separator(m_pathname, root_dir_pos, pos - 1))
+ if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1))
return detail::dot_path();
}
- const value_type* p = m_pathname.c_str() + pos;
- return path(p, p + filename_size);
+ const value_type* ptr = p.m_pathname.c_str() + pos;
+ return path(ptr, ptr + filename_size);
}
-BOOST_FILESYSTEM_DECL string_type::size_type path::find_filename_v4_size() const
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p)
{
- const size_type size = m_pathname.size();
+ const size_type size = p.m_pathname.size();
size_type root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), size, root_name_size);
- return find_filename_size(m_pathname, root_name_size, size);
+ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+ return find_filename_size(p.m_pathname, root_name_size, size);
}
-BOOST_FILESYSTEM_DECL path path::stem_v3() const
+BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p)
{
- path name(filename_v3());
- if (name != detail::dot_path() && name != detail::dot_dot_path())
+ path name(path_algorithms::filename_v3(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0)
{
- size_type pos = name.m_pathname.rfind(dot);
+ size_type pos = name.m_pathname.rfind(path::dot);
if (pos != string_type::npos)
name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end());
}
return name;
}
-BOOST_FILESYSTEM_DECL path path::stem_v4() const
+BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p)
{
- path name(filename_v4());
- if (name != detail::dot_path() && name != detail::dot_dot_path())
+ path name(path_algorithms::filename_v4(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0)
{
- size_type pos = name.m_pathname.rfind(dot);
+ size_type pos = name.m_pathname.rfind(path::dot);
if (pos != 0 && pos != string_type::npos)
name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end());
}
return name;
}
-BOOST_FILESYSTEM_DECL path path::extension_v3() const
+BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p)
{
- path name(filename_v3());
- if (name == detail::dot_path() || name == detail::dot_dot_path())
+ path name(path_algorithms::filename_v3(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0)
return path();
- size_type pos(name.m_pathname.rfind(dot));
+ size_type pos(name.m_pathname.rfind(path::dot));
return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos);
}
-BOOST_FILESYSTEM_DECL string_type::size_type path::find_extension_v4_size() const
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p)
{
- const size_type size = m_pathname.size();
+ const size_type size = p.m_pathname.size();
size_type root_name_size = 0;
- find_root_directory_start(m_pathname.c_str(), size, root_name_size);
- size_type filename_size = find_filename_size(m_pathname, root_name_size, size);
+ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size);
size_type filename_pos = size - filename_size;
if
(
filename_size > 0u &&
// Check for "." and ".." filenames
- !(m_pathname[filename_pos] == dot &&
- (filename_size == 1u || (filename_size == 2u && m_pathname[filename_pos + 1u] == dot)))
+ !(p.m_pathname[filename_pos] == path::dot &&
+ (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot)))
)
{
size_type ext_pos = size;
while (ext_pos > filename_pos)
{
--ext_pos;
- if (m_pathname[ext_pos] == dot)
+ if (p.m_pathname[ext_pos] == path::dot)
break;
}
@@ -611,21 +769,30 @@ BOOST_FILESYSTEM_DECL string_type::size_type path::find_extension_v4_size() cons
return 0u;
}
-// lexical operations --------------------------------------------------------------//
+} // namespace detail
-namespace detail {
-// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier
-// standard libraries didn't, so provide this needed functionality.
-inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end)
+BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators()
{
- for (; it1 != it1end && it2 != it2end && *it1 == *it2;)
- {
- ++it1;
- ++it2;
- }
- return std::make_pair(it1, it2);
+ size_type end_pos = detail::path_algorithms::find_parent_path_size(*this);
+ m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end());
+ return *this;
}
-} // namespace detail
+
+BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator()
+{
+ if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1]))
+ m_pathname.erase(m_pathname.end() - 1);
+ return *this;
+}
+
+BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement)
+{
+ detail::path_algorithms::remove_filename_v4(*this);
+ detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size());
+ return *this;
+}
+
+// lexical operations --------------------------------------------------------------//
BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
{
@@ -637,12 +804,12 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
return detail::dot_path();
std::ptrdiff_t n = 0;
- for (; mm.second != base_e; ++mm.second)
+ for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second))
{
path const& p = *mm.second;
- if (p == detail::dot_dot_path())
+ if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0)
--n;
- else if (!p.empty() && p != detail::dot_path())
+ else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0)
++n;
}
if (n < 0)
@@ -652,213 +819,29 @@ BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
path tmp;
for (; n > 0; --n)
- tmp /= detail::dot_dot_path();
- for (; mm.first != e; ++mm.first)
- tmp /= *mm.first;
+ detail::path_algorithms::append_v4(tmp, detail::dot_dot_path());
+ for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first))
+ detail::path_algorithms::append_v4(tmp, *mm.first);
return tmp;
}
-// normal --------------------------------------------------------------------------//
-
-BOOST_FILESYSTEM_DECL path path::lexically_normal_v3() const
-{
- const value_type* const pathname = m_pathname.c_str();
- const size_type pathname_size = m_pathname.size();
- size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
- path normal(pathname, pathname + root_name_size);
-
#if defined(BOOST_WINDOWS_API)
- for (size_type i = 0; i < root_name_size; ++i)
- {
- if (normal.m_pathname[i] == path::separator)
- normal.m_pathname[i] = path::preferred_separator;
- }
-#endif
-
- size_type root_path_size = root_name_size;
- if (root_dir_pos < pathname_size)
- {
- root_path_size = root_dir_pos + 1;
- normal.m_pathname.push_back(preferred_separator);
- }
-
- size_type i = root_path_size;
-
- // Skip redundant directory separators after the root directory
- while (i < pathname_size && detail::is_directory_separator(pathname[i]))
- ++i;
-
- if (i < pathname_size)
- {
- bool last_element_was_dot = false;
- while (true)
- {
- {
- const size_type start_pos = i;
-
- // Find next separator
- i += find_separator(pathname + i, pathname_size - i);
-
- const size_type size = i - start_pos;
-
- // Skip dot elements
- if (size == 1u && pathname[start_pos] == dot)
- {
- last_element_was_dot = true;
- goto skip_append;
- }
-
- last_element_was_dot = false;
-
- // Process dot dot elements
- if (size == 2u && pathname[start_pos] == dot && pathname[start_pos + 1] == dot && normal.m_pathname.size() > root_path_size)
- {
- // Don't remove previous dot dot elements
- const size_type normal_size = normal.m_pathname.size();
- size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
- size_type pos = normal_size - filename_size;
- if (filename_size != 2u || normal.m_pathname[pos] != dot || normal.m_pathname[pos + 1] != dot)
- {
- if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
- --pos;
- normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end());
- goto skip_append;
- }
- }
-
- // Append the element
- normal.append_separator_if_needed();
- normal.m_pathname.append(pathname + start_pos, size);
- }
-
- skip_append:
- if (i == pathname_size)
- break;
-
- // Skip directory separators, including duplicates
- while (i < pathname_size && detail::is_directory_separator(pathname[i]))
- ++i;
- if (i == pathname_size)
- {
- // If a path ends with a separator, add a trailing dot element
- goto append_trailing_dot;
- }
- }
-
- if (normal.empty() || last_element_was_dot)
- {
- append_trailing_dot:
- normal.append_separator_if_needed();
- normal.m_pathname.push_back(dot);
- }
- }
-
- return normal;
+BOOST_FILESYSTEM_DECL path path::generic_path() const
+{
+ path tmp(*this);
+ std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/');
+ return tmp;
}
-BOOST_FILESYSTEM_DECL path path::lexically_normal_v4() const
+BOOST_FILESYSTEM_DECL path& path::make_preferred()
{
- const value_type* const pathname = m_pathname.c_str();
- const size_type pathname_size = m_pathname.size();
- size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
- path normal(pathname, pathname + root_name_size);
-
-#if defined(BOOST_WINDOWS_API)
- for (size_type i = 0; i < root_name_size; ++i)
- {
- if (normal.m_pathname[i] == path::separator)
- normal.m_pathname[i] = path::preferred_separator;
- }
-#endif
-
- size_type root_path_size = root_name_size;
- if (root_dir_pos < pathname_size)
- {
- root_path_size = root_dir_pos + 1;
- normal.m_pathname.push_back(preferred_separator);
- }
-
- size_type i = root_path_size;
-
- // Skip redundant directory separators after the root directory
- while (i < pathname_size && detail::is_directory_separator(pathname[i]))
- ++i;
-
- if (i < pathname_size)
- {
- while (true)
- {
- bool last_element_was_dot = false;
- {
- const size_type start_pos = i;
-
- // Find next separator
- i += find_separator(pathname + i, pathname_size - i);
-
- const size_type size = i - start_pos;
-
- // Skip dot elements
- if (size == 1u && pathname[start_pos] == dot)
- {
- last_element_was_dot = true;
- goto skip_append;
- }
-
- // Process dot dot elements
- if (size == 2u && pathname[start_pos] == dot && pathname[start_pos + 1] == dot && normal.m_pathname.size() > root_path_size)
- {
- // Don't remove previous dot dot elements
- const size_type normal_size = normal.m_pathname.size();
- size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
- size_type pos = normal_size - filename_size;
- if (filename_size != 2u || normal.m_pathname[pos] != dot || normal.m_pathname[pos + 1] != dot)
- {
- if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
- --pos;
- normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end());
- goto skip_append;
- }
- }
-
- // Append the element
- normal.append_separator_if_needed();
- normal.m_pathname.append(pathname + start_pos, size);
- }
-
- skip_append:
- if (i == pathname_size)
- {
- // If a path ends with a trailing dot after a directory element, add a trailing separator
- if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot())
- normal.append_separator_if_needed();
-
- break;
- }
-
- // Skip directory separators, including duplicates
- while (i < pathname_size && detail::is_directory_separator(pathname[i]))
- ++i;
-
- if (i == pathname_size)
- {
- // If a path ends with a separator, add a trailing separator
- if (!normal.empty() && !normal.filename_is_dot_dot())
- normal.append_separator_if_needed();
- break;
- }
- }
-
- // If the original path was not empty and normalized ended up being empty, make it a dot
- if (normal.empty())
- normal.m_pathname.push_back(dot);
- }
-
- return normal;
+ std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
+ return *this;
}
+#endif // defined(BOOST_WINDOWS_API)
+
} // namespace filesystem
} // namespace boost
@@ -1001,7 +984,13 @@ find_next_separator:
return pos;
}
-// first_element --------------------------------------------------------------------//
+//--------------------------------------------------------------------------------------//
+// //
+// class path::iterator implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+// first_element ----------------------------------------------------------------------//
// sets pos and len of first element, excluding extra separators
// if src.empty(), sets pos,len, to 0,0.
@@ -1043,225 +1032,153 @@ namespace boost {
namespace filesystem {
namespace detail {
-BOOST_FILESYSTEM_DECL
-int lex_compare_v3(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2)
-{
- for (; first1 != last1 && first2 != last2;)
- {
- if (first1->native() < first2->native())
- return -1;
- if (first2->native() < first1->native())
- return 1;
- BOOST_ASSERT(first2->native() == first1->native());
- first1.increment_v3();
- first2.increment_v3();
- }
- if (first1 == last1 && first2 == last2)
- return 0;
- return first1 == last1 ? -1 : 1;
-}
-
-BOOST_FILESYSTEM_DECL
-int lex_compare_v4(path::iterator first1, path::iterator last1, path::iterator first2, path::iterator last2)
-{
- for (; first1 != last1 && first2 != last2;)
- {
- if (first1->native() < first2->native())
- return -1;
- if (first2->native() < first1->native())
- return 1;
- BOOST_ASSERT(first2->native() == first1->native());
- ++first1;
- ++first2;
- }
- if (first1 == last1 && first2 == last2)
- return 0;
- return first1 == last1 ? -1 : 1;
-}
-
-} // namespace detail
-
-//--------------------------------------------------------------------------------------//
-// //
-// class path::iterator implementation //
-// //
-//--------------------------------------------------------------------------------------//
-
-BOOST_FILESYSTEM_DECL path::iterator path::begin() const
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it)
{
- iterator itr;
- itr.m_path_ptr = this;
-
- size_type element_size;
- first_element(m_pathname, itr.m_pos, element_size);
-
- if (element_size > 0)
- {
- itr.m_element = m_pathname.substr(itr.m_pos, element_size);
-#ifdef BOOST_WINDOWS_API
- if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == preferred_separator)
- itr.m_element.m_pathname[0] = separator;
-#endif
- }
-
- return itr;
-}
-
-BOOST_FILESYSTEM_DECL path::iterator path::end() const
-{
- iterator itr;
- itr.m_path_ptr = this;
- itr.m_pos = m_pathname.size();
- return itr;
-}
-
-BOOST_FILESYSTEM_DECL void path::iterator::increment_v3()
-{
- const size_type size = m_path_ptr->m_pathname.size();
- BOOST_ASSERT_MSG(m_pos < size, "path::iterator increment past end()");
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()");
// increment to position past current element; if current element is implicit dot,
// this will cause m_pos to represent the end iterator
- m_pos += m_element.m_pathname.size();
+ it.m_pos += it.m_element.m_pathname.size();
// if the end is reached, we are done
- if (m_pos >= size)
+ if (it.m_pos >= size)
{
- BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified");
- m_element.clear(); // aids debugging
+ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified");
+ it.m_element.clear(); // aids debugging
return;
}
// process separator (Windows drive spec is only case not a separator)
- if (detail::is_directory_separator(m_path_ptr->m_pathname[m_pos]))
+ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
{
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
// detect root directory and set iterator value to the separator if it is
- if (m_pos == root_dir_pos && m_element.m_pathname.size() == root_name_size)
+ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
{
- m_element.m_pathname = separator; // generic format; see docs
+ it.m_element.m_pathname = path::separator; // generic format; see docs
return;
}
// skip separators until m_pos points to the start of the next element
- while (m_pos != size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos]))
+ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
{
- ++m_pos;
+ ++it.m_pos;
}
// detect trailing separator, and treat it as ".", per POSIX spec
- if (m_pos == size &&
- !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1))
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
{
- --m_pos;
- m_element = detail::dot_path();
+ --it.m_pos;
+ it.m_element = detail::dot_path();
return;
}
}
// get m_element
- size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, m_pos);
+ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos);
if (end_pos == string_type::npos)
end_pos = size;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p + m_pos, p + end_pos);
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
}
-BOOST_FILESYSTEM_DECL void path::iterator::increment_v4()
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it)
{
- const size_type size = m_path_ptr->m_pathname.size();
- BOOST_ASSERT_MSG(m_pos <= size, "path::iterator increment past end()");
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()");
- if (m_element.m_pathname.empty() && (m_pos + 1) == size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos]))
+ if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
{
// The iterator was pointing to the last empty element of the path; set to end.
- m_pos = size;
+ it.m_pos = size;
return;
}
// increment to position past current element; if current element is implicit dot,
// this will cause m_pos to represent the end iterator
- m_pos += m_element.m_pathname.size();
+ it.m_pos += it.m_element.m_pathname.size();
// if the end is reached, we are done
- if (m_pos >= size)
+ if (it.m_pos >= size)
{
- BOOST_ASSERT_MSG(m_pos == size, "path::iterator increment after the referenced path was modified");
- m_element.clear(); // aids debugging
+ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified");
+ it.m_element.clear(); // aids debugging
return;
}
// process separator (Windows drive spec is only case not a separator)
- if (detail::is_directory_separator(m_path_ptr->m_pathname[m_pos]))
+ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
{
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
// detect root directory and set iterator value to the separator if it is
- if (m_pos == root_dir_pos && m_element.m_pathname.size() == root_name_size)
+ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
{
- m_element.m_pathname = separator; // generic format; see docs
+ it.m_element.m_pathname = path::separator; // generic format; see docs
return;
}
// skip separators until m_pos points to the start of the next element
- while (m_pos != size && detail::is_directory_separator(m_path_ptr->m_pathname[m_pos]))
+ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
{
- ++m_pos;
+ ++it.m_pos;
}
// detect trailing separator
- if (m_pos == size &&
- !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1))
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
{
- --m_pos;
- m_element.m_pathname.clear();
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
return;
}
}
// get m_element
- size_type end_pos = m_path_ptr->m_pathname.find_first_of(separators, m_pos);
+ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos);
if (end_pos == string_type::npos)
end_pos = size;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p + m_pos, p + end_pos);
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
}
-BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3()
+BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it)
{
- const size_type size = m_path_ptr->m_pathname.size();
- BOOST_ASSERT_MSG(m_pos > 0, "path::iterator decrement past begin()");
- BOOST_ASSERT_MSG(m_pos <= size, "path::iterator decrement after the referenced path was modified");
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()");
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified");
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
- if (root_dir_pos < size && m_pos == root_dir_pos)
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
{
// Was pointing at root directory, decrement to root name
set_to_root_name:
- m_pos = 0u;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p, p + root_name_size);
+ it.m_pos = 0u;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p, p + root_name_size);
return;
}
// if at end and there was a trailing non-root '/', return "."
- if (m_pos == size &&
+ if (it.m_pos == size &&
size > 1 &&
- detail::is_directory_separator(m_path_ptr->m_pathname[m_pos - 1]) &&
- !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1))
+ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
{
- --m_pos;
- m_element = detail::dot_path();
+ --it.m_pos;
+ it.m_element = detail::dot_path();
return;
}
// skip separators unless root directory
- size_type end_pos = m_pos;
+ size_type end_pos = it.m_pos;
while (end_pos > root_name_size)
{
--end_pos;
@@ -1269,12 +1186,12 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3()
if (end_pos == root_dir_pos)
{
// Decremented to the root directory
- m_pos = end_pos;
- m_element.m_pathname = separator; // generic format; see docs
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
return;
}
- if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos]))
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
{
++end_pos;
break;
@@ -1284,44 +1201,44 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v3()
if (end_pos <= root_name_size)
goto set_to_root_name;
- size_type filename_size = find_filename_size(m_path_ptr->m_pathname, root_name_size, end_pos);
- m_pos = end_pos - filename_size;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p + m_pos, p + end_pos);
+ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos);
+ it.m_pos = end_pos - filename_size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
}
-BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4()
+BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it)
{
- const size_type size = m_path_ptr->m_pathname.size();
- BOOST_ASSERT_MSG(m_pos > 0, "path::iterator decrement past begin()");
- BOOST_ASSERT_MSG(m_pos <= size, "path::iterator decrement after the referenced path was modified");
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()");
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified");
size_type root_name_size = 0;
- size_type root_dir_pos = find_root_directory_start(m_path_ptr->m_pathname.c_str(), size, root_name_size);
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
- if (root_dir_pos < size && m_pos == root_dir_pos)
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
{
// Was pointing at root directory, decrement to root name
set_to_root_name:
- m_pos = 0u;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p, p + root_name_size);
+ it.m_pos = 0u;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p, p + root_name_size);
return;
}
// if at end and there was a trailing '/', return ""
- if (m_pos == size &&
+ if (it.m_pos == size &&
size > 1 &&
- detail::is_directory_separator(m_path_ptr->m_pathname[m_pos - 1]) &&
- !is_root_separator(m_path_ptr->m_pathname, root_dir_pos, m_pos - 1))
+ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
{
- --m_pos;
- m_element.m_pathname.clear();
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
return;
}
// skip separators unless root directory
- size_type end_pos = m_pos;
+ size_type end_pos = it.m_pos;
while (end_pos > root_name_size)
{
--end_pos;
@@ -1329,12 +1246,12 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4()
if (end_pos == root_dir_pos)
{
// Decremented to the root directory
- m_pos = end_pos;
- m_element.m_pathname = separator; // generic format; see docs
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
return;
}
- if (!detail::is_directory_separator(m_path_ptr->m_pathname[end_pos]))
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
{
++end_pos;
break;
@@ -1344,10 +1261,42 @@ BOOST_FILESYSTEM_DECL void path::iterator::decrement_v4()
if (end_pos <= root_name_size)
goto set_to_root_name;
- size_type filename_size = find_filename_size(m_path_ptr->m_pathname, root_name_size, end_pos);
- m_pos = end_pos - filename_size;
- const path::value_type* p = m_path_ptr->m_pathname.c_str();
- m_element.m_pathname.assign(p + m_pos, p + end_pos);
+ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos);
+ it.m_pos = end_pos - filename_size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
+}
+
+} // namespace detail
+
+// path iterators ------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path::iterator path::begin() const
+{
+ iterator itr;
+ itr.m_path_ptr = this;
+
+ size_type element_size;
+ first_element(m_pathname, itr.m_pos, element_size);
+
+ if (element_size > 0)
+ {
+ itr.m_element = m_pathname.substr(itr.m_pos, element_size);
+#ifdef BOOST_WINDOWS_API
+ if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator)
+ itr.m_element.m_pathname[0] = path::separator;
+#endif
+ }
+
+ return itr;
+}
+
+BOOST_FILESYSTEM_DECL path::iterator path::end() const
+{
+ iterator itr;
+ itr.m_path_ptr = this;
+ itr.m_pos = m_pathname.size();
+ return itr;
}
} // namespace filesystem
diff --git a/contrib/restricted/boost/filesystem/src/path_traits.cpp b/contrib/restricted/boost/filesystem/src/path_traits.cpp
index aa4b8815f7..baed387b4d 100644
--- a/contrib/restricted/boost/filesystem/src/path_traits.cpp
+++ b/contrib/restricted/boost/filesystem/src/path_traits.cpp
@@ -12,19 +12,19 @@
#include "platform_config.hpp"
#include <boost/filesystem/config.hpp>
-#include <boost/filesystem/path_traits.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
+#include <boost/filesystem/path.hpp>
#include <boost/system/system_error.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
#include <boost/assert.hpp>
#include <string>
#include <locale> // for codecvt_base::result
-#include <cstring> // for strlen
-#include <cwchar> // for wcslen
+#include <cwchar> // for mbstate_t
#include <cstddef>
#include <boost/filesystem/detail/header.hpp> // must be the last #include
-namespace pt = boost::filesystem::path_traits;
+namespace pt = boost::filesystem::detail::path_traits;
namespace fs = boost::filesystem;
namespace bs = boost::system;
@@ -51,12 +51,7 @@ BOOST_CONSTEXPR_OR_CONST std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM
// convert_aux const char* to wstring //
//--------------------------------------------------------------------------------------//
-void convert_aux(
- const char* from,
- const char* from_end,
- wchar_t* to, wchar_t* to_end,
- std::wstring& target,
- pt::codecvt_type const& cvt)
+void convert_aux(const char* from, const char* from_end, wchar_t* to, wchar_t* to_end, std::wstring& target, pt::codecvt_type const& cvt)
{
//std::cout << std::hex
// << " from=" << std::size_t(from)
@@ -83,12 +78,7 @@ void convert_aux(
// convert_aux const wchar_t* to string //
//--------------------------------------------------------------------------------------//
-void convert_aux(
- const wchar_t* from,
- const wchar_t* from_end,
- char* to, char* to_end,
- std::string& target,
- pt::codecvt_type const& cvt)
+void convert_aux(const wchar_t* from, const wchar_t* from_end, char* to, char* to_end, std::string& target, pt::codecvt_type const& cvt)
{
//std::cout << std::hex
// << " from=" << std::size_t(from)
@@ -119,6 +109,7 @@ void convert_aux(
namespace boost {
namespace filesystem {
+namespace detail {
namespace path_traits {
//--------------------------------------------------------------------------------------//
@@ -126,32 +117,29 @@ namespace path_traits {
//--------------------------------------------------------------------------------------//
BOOST_FILESYSTEM_DECL
-void convert(const char* from,
- const char* from_end, // 0 for null terminated MBCS
- std::wstring& to, codecvt_type const& cvt)
+void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt)
{
- BOOST_ASSERT(from);
-
- if (!from_end) // null terminated
- {
- from_end = from + std::strlen(from);
- }
-
if (from == from_end)
return;
+ BOOST_ASSERT(from != NULL);
+ BOOST_ASSERT(from_end != NULL);
+
+ if (!cvt)
+ cvt = &fs::path::codecvt();
+
std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK
// dynamically allocate a buffer only if source is unusually large
if (buf_size > default_codecvt_buf_size)
{
boost::scoped_array< wchar_t > buf(new wchar_t[buf_size]);
- convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, cvt);
+ convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt);
}
else
{
wchar_t buf[default_codecvt_buf_size];
- convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, cvt);
+ convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt);
}
}
@@ -160,20 +148,17 @@ void convert(const char* from,
//--------------------------------------------------------------------------------------//
BOOST_FILESYSTEM_DECL
-void convert(const wchar_t* from,
- const wchar_t* from_end, // 0 for null terminated MBCS
- std::string& to, codecvt_type const& cvt)
+void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt)
{
- BOOST_ASSERT(from);
-
- if (!from_end) // null terminated
- {
- from_end = from + std::wcslen(from);
- }
-
if (from == from_end)
return;
+ BOOST_ASSERT(from != NULL);
+ BOOST_ASSERT(from_end != NULL);
+
+ if (!cvt)
+ cvt = &fs::path::codecvt();
+
// The codecvt length functions may not be implemented, and I don't really
// understand them either. Thus this code is just a guess; if it turns
// out the buffer is too small then an error will be reported and the code
@@ -185,16 +170,17 @@ void convert(const wchar_t* from,
if (buf_size > default_codecvt_buf_size)
{
boost::scoped_array< char > buf(new char[buf_size]);
- convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, cvt);
+ convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt);
}
else
{
char buf[default_codecvt_buf_size];
- convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, cvt);
+ convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt);
}
}
} // namespace path_traits
+} // namespace detail
} // namespace filesystem
} // namespace boost
diff --git a/contrib/restricted/boost/filesystem/src/windows_tools.hpp b/contrib/restricted/boost/filesystem/src/windows_tools.hpp
index 8a2de7f0c9..ca62bfbf7e 100644
--- a/contrib/restricted/boost/filesystem/src/windows_tools.hpp
+++ b/contrib/restricted/boost/filesystem/src/windows_tools.hpp
@@ -1,7 +1,8 @@
// windows_tools.hpp -----------------------------------------------------------------//
-// Copyright 2002-2009, 2014 Beman Dawes
// Copyright 2001 Dietmar Kuehl
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2021-2022 Andrey Semashev
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
@@ -23,6 +24,10 @@
#include <boost/filesystem/detail/header.hpp> // must be the last #include
+#ifndef IO_REPARSE_TAG_DEDUP
+#define IO_REPARSE_TAG_DEDUP (0x80000013L)
+#endif
+
#ifndef IO_REPARSE_TAG_MOUNT_POINT
#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
#endif
@@ -57,14 +62,14 @@ 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;
if ((attr & FILE_ATTRIBUTE_READONLY) == 0u)
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();
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;
return prms;
}
-bool is_reparse_point_a_symlink_ioctl(HANDLE h);
+ULONG get_reparse_point_tag_ioctl(HANDLE h, boost::filesystem::path const& p, boost::system::error_code* ec);
inline bool is_reparse_point_tag_a_symlink(ULONG reparse_point_tag)
{
@@ -156,6 +161,9 @@ struct object_attributes
#ifndef FILE_DIRECTORY_FILE
#define FILE_DIRECTORY_FILE 0x00000001
#endif
+#ifndef FILE_SYNCHRONOUS_IO_NONALERT
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+#endif
#ifndef FILE_OPEN_FOR_BACKUP_INTENT
#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
#endif