xfail all scan-tree-dump-times checks on hppa*64*-*-* in sra-17.c and sra-18.c
[official-gcc.git] / libstdc++-v3 / src / filesystem / dir-common.h
blob95eaf98ed08f1f19322c2f1741ddb879f5bf9bd6
1 // Filesystem directory iterator utilities -*- C++ -*-
3 // Copyright (C) 2014-2024 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 #ifndef _GLIBCXX_DIR_COMMON_H
26 #define _GLIBCXX_DIR_COMMON_H 1
28 #include <stdint.h> // uint32_t
29 #include <string.h> // strcmp
30 #include <errno.h>
31 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
32 #include <wchar.h> // wcscmp
33 #endif
34 #ifdef _GLIBCXX_HAVE_DIRENT_H
35 # ifdef _GLIBCXX_HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 # endif
38 # include <dirent.h> // opendir, readdir, fdopendir, dirfd
39 # ifdef _GLIBCXX_HAVE_FCNTL_H
40 # include <fcntl.h> // open, openat, fcntl, AT_FDCWD, O_NOFOLLOW etc.
41 # include <unistd.h> // close, unlinkat
42 # endif
43 #endif
45 namespace std _GLIBCXX_VISIBILITY(default)
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
48 namespace filesystem
50 namespace __gnu_posix
52 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
53 // Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
54 using char_type = wchar_t;
55 using DIR = ::_WDIR;
56 using dirent = _wdirent;
57 inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); }
58 inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); }
59 inline int closedir(DIR* dir) { return ::_wclosedir(dir); }
60 #elif defined _GLIBCXX_HAVE_DIRENT_H
61 using char_type = char;
62 using DIR = ::DIR;
63 typedef struct ::dirent dirent;
64 using ::opendir;
65 using ::readdir;
66 using ::closedir;
67 #else
68 using char_type = char;
69 struct dirent { const char* d_name; };
70 struct DIR { };
71 inline DIR* opendir(const char*) { return nullptr; }
72 inline dirent* readdir(DIR*) { return nullptr; }
73 inline int closedir(DIR*) { return -1; }
74 #undef _GLIBCXX_HAVE_DIRFD
75 #undef _GLIBCXX_HAVE_UNLINKAT
76 #endif
77 } // namespace __gnu_posix
79 namespace posix = __gnu_posix;
81 inline bool
82 is_permission_denied_error(int e)
84 if (e == EACCES)
85 return true;
86 #ifdef __APPLE__
87 if (e == EPERM) // See PR 99533
88 return true;
89 #endif
90 return false;
93 struct _Dir_base
95 // As well as the full pathname (including the directory iterator's path)
96 // this type contains a file descriptor for a directory and a second pathname
97 // relative to that directory. The file descriptor and relative pathname
98 // can be used with POSIX openat and unlinkat.
99 struct _At_path
101 // No file descriptor given, so interpret the pathname relative to the CWD.
102 _At_path(const posix::char_type* p) noexcept
103 : pathname(p), dir_fd(fdcwd()), offset(0)
106 _At_path(int fd, const posix::char_type* p, size_t offset) noexcept
107 : pathname(p), dir_fd(fd), offset(offset)
110 const posix::char_type*
111 path() const noexcept { return pathname; }
114 dir() const noexcept { return dir_fd; }
116 const posix::char_type*
117 path_at_dir() const noexcept { return pathname + offset; }
119 private:
120 const posix::char_type* pathname; // Full path relative to CWD.
121 int dir_fd; // A directory descriptor (either the parent dir, or AT_FDCWD).
122 uint32_t offset; // Offset into pathname for the part relative to dir_fd.
124 // Special value representing the current working directory.
125 // Not a valid file descriptor for an open directory stream.
126 static constexpr int
127 fdcwd() noexcept
129 #ifdef AT_FDCWD
130 return AT_FDCWD;
131 #else
132 return -1; // Use invalid fd if AT_FDCWD isn't supported.
133 #endif
137 // If no error occurs then dirp is non-null,
138 // otherwise null (even if a permission denied error is ignored).
139 _Dir_base(const _At_path& atp,
140 bool skip_permission_denied, bool nofollow,
141 error_code& ec) noexcept
142 : dirp(_Dir_base::openat(atp, nofollow))
144 if (dirp)
145 ec.clear();
146 else if (is_permission_denied_error(errno) && skip_permission_denied)
147 ec.clear();
148 else
149 ec.assign(errno, std::generic_category());
152 _Dir_base(_Dir_base&& d) : dirp(std::exchange(d.dirp, nullptr)) { }
154 _Dir_base& operator=(_Dir_base&&) = delete;
156 ~_Dir_base() { if (dirp) posix::closedir(dirp); }
158 const posix::dirent*
159 advance(bool skip_permission_denied, error_code& ec) noexcept
161 ec.clear();
163 int err = std::exchange(errno, 0);
164 const posix::dirent* entp = posix::readdir(dirp);
165 // std::swap cannot be used with Bionic's errno
166 err = std::exchange(errno, err);
168 if (entp)
170 // skip past dot and dot-dot
171 if (is_dot_or_dotdot(entp->d_name))
172 return advance(skip_permission_denied, ec);
173 return entp;
175 else if (err)
177 if (err == EACCES && skip_permission_denied)
178 return nullptr;
179 ec.assign(err, std::generic_category());
180 return nullptr;
182 else
184 // reached the end
185 return nullptr;
189 static bool is_dot_or_dotdot(const char* s) noexcept
190 { return !strcmp(s, ".") || !strcmp(s, ".."); }
192 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
193 static bool is_dot_or_dotdot(const wchar_t* s) noexcept
194 { return !wcscmp(s, L".") || !wcscmp(s, L".."); }
195 #endif
197 // Set the close-on-exec flag if not already done via O_CLOEXEC.
198 static bool
199 set_close_on_exec([[maybe_unused]] int fd)
201 #if ! defined O_CLOEXEC && defined FD_CLOEXEC
202 int flags = ::fcntl(fd, F_GETFD);
203 if (flags == -1 || ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
204 return false;
205 #endif
206 return true;
209 static posix::DIR*
210 openat(const _At_path& atp, bool nofollow)
212 #if _GLIBCXX_HAVE_FDOPENDIR && defined O_RDONLY && defined O_DIRECTORY \
213 && ! _GLIBCXX_FILESYSTEM_IS_WINDOWS
215 // Any file descriptor we open here should be closed on exec.
216 #ifdef O_CLOEXEC
217 constexpr int close_on_exec = O_CLOEXEC;
218 #else
219 constexpr int close_on_exec = 0;
220 #endif
222 int flags = O_RDONLY | O_DIRECTORY | close_on_exec;
224 // Directory iterators are vulnerable to race conditions unless O_NOFOLLOW
225 // is supported, because a directory could be replaced with a symlink after
226 // checking is_directory(symlink_status(f)). O_NOFOLLOW avoids the race.
227 #ifdef O_NOFOLLOW
228 if (nofollow)
229 flags |= O_NOFOLLOW;
230 #else
231 nofollow = false;
232 #endif
234 int fd;
236 #if _GLIBCXX_HAVE_OPENAT
237 fd = ::openat(atp.dir(), atp.path_at_dir(), flags);
238 #else
239 // If we cannot use openat, there's no benefit to using posix::open unless
240 // we will use O_NOFOLLOW, so just use the simpler posix::opendir.
241 if (!nofollow)
242 return posix::opendir(atp.path());
244 fd = ::open(atp.path(), flags);
245 #endif
247 if (fd == -1)
248 return nullptr;
249 if (set_close_on_exec(fd))
250 if (::DIR* dirp = ::fdopendir(fd))
251 return dirp;
252 int err = errno;
253 ::close(fd);
254 errno = err;
255 return nullptr;
256 #else
257 return posix::opendir(atp.path());
258 #endif
261 posix::DIR* dirp;
264 } // namespace filesystem
266 // BEGIN/END macros must be defined before including this file.
267 _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
269 inline file_type
270 get_file_type(const std::filesystem::__gnu_posix::dirent& d [[gnu::unused]])
272 #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
273 switch (d.d_type)
275 case DT_BLK:
276 return file_type::block;
277 case DT_CHR:
278 return file_type::character;
279 case DT_DIR:
280 return file_type::directory;
281 case DT_FIFO:
282 return file_type::fifo;
283 case DT_LNK:
284 return file_type::symlink;
285 case DT_REG:
286 return file_type::regular;
287 case DT_SOCK:
288 return file_type::socket;
289 case DT_UNKNOWN:
290 return file_type::unknown;
291 default:
292 return file_type::none;
294 #else
295 return file_type::none;
296 #endif
299 _GLIBCXX_END_NAMESPACE_FILESYSTEM
301 _GLIBCXX_END_NAMESPACE_VERSION
302 } // namespace std
304 #endif // _GLIBCXX_DIR_COMMON_H