Handle EINTR error code returned from opendir and readdir.

Although not documented, this error code, reportedly, may be returned
on Apple operating systems and some BSD systems.
This commit is contained in:
Andrey Semashev
2026-05-05 13:39:10 +03:00
parent acbaca55f3
commit 77e057e8bc
2 changed files with 67 additions and 25 deletions
+1
View File
@@ -45,6 +45,7 @@
<li>Marked templated versions of <code>initial_path</code> as deprecated and removed from <b>v4</b>. Use the non-templated versions instead.</li>
<li>Use <code>readdir</code> instead of <code>readdir_r</code> on more POSIX platforms, specifically on Mac OS and other Apple operating systems, FreeBSD, OpenBSD, DragonFly BSD, NetBSD, QNX 6.0 and later, Solaris 10 and later and Illumos-based systems. Solaris users with gcc are recommended to define <code>__SunOS_5_x</code> macros according to their target Solaris version (e.g. <code>__SunOS_5_11</code>) when building Boost. (<a href="https://github.com/boostorg/filesystem/issues/349">#349</a>)</li>
<li>Support for platforms with non-thread-safe <code>readdir</code> is deprecated and will be removed in a future release. Although not required until <a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/readdir.html">POSIX.1-2024</a>, on modern systems <code>readdir</code> is thread-safe when used with separate <code>DIR</code> objects in different threads and on some systems <code>readdir_r</code> is marked as deprecated. POSIX.1-2024 has been updated accordingly and also marked <code>readdir_r</code> as obsolescent, with a planned removal in a future version of the specification.</li>
<li>On POSIX platforms, handle <code>EINTR</code> error code returned from <code>opendir</code>, <code>readdir</code> and equivalents. Although not documented, this error code, reportedly, may be returned on Apple operating systems and some BSD systems.</li>
</ul>
<h2>1.91.0</h2>
+66 -25
View File
@@ -417,11 +417,21 @@ inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result)
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 system::error_code(err, system::system_category());
if (result == nullptr)
return dir_itr_close(imp);
while (true)
{
int err = invoke_readdir(imp, &result);
if (BOOST_UNLIKELY(err != 0))
{
if (err == EINTR)
continue;
return system::error_code(err, system::system_category());
}
if (result == nullptr)
return dir_itr_close(imp);
break;
}
filename = result->d_name;
@@ -511,21 +521,35 @@ system::error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& i
return ec;
}
pimpl->handle = ::fdopendir(fd.get());
if (BOOST_UNLIKELY(!pimpl->handle))
while (true)
{
const int err = errno;
return system::error_code(err, system::system_category());
pimpl->handle = ::fdopendir(fd.get());
if (BOOST_UNLIKELY(!pimpl->handle))
{
const int err = errno;
if (err == EINTR)
continue;
return system::error_code(err, system::system_category());
}
break;
}
// 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))
while (true)
{
const int err = errno;
return system::error_code(err, system::system_category());
pimpl->handle = ::opendir(dir.c_str());
if (BOOST_UNLIKELY(!pimpl->handle))
{
const int err = errno;
if (err == EINTR)
continue;
return system::error_code(err, system::system_category());
}
break;
}
#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
@@ -1118,29 +1142,44 @@ bool is_empty_directory(boost::scope::unique_fd&& fd, path const& p, error_code*
::closedir(dir);
}
};
std::unique_ptr< DIR, closedir_deleter > dir;
int err;
#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
std::unique_ptr< DIR, closedir_deleter > dir(::fdopendir(fd.get()));
if (BOOST_UNLIKELY(!dir))
while (true)
{
err = errno;
fail:
emit_error(err, p, ec, "boost::filesystem::is_empty");
return false;
dir.reset(::fdopendir(fd.get()));
if (BOOST_UNLIKELY(!dir))
{
err = errno;
if (err == EINTR)
continue;
fail:
emit_error(err, p, ec, "boost::filesystem::is_empty");
return false;
}
break;
}
// At this point fd will be closed by closedir
fd.release();
#else // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
std::unique_ptr< DIR, closedir_deleter > dir(::opendir(p.c_str()));
if (BOOST_UNLIKELY(!dir))
while (true)
{
err = errno;
fail:
emit_error(err, p, ec, "boost::filesystem::is_empty");
return false;
dir.reset(::opendir(p.c_str()));
if (BOOST_UNLIKELY(!dir))
{
err = errno;
if (err == EINTR)
continue;
fail:
emit_error(err, p, ec, "boost::filesystem::is_empty");
return false;
}
break;
}
#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
@@ -1151,6 +1190,8 @@ bool is_empty_directory(boost::scope::unique_fd&& fd, path const& p, error_code*
if (!ent)
{
err = errno;
if (err == EINTR)
continue;
if (err != 0)
goto fail;