mirror of
https://github.com/boostorg/filesystem.git
synced 2025-05-12 13:41:47 +00:00
Reworked directory iterator construction with parameters.
Instead of passing a base directory fd, pass the directory fd to iterate over. This simplifies code a little and makes it closer to Windows version. Also, use unique_fd from Boost.Scope instead of a custom fd wrapper. Also added handling of EINTR returned from open/openat in more places.
This commit is contained in:
parent
9f6bf1a433
commit
e9621c0585
@ -239,6 +239,7 @@ target_link_libraries(boost_filesystem
|
||||
|
||||
PRIVATE
|
||||
Boost::predef
|
||||
Boost::scope
|
||||
)
|
||||
|
||||
if(NOT BOOST_FILESYSTEM_HAS_CXX20_ATOMIC_REF)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
// Copyright 2002-2009, 2014 Beman Dawes
|
||||
// Copyright 2001 Dietmar Kuehl
|
||||
// Copyright 2019, 2022 Andrey Semashev
|
||||
// Copyright 2019, 2022-2024 Andrey Semashev
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See http://www.boost.org/LICENSE_1_0.txt
|
||||
@ -40,6 +40,8 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <boost/scope/unique_fd.hpp>
|
||||
|
||||
#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS >= 0) && defined(_SC_THREAD_SAFE_FUNCTIONS) && \
|
||||
!defined(__CYGWIN__) && \
|
||||
!(defined(linux) || defined(__linux) || defined(__linux__)) && \
|
||||
@ -123,6 +125,104 @@ BOOST_FILESYSTEM_DECL void directory_entry::refresh_impl(system::error_code* ec)
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
|
||||
//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
|
||||
boost::scope::unique_fd open_directory(path const& p, directory_options opts, system::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC;
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
if ((opts & directory_options::_detail_no_follow) != directory_options::none)
|
||||
flags |= O_NOFOLLOW;
|
||||
#endif
|
||||
|
||||
int res;
|
||||
while (true)
|
||||
{
|
||||
res = ::open(p.c_str(), flags);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
const int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
ec = system::error_code(err, system::system_category());
|
||||
return boost::scope::unique_fd();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
|
||||
boost::scope::unique_fd fd(res);
|
||||
|
||||
res = ::fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
const int err = errno;
|
||||
ec = system::error_code(err, system::system_category());
|
||||
return boost::scope::unique_fd();
|
||||
}
|
||||
|
||||
return fd;
|
||||
#else
|
||||
return boost::scope::unique_fd(res);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
|
||||
//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
|
||||
boost::scope::unique_fd openat_directory(int basedir_fd, path const& p, directory_options opts, system::error_code& ec)
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC;
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
if ((opts & directory_options::_detail_no_follow) != directory_options::none)
|
||||
flags |= O_NOFOLLOW;
|
||||
#endif
|
||||
|
||||
int res;
|
||||
while (true)
|
||||
{
|
||||
res = ::openat(basedir_fd, p.c_str(), flags);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
const int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
ec = system::error_code(err, system::system_category());
|
||||
return boost::scope::unique_fd();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
|
||||
boost::scope::unique_fd fd(res);
|
||||
|
||||
res = ::fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
const int err = errno;
|
||||
ec = system::error_code(err, system::system_category());
|
||||
return boost::scope::unique_fd();
|
||||
}
|
||||
|
||||
return fd;
|
||||
#else
|
||||
return boost::scope::unique_fd(res);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
|
||||
#endif // defined(BOOST_POSIX_API)
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_imp_extra_data_alignment = 16u;
|
||||
|
||||
BOOST_FILESYSTEM_DECL void* dir_itr_imp::operator new(std::size_t class_size, std::size_t extra_size) noexcept
|
||||
@ -168,7 +268,7 @@ inline system::error_code dir_itr_close(dir_itr_imp& imp) noexcept
|
||||
if (BOOST_UNLIKELY(::closedir(h) != 0))
|
||||
{
|
||||
err = errno;
|
||||
return error_code(err, system_category());
|
||||
return system::error_code(err, system::system_category());
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,12 +408,12 @@ inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result)
|
||||
|
||||
#endif // !defined(BOOST_FILESYSTEM_USE_READDIR_R)
|
||||
|
||||
error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
|
||||
system::error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
|
||||
{
|
||||
dirent* result = nullptr;
|
||||
int err = invoke_readdir(imp, &result);
|
||||
if (BOOST_UNLIKELY(err != 0))
|
||||
return error_code(err, system_category());
|
||||
return system::error_code(err, system::system_category());
|
||||
if (result == nullptr)
|
||||
return dir_itr_close(imp);
|
||||
|
||||
@ -360,10 +460,10 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
#else
|
||||
sf = symlink_sf = fs::file_status(fs::status_error);
|
||||
#endif
|
||||
return error_code();
|
||||
return system::error_code();
|
||||
}
|
||||
|
||||
error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status&, fs::file_status&)
|
||||
system::error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status&, fs::file_status&)
|
||||
{
|
||||
std::size_t extra_size = 0u;
|
||||
#if defined(BOOST_FILESYSTEM_USE_READDIR_R)
|
||||
@ -392,57 +492,42 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
return make_error_code(system::errc::not_enough_memory);
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC;
|
||||
if ((opts & directory_options::_detail_no_follow) != directory_options::none)
|
||||
flags |= O_NOFOLLOW;
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
int fd = ::openat(params ? params->basedir_fd : AT_FDCWD, dir.c_str(), flags);
|
||||
#else
|
||||
int fd = ::open(dir.c_str(), flags);
|
||||
#endif
|
||||
if (BOOST_UNLIKELY(fd < 0))
|
||||
boost::scope::unique_fd fd;
|
||||
if (params && params->dir_fd)
|
||||
{
|
||||
const int err = errno;
|
||||
return error_code(err, system_category());
|
||||
fd = std::move(params->dir_fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
system::error_code ec;
|
||||
fd = open_directory(dir, opts, ec);
|
||||
if (BOOST_UNLIKELY(!!ec))
|
||||
return ec;
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
|
||||
int res = ::fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
const int err = errno;
|
||||
close_fd(fd);
|
||||
return error_code(err, system_category());
|
||||
}
|
||||
#endif
|
||||
|
||||
pimpl->handle = ::fdopendir(fd);
|
||||
pimpl->handle = ::fdopendir(fd.get());
|
||||
if (BOOST_UNLIKELY(!pimpl->handle))
|
||||
{
|
||||
const int err = errno;
|
||||
close_fd(fd);
|
||||
return error_code(err, system_category());
|
||||
return system::error_code(err, system::system_category());
|
||||
}
|
||||
|
||||
// At this point fd will be closed by closedir
|
||||
fd.release();
|
||||
#else // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
pimpl->handle = ::opendir(dir.c_str());
|
||||
if (BOOST_UNLIKELY(!pimpl->handle))
|
||||
{
|
||||
const int err = errno;
|
||||
return error_code(err, system_category());
|
||||
return system::error_code(err, system::system_category());
|
||||
}
|
||||
#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
|
||||
// Force initial readdir call by the caller. This will initialize the actual first filename and statuses.
|
||||
first_filename.assign(".");
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
if (params)
|
||||
params->iterator_fd = fd;
|
||||
#endif
|
||||
|
||||
imp.swap(pimpl);
|
||||
return error_code();
|
||||
return system::error_code();
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ENOENT;
|
||||
@ -604,7 +689,7 @@ inline system::error_code dir_itr_close(dir_itr_imp& imp) noexcept
|
||||
return error_code();
|
||||
}
|
||||
|
||||
error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
|
||||
system::error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
|
||||
{
|
||||
void* extra_data = get_dir_itr_imp_extra_data(&imp);
|
||||
const void* current_data = static_cast< const unsigned char* >(extra_data) + imp.current_offset;
|
||||
@ -623,7 +708,7 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
if (error == ERROR_NO_MORE_FILES)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
imp.current_offset = 0u;
|
||||
@ -653,7 +738,7 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
if (error == ERROR_NO_MORE_FILES)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
imp.current_offset = 0u;
|
||||
@ -683,7 +768,7 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
if (error == ERROR_NO_MORE_FILES)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
imp.current_offset = 0u;
|
||||
@ -727,7 +812,7 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
if (status == STATUS_NO_MORE_FILES)
|
||||
goto done;
|
||||
|
||||
return error_code(translate_ntstatus(status), system_category());
|
||||
return system::error_code(translate_ntstatus(status), system::system_category());
|
||||
}
|
||||
|
||||
imp.current_offset = 0u;
|
||||
@ -746,7 +831,7 @@ error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_stat
|
||||
}
|
||||
|
||||
done:
|
||||
return error_code();
|
||||
return system::error_code();
|
||||
}
|
||||
|
||||
//! Returns \c true if the error code indicates that the OS or the filesystem does not support a particular directory info class
|
||||
@ -771,7 +856,7 @@ inline bool is_dir_info_class_not_supported(DWORD error)
|
||||
error == ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf)
|
||||
system::error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options 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());
|
||||
if (BOOST_UNLIKELY(!pimpl))
|
||||
@ -799,7 +884,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
{
|
||||
return_last_error:
|
||||
DWORD error = ::GetLastError();
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
if (BOOST_LIKELY(get_file_information_by_handle_ex != nullptr))
|
||||
@ -813,7 +898,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
if (error == ERROR_INVALID_PARAMETER || error == ERROR_NOT_SUPPORTED)
|
||||
goto use_get_file_information_by_handle;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
if (BOOST_UNLIKELY((info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u))
|
||||
@ -869,7 +954,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
pimpl->extra_data_format = file_id_extd_dir_info_format;
|
||||
@ -899,7 +984,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
pimpl->extra_data_format = file_full_dir_info_format;
|
||||
@ -929,7 +1014,7 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
|
||||
goto done;
|
||||
|
||||
return error_code(error, system_category());
|
||||
return system::error_code(error, system::system_category());
|
||||
}
|
||||
|
||||
pimpl->extra_data_format = file_id_both_dir_info_format;
|
||||
@ -986,14 +1071,13 @@ error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
pimpl->handle = iterator_handle;
|
||||
h.handle = INVALID_HANDLE_VALUE;
|
||||
pimpl->close_handle = close_handle;
|
||||
|
||||
done:
|
||||
imp.swap(pimpl);
|
||||
return error_code();
|
||||
return system::error_code();
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ERROR_PATH_NOT_FOUND;
|
||||
@ -1026,6 +1110,9 @@ dir_itr_imp::~dir_itr_imp() noexcept
|
||||
BOOST_FILESYSTEM_DECL
|
||||
void directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, directory_iterator_params* params, system::error_code* ec)
|
||||
{
|
||||
// At most one of the two options may be specified, and follow_directory_symlink is ignored for directory_iterator.
|
||||
BOOST_ASSERT((opts & (directory_options::follow_directory_symlink | directory_options::_detail_no_follow)) != (directory_options::follow_directory_symlink | directory_options::_detail_no_follow));
|
||||
|
||||
if (BOOST_UNLIKELY(p.empty()))
|
||||
{
|
||||
emit_error(not_found_error_code, p, ec, "boost::filesystem::directory_iterator::construct");
|
||||
@ -1037,21 +1124,6 @@ void directory_iterator_construct(directory_iterator& it, path const& p, directo
|
||||
|
||||
try
|
||||
{
|
||||
#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
path dir_path;
|
||||
if (params)
|
||||
{
|
||||
dir_path = params->basedir;
|
||||
path_algorithms::append_v4(dir_path, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir_path = p;
|
||||
}
|
||||
#else
|
||||
path const& dir_path = p;
|
||||
#endif
|
||||
|
||||
boost::intrusive_ptr< detail::dir_itr_imp > imp;
|
||||
path filename;
|
||||
file_status file_stat, symlink_file_stat;
|
||||
@ -1081,7 +1153,7 @@ void directory_iterator_construct(directory_iterator& it, path const& p, directo
|
||||
&& (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')))))
|
||||
{
|
||||
path full_path(dir_path);
|
||||
path full_path(p);
|
||||
path_algorithms::append_v4(full_path, filename);
|
||||
imp->dir_entry.assign_with_status
|
||||
(
|
||||
@ -1172,6 +1244,9 @@ void directory_iterator_increment(directory_iterator& it, system::error_code* ec
|
||||
BOOST_FILESYSTEM_DECL
|
||||
void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec)
|
||||
{
|
||||
// At most one of the two options may be specified
|
||||
BOOST_ASSERT((opts & (directory_options::follow_directory_symlink | directory_options::_detail_no_follow)) != (directory_options::follow_directory_symlink | directory_options::_detail_no_follow));
|
||||
|
||||
if (ec)
|
||||
ec->clear();
|
||||
|
||||
@ -1400,6 +1475,11 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
{
|
||||
directory_iterator const& dir_it = imp->m_stack.back();
|
||||
|
||||
// Don't query the file type from the filesystem yet, if not known. We will use dir_it for that below.
|
||||
file_type ft = dir_it->m_status.type();
|
||||
if (ft != status_error && ft != directory_file)
|
||||
return result;
|
||||
|
||||
#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
if (parentdir_fd < 0)
|
||||
{
|
||||
@ -1410,12 +1490,28 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
dir_it_filename = detail::path_algorithms::filename_v4(dir_it->path());
|
||||
}
|
||||
|
||||
file_type ft = status_error;
|
||||
if (filesystem::type_present(dir_it->m_status))
|
||||
ft = dir_it->m_status.type();
|
||||
else
|
||||
ft = detail::status_impl(dir_it_filename, &ec, parentdir_fd).type();
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
// Try to open the file as a directory right away. This effectively tests whether the file is a directory, and, if it is, opens the directory in one system call.
|
||||
detail::directory_iterator_params params{ detail::openat_directory(parentdir_fd, dir_it_filename, imp->m_options, ec) };
|
||||
if (!!ec)
|
||||
{
|
||||
if
|
||||
(
|
||||
// Skip non-directory files
|
||||
ec == system::error_code(ENOTDIR, system::system_category()) ||
|
||||
(
|
||||
// Skip dangling symlink, if requested by options
|
||||
ec == system::error_code(ENOENT, system::system_category()) && symlink_ft == symlink_file &&
|
||||
(imp->m_options & (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)
|
||||
)
|
||||
)
|
||||
{
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else // defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
if (direntry_handle.handle != INVALID_HANDLE_VALUE && symlink_ft == symlink_file)
|
||||
{
|
||||
// Close the symlink to reopen the target file below
|
||||
@ -1423,7 +1519,6 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
direntry_handle.handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
file_type ft = symlink_ft;
|
||||
if (direntry_handle.handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
boost::winapi::NTSTATUS_ status = nt_create_file_handle_at
|
||||
@ -1440,7 +1535,7 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
ft = detail::status_by_handle(direntry_handle.handle, dir_it->path(), &ec).type();
|
||||
goto get_file_type_by_handle;
|
||||
}
|
||||
else if (status == STATUS_NOT_IMPLEMENTED)
|
||||
{
|
||||
@ -1451,9 +1546,16 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
ec.assign(translate_ntstatus(status), system::system_category());
|
||||
}
|
||||
}
|
||||
#else
|
||||
file_type ft = dir_it->file_type(ec);
|
||||
#endif
|
||||
else
|
||||
{
|
||||
get_file_type_by_handle:
|
||||
ft = detail::status_by_handle(direntry_handle.handle, dir_it->path(), &ec).type();
|
||||
}
|
||||
#else // defined(BOOST_WINDOWS_API)
|
||||
if (ft == status_error)
|
||||
ft = dir_it->file_type(ec);
|
||||
#endif // defined(BOOST_WINDOWS_API)
|
||||
|
||||
if (BOOST_UNLIKELY(!!ec))
|
||||
{
|
||||
if (ec == make_error_condition(system::errc::no_such_file_or_directory) && symlink_ft == symlink_file &&
|
||||
@ -1468,6 +1570,7 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
|
||||
if (ft != directory_file)
|
||||
return result;
|
||||
#endif // defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
|
||||
if (BOOST_UNLIKELY((imp->m_stack.size() - 1u) >= static_cast< std::size_t >((std::numeric_limits< int >::max)())))
|
||||
{
|
||||
@ -1480,25 +1583,22 @@ void recursive_directory_iterator_increment(recursive_directory_iterator& it, sy
|
||||
}
|
||||
|
||||
#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
detail::directory_iterator_params params;
|
||||
params.basedir = dir_it->path().parent_path();
|
||||
params.basedir_fd = parentdir_fd;
|
||||
params.iterator_fd = -1;
|
||||
directory_iterator next;
|
||||
detail::directory_iterator_construct(next, dir_it_filename, imp->m_options, ¶ms, &ec);
|
||||
detail::directory_iterator_construct(next, dir_it->path(), imp->m_options, ¶ms, &ec);
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
detail::directory_iterator_params params;
|
||||
params.dir_handle = direntry_handle.handle;
|
||||
params.close_handle = true;
|
||||
directory_iterator next;
|
||||
detail::directory_iterator_construct(next, dir_it->path(), imp->m_options, ¶ms, &ec);
|
||||
if (BOOST_LIKELY(!ec))
|
||||
direntry_handle.handle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
directory_iterator next(dir_it->path(), imp->m_options, ec);
|
||||
#endif
|
||||
if (BOOST_LIKELY(!ec))
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
direntry_handle.handle = INVALID_HANDLE_VALUE;
|
||||
#endif
|
||||
if (!next.is_end())
|
||||
{
|
||||
imp->m_stack.push_back(std::move(next)); // may throw
|
||||
|
@ -118,6 +118,8 @@
|
||||
|
||||
#endif // defined(linux) || defined(__linux) || defined(__linux__)
|
||||
|
||||
#include <boost/scope/unique_fd.hpp>
|
||||
|
||||
#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21)
|
||||
#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE
|
||||
#endif
|
||||
@ -305,26 +307,45 @@ bool not_found_error(int errval) noexcept; // forward declaration
|
||||
// //
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
struct fd_wrapper
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd_wrapper() noexcept : fd(-1) {}
|
||||
explicit fd_wrapper(int fd) noexcept : fd(fd) {}
|
||||
~fd_wrapper() noexcept
|
||||
{
|
||||
if (fd >= 0)
|
||||
close_fd(fd);
|
||||
}
|
||||
fd_wrapper(fd_wrapper const&) = delete;
|
||||
fd_wrapper& operator=(fd_wrapper const&) = delete;
|
||||
};
|
||||
|
||||
inline bool not_found_error(int errval) noexcept
|
||||
{
|
||||
return errval == ENOENT || errval == ENOTDIR;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Closes a file descriptor and returns the result, similar to close(2). Unlike close(2), guarantees that the file descriptor is closed even if EINTR error happens.
|
||||
*
|
||||
* Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR.
|
||||
* Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it
|
||||
* again could close a different file descriptor that was opened by a different thread. This function hides this difference in behavior.
|
||||
*
|
||||
* Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529)
|
||||
* and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2)
|
||||
* behaves differently between systems.
|
||||
*/
|
||||
inline int close_fd(int fd)
|
||||
{
|
||||
#if defined(hpux) || defined(_hpux) || defined(__hpux)
|
||||
int res;
|
||||
while (true)
|
||||
{
|
||||
res = ::close(fd);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
return ::close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_STATX)
|
||||
|
||||
//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't
|
||||
@ -1108,19 +1129,12 @@ uintmax_t remove_all_impl
|
||||
)
|
||||
{
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
fs::detail::directory_iterator_params params;
|
||||
params.basedir_fd = parentdir_fd;
|
||||
params.iterator_fd = -1;
|
||||
|
||||
fs::path remove_path;
|
||||
fs::path filename;
|
||||
const fs::path* remove_path = &p;
|
||||
if (parentdir_fd != AT_FDCWD)
|
||||
{
|
||||
params.basedir = p.parent_path();
|
||||
remove_path = path_algorithms::filename_v4(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
remove_path = p;
|
||||
filename = path_algorithms::filename_v4(p);
|
||||
remove_path = &filename;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1131,7 +1145,7 @@ uintmax_t remove_all_impl
|
||||
{
|
||||
error_code local_ec;
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
type = fs::detail::symlink_status_impl(remove_path, &local_ec, parentdir_fd).type();
|
||||
type = fs::detail::symlink_status_impl(*remove_path, &local_ec, parentdir_fd).type();
|
||||
#else
|
||||
type = fs::detail::symlink_status_impl(p, &local_ec).type();
|
||||
#endif
|
||||
@ -1154,9 +1168,27 @@ uintmax_t remove_all_impl
|
||||
{
|
||||
fs::directory_iterator itr;
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
fs::detail::directory_iterator_construct(itr, remove_path, directory_options::_detail_no_follow, ¶ms, &dit_create_ec);
|
||||
fs::detail::directory_iterator_params params{ fs::detail::openat_directory(parentdir_fd, *remove_path, directory_options::_detail_no_follow, dit_create_ec) };
|
||||
int dir_fd = -1;
|
||||
if (BOOST_LIKELY(!dit_create_ec))
|
||||
{
|
||||
// Save dir_fd as constructing the iterator will move the fd into the iterator context
|
||||
dir_fd = params.dir_fd.get();
|
||||
fs::detail::directory_iterator_construct(itr, *remove_path, directory_options::_detail_no_follow, ¶ms, &dit_create_ec);
|
||||
}
|
||||
#else
|
||||
fs::detail::directory_iterator_construct(itr, p, directory_options::_detail_no_follow, nullptr, &dit_create_ec);
|
||||
fs::detail::directory_iterator_construct
|
||||
(
|
||||
itr,
|
||||
p,
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
directory_options::_detail_no_follow,
|
||||
#else
|
||||
directory_options::none,
|
||||
#endif
|
||||
nullptr,
|
||||
&dit_create_ec
|
||||
);
|
||||
#endif
|
||||
|
||||
if (BOOST_UNLIKELY(!!dit_create_ec))
|
||||
@ -1188,7 +1220,7 @@ uintmax_t remove_all_impl
|
||||
itr->path(),
|
||||
ec
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
, params.iterator_fd
|
||||
, dir_fd
|
||||
#endif
|
||||
);
|
||||
if (ec && *ec)
|
||||
@ -1201,7 +1233,7 @@ uintmax_t remove_all_impl
|
||||
}
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
count += fs::detail::remove_impl(remove_path, type, ec, parentdir_fd);
|
||||
count += fs::detail::remove_impl(*remove_path, type, ec, parentdir_fd);
|
||||
#else
|
||||
count += fs::detail::remove_impl(p, type, ec);
|
||||
#endif
|
||||
@ -2997,13 +3029,13 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
|
||||
int err = 0;
|
||||
|
||||
// Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors
|
||||
fd_wrapper infile, outfile;
|
||||
// Note: Declare fd wrappers here so that errno is not clobbered by close() that may be called in fd wrapper destructors
|
||||
boost::scope::unique_fd infile, outfile;
|
||||
|
||||
while (true)
|
||||
{
|
||||
infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (BOOST_UNLIKELY(infile.fd < 0))
|
||||
infile.reset(::open(from.c_str(), O_RDONLY | O_CLOEXEC));
|
||||
if (BOOST_UNLIKELY(!infile))
|
||||
{
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
@ -3023,7 +3055,7 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
statx_data_mask |= STATX_MTIME;
|
||||
|
||||
struct ::statx from_stat;
|
||||
if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0))
|
||||
if (BOOST_UNLIKELY(invoke_statx(infile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0))
|
||||
{
|
||||
fail_errno:
|
||||
err = errno;
|
||||
@ -3037,7 +3069,7 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
}
|
||||
#else
|
||||
struct ::stat from_stat;
|
||||
if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0))
|
||||
if (BOOST_UNLIKELY(::fstat(infile.get(), &from_stat) != 0))
|
||||
{
|
||||
fail_errno:
|
||||
err = errno;
|
||||
@ -3065,8 +3097,8 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
// Try opening the existing file without truncation to test the modification time later
|
||||
while (true)
|
||||
{
|
||||
outfile.fd = ::open(to.c_str(), oflag, to_mode);
|
||||
if (outfile.fd < 0)
|
||||
outfile.reset(::open(to.c_str(), oflag, to_mode));
|
||||
if (!outfile)
|
||||
{
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
@ -3094,8 +3126,8 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
|
||||
while (true)
|
||||
{
|
||||
outfile.fd = ::open(to.c_str(), oflag, to_mode);
|
||||
if (outfile.fd < 0)
|
||||
outfile.reset(::open(to.c_str(), oflag, to_mode));
|
||||
if (!outfile)
|
||||
{
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
@ -3120,7 +3152,7 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
}
|
||||
|
||||
struct ::statx to_stat;
|
||||
if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0))
|
||||
if (BOOST_UNLIKELY(invoke_statx(outfile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0))
|
||||
goto fail_errno;
|
||||
|
||||
if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask))
|
||||
@ -3130,7 +3162,7 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
}
|
||||
#else
|
||||
struct ::stat to_stat;
|
||||
if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0))
|
||||
if (BOOST_UNLIKELY(::fstat(outfile.get(), &to_stat) != 0))
|
||||
goto fail_errno;
|
||||
#endif
|
||||
|
||||
@ -3163,12 +3195,12 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0))
|
||||
if (BOOST_UNLIKELY(::ftruncate(outfile.get(), 0) != 0))
|
||||
goto fail_errno;
|
||||
}
|
||||
|
||||
// Note: Use block size of the target file since it is most important for writing performance.
|
||||
err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat));
|
||||
err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.get(), outfile.get(), get_size(from_stat), get_blksize(to_stat));
|
||||
if (BOOST_UNLIKELY(err != 0))
|
||||
goto fail; // err already contains the error code
|
||||
|
||||
@ -3177,7 +3209,7 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
// we may need to update its mode bits to match the source file.
|
||||
if ((to_mode & fs::perms_mask) != (from_mode & fs::perms_mask))
|
||||
{
|
||||
if (BOOST_UNLIKELY(::fchmod(outfile.fd, (from_mode & fs::perms_mask)) != 0 &&
|
||||
if (BOOST_UNLIKELY(::fchmod(outfile.get(), (from_mode & fs::perms_mask)) != 0 &&
|
||||
(options & copy_options::ignore_attribute_errors) == copy_options::none))
|
||||
{
|
||||
goto fail_errno;
|
||||
@ -3188,9 +3220,9 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
if ((options & (copy_options::synchronize_data | copy_options::synchronize)) != copy_options::none)
|
||||
{
|
||||
if ((options & copy_options::synchronize) != copy_options::none)
|
||||
err = full_sync(outfile.fd);
|
||||
err = full_sync(outfile.get());
|
||||
else
|
||||
err = data_sync(outfile.fd);
|
||||
err = data_sync(outfile.get());
|
||||
|
||||
if (BOOST_UNLIKELY(err != 0))
|
||||
goto fail;
|
||||
@ -3198,8 +3230,8 @@ bool copy_file(path const& from, path const& to, copy_options options, error_cod
|
||||
|
||||
// We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate
|
||||
// a failure of a prior write operation.
|
||||
err = close_fd(outfile.fd);
|
||||
outfile.fd = -1;
|
||||
err = close_fd(outfile.get());
|
||||
outfile.release();
|
||||
if (BOOST_UNLIKELY(err < 0))
|
||||
{
|
||||
err = errno;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// posix_tools.hpp -------------------------------------------------------------------//
|
||||
|
||||
// Copyright 2021 Andrey Semashev
|
||||
// Copyright 2021-2024 Andrey Semashev
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See http://www.boost.org/LICENSE_1_0.txt
|
||||
@ -13,16 +13,15 @@
|
||||
#define BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_
|
||||
|
||||
#include "platform_config.hpp"
|
||||
#include <cerrno>
|
||||
#include <boost/filesystem/config.hpp>
|
||||
#ifdef BOOST_HAS_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <boost/scope/unique_fd.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/file_status.hpp>
|
||||
#include <boost/filesystem/directory.hpp>
|
||||
#include <boost/filesystem/detail/header.hpp> // must be the last #include
|
||||
|
||||
namespace boost {
|
||||
@ -32,52 +31,12 @@ namespace detail {
|
||||
//! Platform-specific parameters for directory iterator construction
|
||||
struct directory_iterator_params
|
||||
{
|
||||
#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
//! Base directory path, relative to which to interpret relative paths. Must be empty if basedir_fd is AT_FDCWD.
|
||||
path basedir;
|
||||
//! File descriptor of the base directory relative to which to interpret relative paths
|
||||
int basedir_fd;
|
||||
#endif
|
||||
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
|
||||
//! File descriptor of the directory over which the iterator iterates
|
||||
int iterator_fd;
|
||||
//! File descriptor of the directory to iterate over. If not a negative value, the directory path is only used to generate paths returned by the iterator.
|
||||
boost::scope::unique_fd dir_fd;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
* Closes a file descriptor and returns the result, similar to close(2). Unlike close(2), guarantees that the file descriptor is closed even if EINTR error happens.
|
||||
*
|
||||
* Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR.
|
||||
* Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it
|
||||
* again could close a different file descriptor that was opened by a different thread. This function hides this difference in behavior.
|
||||
*
|
||||
* Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529)
|
||||
* and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2)
|
||||
* behaves differently between systems.
|
||||
*/
|
||||
inline int close_fd(int fd)
|
||||
{
|
||||
#if defined(hpux) || defined(_hpux) || defined(__hpux)
|
||||
int res;
|
||||
while (true)
|
||||
{
|
||||
res = ::close(fd);
|
||||
if (BOOST_UNLIKELY(res < 0))
|
||||
{
|
||||
int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
return ::close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! status() implementation
|
||||
file_status status_impl
|
||||
(
|
||||
@ -98,6 +57,18 @@ file_status symlink_status_impl
|
||||
#endif
|
||||
);
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
|
||||
//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
|
||||
boost::scope::unique_fd open_directory(path const& p, directory_options opts, system::error_code& ec);
|
||||
|
||||
#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
|
||||
boost::scope::unique_fd openat_directory(int basedir_fd, path const& p, directory_options opts, system::error_code& ec);
|
||||
#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
|
||||
|
||||
#endif // defined(BOOST_POSIX_API)
|
||||
|
||||
} // namespace detail
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
@ -1,7 +1,7 @@
|
||||
// filesystem unique_path.cpp --------------------------------------------------------//
|
||||
|
||||
// Copyright Beman Dawes 2010
|
||||
// Copyright Andrey Semashev 2020
|
||||
// Copyright Andrey Semashev 2020, 2024
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See http://www.boost.org/LICENSE_1_0.txt
|
||||
@ -20,10 +20,8 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef BOOST_HAS_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#if !defined(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM)
|
||||
#if BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(2, 1, 0) || \
|
||||
@ -56,6 +54,7 @@
|
||||
#endif // (defined(__linux__) || defined(__linux) || defined(linux)) && (!defined(__ANDROID__) || __ANDROID_API__ >= 28)
|
||||
#endif // !defined(BOOST_FILESYSTEM_DISABLE_GETRANDOM)
|
||||
|
||||
#include <boost/scope/unique_fd.hpp>
|
||||
#include "posix_tools.hpp"
|
||||
|
||||
#else // BOOST_WINDOWS_API
|
||||
@ -115,31 +114,52 @@ namespace {
|
||||
//! Fills buffer with cryptographically random data obtained from /dev/(u)random
|
||||
int fill_random_dev_random(void* buf, std::size_t len)
|
||||
{
|
||||
int file = ::open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
if (file == -1)
|
||||
boost::scope::unique_fd file;
|
||||
while (true)
|
||||
{
|
||||
file = ::open("/dev/random", O_RDONLY | O_CLOEXEC);
|
||||
if (file == -1)
|
||||
return errno;
|
||||
file.reset(::open("/dev/urandom", O_RDONLY | O_CLOEXEC));
|
||||
if (!file)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!file)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
file.reset(::open("/dev/random", O_RDONLY | O_CLOEXEC));
|
||||
if (!file)
|
||||
{
|
||||
const int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t bytes_read = 0u;
|
||||
while (bytes_read < len)
|
||||
{
|
||||
ssize_t n = ::read(file, buf, len - bytes_read);
|
||||
if (BOOST_UNLIKELY(n == -1))
|
||||
ssize_t n = ::read(file.get(), buf, len - bytes_read);
|
||||
if (BOOST_UNLIKELY(n < 0))
|
||||
{
|
||||
int err = errno;
|
||||
const int err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
close_fd(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
bytes_read += n;
|
||||
buf = static_cast< char* >(buf) + n;
|
||||
}
|
||||
|
||||
close_fd(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user