1 // Class filesystem::directory_entry etc. -*- C++ -*-
3 // Copyright (C) 2014-2019 Free Software Foundation, Inc.
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)
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
34 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
35 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
36 #include "../filesystem/dir-common.h"
38 namespace fs
= std::filesystem
;
39 namespace posix
= std::filesystem::__gnu_posix
;
41 template class std::__shared_ptr
<fs::_Dir
>;
42 template class std::__shared_ptr
<fs::recursive_directory_iterator::_Dir_stack
>;
44 struct fs::_Dir
: _Dir_base
46 _Dir(const fs::path
& p
, bool skip_permission_denied
, error_code
& ec
)
47 : _Dir_base(p
.c_str(), skip_permission_denied
, ec
)
53 _Dir(posix::DIR* dirp
, const path
& p
) : _Dir_base(dirp
), path(p
) { }
55 _Dir(_Dir
&&) = default;
57 // Returns false when the end of the directory entries is reached.
58 // Reports errors by setting ec.
59 bool advance(bool skip_permission_denied
, error_code
& ec
) noexcept
61 if (const auto entp
= _Dir_base::advance(skip_permission_denied
, ec
))
65 entry
= fs::directory_entry
{std::move(name
), get_file_type(*entp
)};
76 bool advance(error_code
& ec
) noexcept
{ return advance(false, ec
); }
78 // Returns false when the end of the directory entries is reached.
79 // Reports errors by throwing.
80 bool advance(bool skip_permission_denied
= false)
83 const bool ok
= advance(skip_permission_denied
, ec
);
85 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
86 "directory iterator cannot advance", ec
));
90 bool should_recurse(bool follow_symlink
, error_code
& ec
) const
92 file_type type
= entry
._M_type
;
93 if (type
== file_type::none
|| type
== file_type::unknown
)
95 type
= entry
.symlink_status(ec
).type();
100 if (type
== file_type::directory
)
102 if (type
== file_type::symlink
)
103 return follow_symlink
&& is_directory(entry
.status(ec
));
108 directory_entry entry
;
113 template<typename Bitmask
>
115 is_set(Bitmask obj
, Bitmask bits
)
117 return (obj
& bits
) != Bitmask::none
;
121 fs::directory_iterator::
122 directory_iterator(const path
& p
, directory_options options
, error_code
* ecptr
)
124 const bool skip_permission_denied
125 = is_set(options
, directory_options::skip_permission_denied
);
128 _Dir
dir(p
, skip_permission_denied
, ec
);
132 auto sp
= std::__make_shared
<fs::_Dir
>(std::move(dir
));
133 if (sp
->advance(skip_permission_denied
, ec
))
139 _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
140 "directory iterator cannot open directory", p
, ec
));
143 const fs::directory_entry
&
144 fs::directory_iterator::operator*() const
147 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
148 "non-dereferenceable directory iterator",
149 std::make_error_code(errc::invalid_argument
)));
150 return _M_dir
->entry
;
153 fs::directory_iterator
&
154 fs::directory_iterator::operator++()
157 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
158 "cannot advance non-dereferenceable directory iterator",
159 std::make_error_code(errc::invalid_argument
)));
160 if (!_M_dir
->advance())
165 fs::directory_iterator
&
166 fs::directory_iterator::increment(error_code
& ec
)
170 ec
= std::make_error_code(errc::invalid_argument
);
173 if (!_M_dir
->advance(ec
))
178 struct fs::recursive_directory_iterator::_Dir_stack
: std::stack
<_Dir
>
180 void clear() { c
.clear(); }
183 fs::recursive_directory_iterator::
184 recursive_directory_iterator(const path
& p
, directory_options options
,
186 : _M_options(options
), _M_pending(true)
188 if (posix::DIR* dirp
= posix::opendir(p
.c_str()))
192 auto sp
= std::__make_shared
<_Dir_stack
>();
193 sp
->push(_Dir
{ dirp
, p
});
194 if (ecptr
? sp
->top().advance(*ecptr
) : sp
->top().advance())
199 const int err
= errno
;
201 && is_set(options
, fs::directory_options::skip_permission_denied
))
209 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
210 "recursive directory iterator cannot open directory", p
,
211 std::error_code(err
, std::generic_category())));
213 ecptr
->assign(err
, std::generic_category());
217 fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
220 fs::recursive_directory_iterator::depth() const
222 return int(_M_dirs
->size()) - 1;
225 const fs::directory_entry
&
226 fs::recursive_directory_iterator::operator*() const
228 return _M_dirs
->top().entry
;
231 fs::recursive_directory_iterator
&
232 fs::recursive_directory_iterator::
233 operator=(const recursive_directory_iterator
& other
) noexcept
= default;
235 fs::recursive_directory_iterator
&
236 fs::recursive_directory_iterator::
237 operator=(recursive_directory_iterator
&& other
) noexcept
= default;
239 fs::recursive_directory_iterator
&
240 fs::recursive_directory_iterator::operator++()
245 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
246 "cannot increment recursive directory iterator", ec
));
250 fs::recursive_directory_iterator
&
251 fs::recursive_directory_iterator::increment(error_code
& ec
)
255 ec
= std::make_error_code(errc::invalid_argument
);
260 = is_set(_M_options
, directory_options::follow_directory_symlink
);
261 const bool skip_permission_denied
262 = is_set(_M_options
, directory_options::skip_permission_denied
);
264 auto& top
= _M_dirs
->top();
266 if (std::exchange(_M_pending
, true) && top
.should_recurse(follow
, ec
))
268 _Dir
dir(top
.entry
.path(), skip_permission_denied
, ec
);
275 _M_dirs
->push(std::move(dir
));
278 while (!_M_dirs
->top().advance(skip_permission_denied
, ec
) && !ec
)
281 if (_M_dirs
->empty())
291 fs::recursive_directory_iterator::pop(error_code
& ec
)
295 ec
= std::make_error_code(errc::invalid_argument
);
299 const bool skip_permission_denied
300 = is_set(_M_options
, directory_options::skip_permission_denied
);
304 if (_M_dirs
->empty())
310 } while (!_M_dirs
->top().advance(skip_permission_denied
, ec
));
314 fs::recursive_directory_iterator::pop()
319 _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
320 ? "recursive directory iterator cannot pop"
321 : "non-dereferenceable recursive directory iterator cannot pop",