aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/filesystem/src/directory.cpp
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/directory.cpp
parent1f6bef05ed441c3aa2d565ac792b26cded704ac7 (diff)
downloadydb-d67bfb4b4b7549081543e87a31bc6cb5c46ac973.tar.gz
Import libs 4 (#758)
Diffstat (limited to 'contrib/restricted/boost/filesystem/src/directory.cpp')
-rw-r--r--contrib/restricted/boost/filesystem/src/directory.cpp209
1 files changed, 112 insertions, 97 deletions
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)())))