libquadmath: Fix up libquadmath/math/sqrtq.c compilation in some powerpc* configurati...
[official-gcc.git] / libstdc++-v3 / src / filesystem / dir.cc
blob4ebd0737f77dca6d2892298d159fe02285f23f14
1 // Class filesystem::directory_entry etc. -*- 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_USE_CXX11_ABI
26 # define _GLIBCXX_USE_CXX11_ABI 1
27 #endif
28 #ifndef _GNU_SOURCE
29 // Cygwin needs this for secure_getenv
30 # define _GNU_SOURCE 1
31 #endif
33 #include <bits/largefile-config.h>
34 #include <experimental/filesystem>
36 #ifndef _GLIBCXX_HAVE_DIRENT_H
37 # error "the <dirent.h> header is needed to build the Filesystem TS"
38 #endif
40 #include <utility>
41 #include <stack>
42 #include <string.h>
43 #include <errno.h>
44 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
45 namespace experimental { namespace filesystem {
46 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
47 #include "dir-common.h"
49 namespace fs = std::experimental::filesystem;
50 namespace posix = std::filesystem::__gnu_posix;
52 struct fs::_Dir : std::filesystem::_Dir_base
54 _Dir(const fs::path& p, bool skip_permission_denied, bool nofollow,
55 error_code& ec)
56 : _Dir_base(p.c_str(), skip_permission_denied, nofollow, ec)
58 if (!ec)
59 path = p;
62 _Dir(_Dir_base&& d, const path& p) : _Dir_base(std::move(d)), path(p) { }
64 _Dir(_Dir&&) = default;
66 // Returns false when the end of the directory entries is reached.
67 // Reports errors by setting ec.
68 bool advance(bool skip_permission_denied, error_code& ec) noexcept
70 if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
72 entry = fs::directory_entry{path / entp->d_name};
73 type = get_file_type(*entp);
74 return true;
76 else if (!ec)
78 // reached the end
79 entry = {};
80 type = file_type::none;
82 return false;
85 bool advance(error_code& ec) noexcept { return advance(false, ec); }
87 // Returns false when the end of the directory entries is reached.
88 // Reports errors by throwing.
89 bool advance(bool skip_permission_denied = false)
91 error_code ec;
92 const bool ok = advance(skip_permission_denied, ec);
93 if (ec)
94 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
95 "directory iterator cannot advance", ec));
96 return ok;
99 bool should_recurse(bool follow_symlink, error_code& ec) const
101 file_type type = this->type;
102 if (type == file_type::none || type == file_type::unknown)
104 type = entry.symlink_status(ec).type();
105 if (ec)
106 return false;
109 if (type == file_type::directory)
110 return true;
111 if (type == file_type::symlink)
112 return follow_symlink && is_directory(entry.status(ec));
113 return false;
116 // Return a pathname for the current directory entry, as an _At_path.
117 _Dir_base::_At_path
118 current() const noexcept
120 const fs::path& p = entry.path();
121 #if _GLIBCXX_HAVE_DIRFD
122 auto len = std::prev(p.end())->native().size();
123 return {::dirfd(this->dirp), p.c_str(), p.native().size() - len};
124 #else
125 return p.c_str();
126 #endif
129 // Create a new _Dir for the directory this->entry.path().
130 _Dir
131 open_subdir(bool skip_permission_denied, bool nofollow,
132 error_code& ec) noexcept
134 _Dir_base d(current(), skip_permission_denied, nofollow, ec);
135 return _Dir(std::move(d), entry.path());
138 fs::path path;
139 directory_entry entry;
140 file_type type = file_type::none;
143 namespace
145 template<typename Bitmask>
146 inline bool
147 is_set(Bitmask obj, Bitmask bits)
149 return (obj & bits) != Bitmask::none;
153 fs::directory_iterator::
154 directory_iterator(const path& p, directory_options options, error_code* ecptr)
156 // Do not report an error for permission denied errors.
157 const bool skip_permission_denied
158 = is_set(options, directory_options::skip_permission_denied);
160 error_code ec;
161 _Dir dir(p, skip_permission_denied, /*nofollow*/false, ec);
163 if (dir.dirp)
165 auto sp = std::make_shared<fs::_Dir>(std::move(dir));
166 if (sp->advance(skip_permission_denied, ec))
167 _M_dir.swap(sp);
169 if (ecptr)
170 *ecptr = ec;
171 else if (ec)
172 _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
173 "directory iterator cannot open directory", p, ec));
176 const fs::directory_entry&
177 fs::directory_iterator::operator*() const
179 if (!_M_dir)
180 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
181 "non-dereferenceable directory iterator",
182 std::make_error_code(errc::invalid_argument)));
183 return _M_dir->entry;
186 fs::directory_iterator&
187 fs::directory_iterator::operator++()
189 if (!_M_dir)
190 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
191 "cannot advance non-dereferenceable directory iterator",
192 std::make_error_code(errc::invalid_argument)));
193 if (!_M_dir->advance())
194 _M_dir.reset();
195 return *this;
198 fs::directory_iterator&
199 fs::directory_iterator::increment(error_code& ec) noexcept
201 if (!_M_dir)
203 ec = std::make_error_code(errc::invalid_argument);
204 return *this;
206 if (!_M_dir->advance(ec))
207 _M_dir.reset();
208 return *this;
211 struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
213 _Dir_stack(_Dir&& dir)
215 this->push(std::move(dir));
218 void clear() { c.clear(); }
221 fs::recursive_directory_iterator::
222 recursive_directory_iterator(const path& p, directory_options options,
223 error_code* ecptr)
224 : _M_options(options), _M_pending(true)
226 // Do not report an error for permission denied errors.
227 const bool skip_permission_denied
228 = is_set(options, directory_options::skip_permission_denied);
230 error_code ec;
231 _Dir dir(p, skip_permission_denied, /*nofollow*/false, ec);
233 if (dir.dirp)
235 auto sp = std::__make_shared<_Dir_stack>(std::move(dir));
236 if (ecptr ? sp->top().advance(skip_permission_denied, *ecptr)
237 : sp->top().advance(skip_permission_denied))
239 _M_dirs.swap(sp);
242 else if (ecptr)
243 *ecptr = ec;
244 else if (ec)
245 _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
246 "recursive directory iterator cannot open directory", p, ec));
249 fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
252 fs::recursive_directory_iterator::depth() const
254 return int(_M_dirs->size()) - 1;
257 const fs::directory_entry&
258 fs::recursive_directory_iterator::operator*() const
260 return _M_dirs->top().entry;
263 fs::recursive_directory_iterator&
264 fs::recursive_directory_iterator::
265 operator=(const recursive_directory_iterator& other) noexcept = default;
267 fs::recursive_directory_iterator&
268 fs::recursive_directory_iterator::
269 operator=(recursive_directory_iterator&& other) noexcept = default;
271 fs::recursive_directory_iterator&
272 fs::recursive_directory_iterator::operator++()
274 error_code ec;
275 increment(ec);
276 if (ec.value())
277 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
278 "cannot increment recursive directory iterator", ec));
279 return *this;
282 fs::recursive_directory_iterator&
283 fs::recursive_directory_iterator::increment(error_code& ec) noexcept
285 if (!_M_dirs)
287 ec = std::make_error_code(errc::invalid_argument);
288 return *this;
291 const bool follow
292 = is_set(_M_options, directory_options::follow_directory_symlink);
293 const bool skip_permission_denied
294 = is_set(_M_options, directory_options::skip_permission_denied);
296 auto& top = _M_dirs->top();
298 if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
300 _Dir dir = top.open_subdir(skip_permission_denied, !follow, ec);
301 if (ec)
303 _M_dirs.reset();
304 return *this;
306 if (dir.dirp)
307 _M_dirs->push(std::move(dir));
310 while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
312 _M_dirs->pop();
313 if (_M_dirs->empty())
315 _M_dirs.reset();
316 return *this;
320 if (ec)
321 _M_dirs.reset();
323 return *this;
326 void
327 fs::recursive_directory_iterator::pop(error_code& ec)
329 if (!_M_dirs)
331 ec = std::make_error_code(errc::invalid_argument);
332 return;
335 const bool skip_permission_denied
336 = is_set(_M_options, directory_options::skip_permission_denied);
338 do {
339 _M_dirs->pop();
340 if (_M_dirs->empty())
342 _M_dirs.reset();
343 ec.clear();
344 return;
346 } while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec);
348 if (ec)
349 _M_dirs.reset();
352 void
353 fs::recursive_directory_iterator::pop()
355 [[maybe_unused]] const bool dereferenceable = _M_dirs != nullptr;
356 error_code ec;
357 pop(ec);
358 if (ec)
359 _GLIBCXX_THROW_OR_ABORT(filesystem_error(dereferenceable
360 ? "recursive directory iterator cannot pop"
361 : "non-dereferenceable recursive directory iterator cannot pop",
362 ec));