aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/filesystem/dir-common.h
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-06-27 14:43:54 +0100
committerJonathan Wakely <jwakely@redhat.com>2022-06-28 12:09:20 +0100
commit198781144f33b0ef17dd2094580b5c77ad97d6e8 (patch)
treeea71d88cfa12271bebe5437f606e0981dc0cdaa3 /libstdc++-v3/src/filesystem/dir-common.h
parent835b19936bf30d693783bfa39145a4ce243bbd7c (diff)
downloadgcc-198781144f33b0ef17dd2094580b5c77ad97d6e8.zip
gcc-198781144f33b0ef17dd2094580b5c77ad97d6e8.tar.gz
gcc-198781144f33b0ef17dd2094580b5c77ad97d6e8.tar.bz2
libstdc++: Improve directory iterator abstractions for openat
Currently the _Dir::open_subdir function decides whether to construct a _Dir_base with just a pathname, or a file descriptor and pathname. But that means it is tiughtly coupled to the implementation of _Dir_base::openat, which is what actually decides whether to use a file descriptor or not. If the derived class passes a file descriptor and filename, but the base class expects a full path and ignores the file descriptor, then recursive_directory_iterator cannot recurse. This change introduces a new type that provides the union of all the information available to the derived class (the full pathname, as well as a file descriptor for a directory and another pathname relative to that directory). This allows the derived class to be agnostic to how the base class will use that information. libstdc++-v3/ChangeLog: * src/c++17/fs_dir.cc (_Dir::dir_and_pathname):: Replace with current() returning _At_path. (_Dir::_Dir, _Dir::open_subdir, _Dir::do_unlink): Adjust. * src/filesystem/dir-common.h (_Dir_base::_At_path): New class. (_Dir_base::_Dir_Base, _Dir_base::openat): Use _At_path. * src/filesystem/dir.cc (_Dir::dir_and_pathname): Replace with current() returning _At_path. (_Dir::_Dir, _Dir::open_subdir): Adjust.
Diffstat (limited to 'libstdc++-v3/src/filesystem/dir-common.h')
-rw-r--r--libstdc++-v3/src/filesystem/dir-common.h66
1 files changed, 48 insertions, 18 deletions
diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h
index 669780e..4844b1a 100644
--- a/libstdc++-v3/src/filesystem/dir-common.h
+++ b/libstdc++-v3/src/filesystem/dir-common.h
@@ -25,6 +25,7 @@
#ifndef _GLIBCXX_DIR_COMMON_H
#define _GLIBCXX_DIR_COMMON_H 1
+#include <stdint.h> // uint32_t
#include <string.h> // strcmp
#include <errno.h>
#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
@@ -91,12 +92,50 @@ is_permission_denied_error(int e)
struct _Dir_base
{
+ // As well as the full pathname (including the directory iterator's path)
+ // this type contains a file descriptor for a directory and a second pathname
+ // relative to that directory. The file descriptor and relative pathname
+ // can be used with POSIX openat and unlinkat.
+ struct _At_path
+ {
+ // No file descriptor given, so interpret the pathname relative to the CWD.
+ _At_path(const char* p) noexcept
+ : pathname(p), dir_fd(fdcwd()), offset(0)
+ { }
+
+ _At_path(int fd, const char* p, size_t offset) noexcept
+ : pathname(p), dir_fd(fd), offset(offset)
+ { }
+
+ const char* path() const noexcept { return pathname; }
+
+ int dir() const noexcept { return dir_fd; }
+ const char* path_at_dir() const noexcept { return pathname + offset; }
+
+ private:
+ const posix::char_type* pathname; // Full path relative to CWD.
+ int dir_fd; // A directory descriptor (either the parent dir, or AT_FDCWD).
+ uint32_t offset; // Offset into pathname for the part relative to dir_fd.
+
+ // Special value representing the current working directory.
+ // Not a valid file descriptor for an open directory stream.
+ static constexpr int
+ fdcwd() noexcept
+ {
+#ifdef AT_FDCWD
+ return AT_FDCWD;
+#else
+ return -1; // Use invalid fd if AT_FDCWD isn't supported.
+#endif
+ }
+ };
+
// If no error occurs then dirp is non-null,
// otherwise null (even if a permission denied error is ignored).
- _Dir_base(int fd, const posix::char_type* pathname,
+ _Dir_base(const _At_path& atp,
bool skip_permission_denied, bool nofollow,
error_code& ec) noexcept
- : dirp(_Dir_base::openat(fd, pathname, nofollow))
+ : dirp(_Dir_base::openat(atp, nofollow))
{
if (dirp)
ec.clear();
@@ -143,16 +182,6 @@ struct _Dir_base
}
}
- static constexpr int
- fdcwd() noexcept
- {
-#ifdef AT_FDCWD
- return AT_FDCWD;
-#else
- return -1; // Use invalid fd if AT_FDCWD isn't supported.
-#endif
- }
-
static bool is_dot_or_dotdot(const char* s) noexcept
{ return !strcmp(s, ".") || !strcmp(s, ".."); }
@@ -174,7 +203,7 @@ struct _Dir_base
}
static posix::DIR*
- openat(int fd, const posix::char_type* pathname, bool nofollow)
+ openat(const _At_path& atp, bool nofollow)
{
#if _GLIBCXX_HAVE_FDOPENDIR && defined O_RDONLY && defined O_DIRECTORY \
&& ! _GLIBCXX_FILESYSTEM_IS_WINDOWS
@@ -198,16 +227,17 @@ struct _Dir_base
nofollow = false;
#endif
+ int fd;
-#if _GLIBCXX_HAVE_OPENAT && defined AT_FDCWD
- fd = ::openat(fd, pathname, flags);
+#if _GLIBCXX_HAVE_OPENAT
+ fd = ::openat(atp.dir(), atp.path_at_dir(), flags);
#else
// If we cannot use openat, there's no benefit to using posix::open unless
// we will use O_NOFOLLOW, so just use the simpler posix::opendir.
if (!nofollow)
- return posix::opendir(pathname);
+ return posix::opendir(atp.path());
- fd = ::open(pathname, flags);
+ fd = ::open(atp.path(), flags);
#endif
if (fd == -1)
@@ -220,7 +250,7 @@ struct _Dir_base
errno = err;
return nullptr;
#else
- return posix::opendir(pathname);
+ return posix::opendir(atp.path());
#endif
}