1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H |
11 | #define _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H |
12 | |
13 | #include <__chrono/time_point.h> |
14 | #include <__compare/ordering.h> |
15 | #include <__config> |
16 | #include <__filesystem/file_status.h> |
17 | #include <__filesystem/file_time_type.h> |
18 | #include <__filesystem/file_type.h> |
19 | #include <__filesystem/filesystem_error.h> |
20 | #include <__filesystem/operations.h> |
21 | #include <__filesystem/path.h> |
22 | #include <__filesystem/perms.h> |
23 | #include <__system_error/errc.h> |
24 | #include <__system_error/error_code.h> |
25 | #include <__utility/move.h> |
26 | #include <__utility/unreachable.h> |
27 | #include <cstdint> |
28 | |
29 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
30 | # pragma GCC system_header |
31 | #endif |
32 | |
33 | _LIBCPP_PUSH_MACROS |
34 | #include <__undef_macros> |
35 | |
36 | #if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) |
37 | |
38 | _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM |
39 | |
40 | _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH |
41 | |
42 | class directory_entry { |
43 | typedef filesystem::path _Path; |
44 | |
45 | public: |
46 | // constructors and destructors |
47 | _LIBCPP_HIDE_FROM_ABI directory_entry() noexcept = default; |
48 | _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry const&) = default; |
49 | _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry&&) noexcept = default; |
50 | |
51 | _LIBCPP_HIDE_FROM_ABI explicit directory_entry(_Path const& __p) : __p_(__p) { |
52 | error_code __ec; |
53 | __refresh(ec: &__ec); |
54 | } |
55 | |
56 | _LIBCPP_HIDE_FROM_ABI directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) { __refresh(ec: &__ec); } |
57 | |
58 | _LIBCPP_HIDE_FROM_ABI ~directory_entry() {} |
59 | |
60 | _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry const&) = default; |
61 | _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry&&) noexcept = default; |
62 | |
63 | _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p) { |
64 | __p_ = __p; |
65 | error_code __ec; |
66 | __refresh(ec: &__ec); |
67 | } |
68 | |
69 | _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p, error_code& __ec) { |
70 | __p_ = __p; |
71 | __refresh(ec: &__ec); |
72 | } |
73 | |
74 | _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p) { |
75 | __p_.replace_filename(replacement: __p); |
76 | error_code __ec; |
77 | __refresh(ec: &__ec); |
78 | } |
79 | |
80 | _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p, error_code& __ec) { |
81 | __p_ = __p_.parent_path() / __p; |
82 | __refresh(ec: &__ec); |
83 | } |
84 | |
85 | _LIBCPP_HIDE_FROM_ABI void refresh() { __refresh(); } |
86 | |
87 | _LIBCPP_HIDE_FROM_ABI void refresh(error_code& __ec) noexcept { __refresh(ec: &__ec); } |
88 | |
89 | _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; } |
90 | |
91 | _LIBCPP_HIDE_FROM_ABI operator const _Path&() const noexcept { return __p_; } |
92 | |
93 | _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(s: file_status{__get_ft()}); } |
94 | |
95 | _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept { |
96 | return filesystem::exists(s: file_status{__get_ft(ec: &__ec)}); |
97 | } |
98 | |
99 | _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; } |
100 | |
101 | _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept { |
102 | return __get_ft(ec: &__ec) == file_type::block; |
103 | } |
104 | |
105 | _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; } |
106 | |
107 | _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept { |
108 | return __get_ft(ec: &__ec) == file_type::character; |
109 | } |
110 | |
111 | _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; } |
112 | |
113 | _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept { |
114 | return __get_ft(ec: &__ec) == file_type::directory; |
115 | } |
116 | |
117 | _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; } |
118 | |
119 | _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { return __get_ft(ec: &__ec) == file_type::fifo; } |
120 | |
121 | _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(s: file_status{__get_ft()}); } |
122 | |
123 | _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept { |
124 | return filesystem::is_other(s: file_status{__get_ft(ec: &__ec)}); |
125 | } |
126 | |
127 | _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; } |
128 | |
129 | _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept { |
130 | return __get_ft(ec: &__ec) == file_type::regular; |
131 | } |
132 | |
133 | _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; } |
134 | |
135 | _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { return __get_ft(ec: &__ec) == file_type::socket; } |
136 | |
137 | _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; } |
138 | |
139 | _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept { |
140 | return __get_sym_ft(ec: &__ec) == file_type::symlink; |
141 | } |
142 | _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); } |
143 | |
144 | _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(ec: &__ec); } |
145 | |
146 | _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); } |
147 | |
148 | _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { return __get_nlink(ec: &__ec); } |
149 | |
150 | _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); } |
151 | |
152 | _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept { |
153 | return __get_write_time(ec: &__ec); |
154 | } |
155 | |
156 | _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); } |
157 | |
158 | _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { return __get_status(ec: &__ec); } |
159 | |
160 | _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); } |
161 | |
162 | _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept { |
163 | return __get_symlink_status(ec: &__ec); |
164 | } |
165 | |
166 | _LIBCPP_HIDE_FROM_ABI bool operator==(directory_entry const& __rhs) const noexcept { return __p_ == __rhs.__p_; } |
167 | |
168 | # if _LIBCPP_STD_VER <= 17 |
169 | _LIBCPP_HIDE_FROM_ABI bool operator!=(directory_entry const& __rhs) const noexcept { return __p_ != __rhs.__p_; } |
170 | |
171 | _LIBCPP_HIDE_FROM_ABI bool operator<(directory_entry const& __rhs) const noexcept { return __p_ < __rhs.__p_; } |
172 | |
173 | _LIBCPP_HIDE_FROM_ABI bool operator<=(directory_entry const& __rhs) const noexcept { return __p_ <= __rhs.__p_; } |
174 | |
175 | _LIBCPP_HIDE_FROM_ABI bool operator>(directory_entry const& __rhs) const noexcept { return __p_ > __rhs.__p_; } |
176 | |
177 | _LIBCPP_HIDE_FROM_ABI bool operator>=(directory_entry const& __rhs) const noexcept { return __p_ >= __rhs.__p_; } |
178 | |
179 | # else // _LIBCPP_STD_VER <= 17 |
180 | |
181 | _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const directory_entry& __rhs) const noexcept { |
182 | return __p_ <=> __rhs.__p_; |
183 | } |
184 | |
185 | # endif // _LIBCPP_STD_VER <= 17 |
186 | |
187 | template <class _CharT, class _Traits> |
188 | _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>& |
189 | operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) { |
190 | return __os << __d.path(); |
191 | } |
192 | |
193 | private: |
194 | friend class directory_iterator; |
195 | friend class recursive_directory_iterator; |
196 | friend class _LIBCPP_HIDDEN __dir_stream; |
197 | |
198 | enum _CacheType : unsigned char { |
199 | _Empty, |
200 | _IterSymlink, |
201 | _IterNonSymlink, |
202 | _RefreshSymlink, |
203 | _RefreshSymlinkUnresolved, |
204 | _RefreshNonSymlink |
205 | }; |
206 | |
207 | struct __cached_data { |
208 | uintmax_t __size_; |
209 | uintmax_t __nlink_; |
210 | file_time_type __write_time_; |
211 | perms __sym_perms_; |
212 | perms __non_sym_perms_; |
213 | file_type __type_; |
214 | _CacheType __cache_type_; |
215 | |
216 | _LIBCPP_HIDE_FROM_ABI __cached_data() noexcept { __reset(); } |
217 | |
218 | _LIBCPP_HIDE_FROM_ABI void __reset() { |
219 | __cache_type_ = _Empty; |
220 | __type_ = file_type::none; |
221 | __sym_perms_ = __non_sym_perms_ = perms::unknown; |
222 | __size_ = __nlink_ = uintmax_t(-1); |
223 | __write_time_ = file_time_type::min(); |
224 | } |
225 | }; |
226 | |
227 | _LIBCPP_HIDE_FROM_ABI static __cached_data __create_iter_result(file_type __ft) { |
228 | __cached_data __data; |
229 | __data.__type_ = __ft; |
230 | __data.__cache_type_ = [&]() { |
231 | switch (__ft) { |
232 | case file_type::none: |
233 | return _Empty; |
234 | case file_type::symlink: |
235 | return _IterSymlink; |
236 | default: |
237 | return _IterNonSymlink; |
238 | } |
239 | }(); |
240 | return __data; |
241 | } |
242 | |
243 | _LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) { |
244 | __p_ = std::move(__p); |
245 | __data_ = __dt; |
246 | } |
247 | |
248 | _LIBCPP_EXPORTED_FROM_ABI error_code __do_refresh() noexcept; |
249 | |
250 | _LIBCPP_HIDE_FROM_ABI static bool __is_dne_error(error_code const& __ec) { |
251 | if (!__ec) |
252 | return true; |
253 | switch (static_cast<errc>(__ec.value())) { |
254 | case errc::no_such_file_or_directory: |
255 | case errc::not_a_directory: |
256 | return true; |
257 | default: |
258 | return false; |
259 | } |
260 | } |
261 | |
262 | _LIBCPP_HIDE_FROM_ABI void |
263 | __handle_error(const char* __msg, error_code* __dest_ec, error_code const& __ec, bool __allow_dne = false) const { |
264 | if (__dest_ec) { |
265 | *__dest_ec = __ec; |
266 | return; |
267 | } |
268 | if (__ec && (!__allow_dne || !__is_dne_error(__ec))) |
269 | __throw_filesystem_error(args&: __msg, args: __p_, args: __ec); |
270 | } |
271 | |
272 | _LIBCPP_HIDE_FROM_ABI void __refresh(error_code* __ec = nullptr) { |
273 | __handle_error(msg: "in directory_entry::refresh" , |
274 | dest_ec: __ec, |
275 | ec: __do_refresh(), |
276 | /*allow_dne*/ allow_dne: true); |
277 | } |
278 | |
279 | _LIBCPP_HIDE_FROM_ABI file_type __get_sym_ft(error_code* __ec = nullptr) const { |
280 | switch (__data_.__cache_type_) { |
281 | case _Empty: |
282 | return __symlink_status(__p_, __ec).type(); |
283 | case _IterSymlink: |
284 | case _RefreshSymlink: |
285 | case _RefreshSymlinkUnresolved: |
286 | if (__ec) |
287 | __ec->clear(); |
288 | return file_type::symlink; |
289 | case _IterNonSymlink: |
290 | case _RefreshNonSymlink: |
291 | file_status __st(__data_.__type_); |
292 | if (__ec && !filesystem::exists(s: __st)) |
293 | *__ec = make_error_code(e: errc::no_such_file_or_directory); |
294 | else if (__ec) |
295 | __ec->clear(); |
296 | return __data_.__type_; |
297 | } |
298 | __libcpp_unreachable(); |
299 | } |
300 | |
301 | _LIBCPP_HIDE_FROM_ABI file_type __get_ft(error_code* __ec = nullptr) const { |
302 | switch (__data_.__cache_type_) { |
303 | case _Empty: |
304 | case _IterSymlink: |
305 | case _RefreshSymlinkUnresolved: |
306 | return __status(__p_, __ec).type(); |
307 | case _IterNonSymlink: |
308 | case _RefreshNonSymlink: |
309 | case _RefreshSymlink: { |
310 | file_status __st(__data_.__type_); |
311 | if (__ec && !filesystem::exists(s: __st)) |
312 | *__ec = make_error_code(e: errc::no_such_file_or_directory); |
313 | else if (__ec) |
314 | __ec->clear(); |
315 | return __data_.__type_; |
316 | } |
317 | } |
318 | __libcpp_unreachable(); |
319 | } |
320 | |
321 | _LIBCPP_HIDE_FROM_ABI file_status __get_status(error_code* __ec = nullptr) const { |
322 | switch (__data_.__cache_type_) { |
323 | case _Empty: |
324 | case _IterNonSymlink: |
325 | case _IterSymlink: |
326 | case _RefreshSymlinkUnresolved: |
327 | return __status(__p_, __ec); |
328 | case _RefreshNonSymlink: |
329 | case _RefreshSymlink: |
330 | return file_status(__get_ft(__ec), __data_.__non_sym_perms_); |
331 | } |
332 | __libcpp_unreachable(); |
333 | } |
334 | |
335 | _LIBCPP_HIDE_FROM_ABI file_status __get_symlink_status(error_code* __ec = nullptr) const { |
336 | switch (__data_.__cache_type_) { |
337 | case _Empty: |
338 | case _IterNonSymlink: |
339 | case _IterSymlink: |
340 | return __symlink_status(__p_, __ec); |
341 | case _RefreshNonSymlink: |
342 | return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_); |
343 | case _RefreshSymlink: |
344 | case _RefreshSymlinkUnresolved: |
345 | return file_status(__get_sym_ft(__ec), __data_.__sym_perms_); |
346 | } |
347 | __libcpp_unreachable(); |
348 | } |
349 | |
350 | _LIBCPP_HIDE_FROM_ABI uintmax_t __get_size(error_code* __ec = nullptr) const { |
351 | switch (__data_.__cache_type_) { |
352 | case _Empty: |
353 | case _IterNonSymlink: |
354 | case _IterSymlink: |
355 | case _RefreshSymlinkUnresolved: |
356 | return filesystem::__file_size(__p_, __ec); |
357 | case _RefreshSymlink: |
358 | case _RefreshNonSymlink: { |
359 | error_code __m_ec; |
360 | file_status __st(__get_ft(ec: &__m_ec)); |
361 | __handle_error(msg: "in directory_entry::file_size" , dest_ec: __ec, ec: __m_ec); |
362 | if (filesystem::exists(s: __st) && !filesystem::is_regular_file(s: __st)) { |
363 | errc __err_kind = filesystem::is_directory(s: __st) ? errc::is_a_directory : errc::not_supported; |
364 | __handle_error(msg: "in directory_entry::file_size" , dest_ec: __ec, ec: make_error_code(e: __err_kind)); |
365 | } |
366 | return __data_.__size_; |
367 | } |
368 | } |
369 | __libcpp_unreachable(); |
370 | } |
371 | |
372 | _LIBCPP_HIDE_FROM_ABI uintmax_t __get_nlink(error_code* __ec = nullptr) const { |
373 | switch (__data_.__cache_type_) { |
374 | case _Empty: |
375 | case _IterNonSymlink: |
376 | case _IterSymlink: |
377 | case _RefreshSymlinkUnresolved: |
378 | return filesystem::__hard_link_count(__p_, __ec); |
379 | case _RefreshSymlink: |
380 | case _RefreshNonSymlink: { |
381 | error_code __m_ec; |
382 | (void)__get_ft(ec: &__m_ec); |
383 | __handle_error(msg: "in directory_entry::hard_link_count" , dest_ec: __ec, ec: __m_ec); |
384 | return __data_.__nlink_; |
385 | } |
386 | } |
387 | __libcpp_unreachable(); |
388 | } |
389 | |
390 | _LIBCPP_HIDE_FROM_ABI file_time_type __get_write_time(error_code* __ec = nullptr) const { |
391 | switch (__data_.__cache_type_) { |
392 | case _Empty: |
393 | case _IterNonSymlink: |
394 | case _IterSymlink: |
395 | case _RefreshSymlinkUnresolved: |
396 | return filesystem::__last_write_time(__p_, __ec); |
397 | case _RefreshSymlink: |
398 | case _RefreshNonSymlink: { |
399 | error_code __m_ec; |
400 | file_status __st(__get_ft(ec: &__m_ec)); |
401 | __handle_error(msg: "in directory_entry::last_write_time" , dest_ec: __ec, ec: __m_ec); |
402 | if (filesystem::exists(s: __st) && __data_.__write_time_ == file_time_type::min()) |
403 | __handle_error(msg: "in directory_entry::last_write_time" , dest_ec: __ec, ec: make_error_code(e: errc::value_too_large)); |
404 | return __data_.__write_time_; |
405 | } |
406 | } |
407 | __libcpp_unreachable(); |
408 | } |
409 | |
410 | private: |
411 | _Path __p_; |
412 | __cached_data __data_; |
413 | }; |
414 | |
415 | class __dir_element_proxy { |
416 | public: |
417 | inline _LIBCPP_HIDE_FROM_ABI directory_entry operator*() { return std::move(__elem_); } |
418 | |
419 | private: |
420 | friend class directory_iterator; |
421 | friend class recursive_directory_iterator; |
422 | _LIBCPP_HIDE_FROM_ABI explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {} |
423 | _LIBCPP_HIDE_FROM_ABI __dir_element_proxy(__dir_element_proxy&& __o) : __elem_(std::move(__o.__elem_)) {} |
424 | directory_entry __elem_; |
425 | }; |
426 | |
427 | _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP |
428 | |
429 | _LIBCPP_END_NAMESPACE_FILESYSTEM |
430 | |
431 | #endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) |
432 | |
433 | _LIBCPP_POP_MACROS |
434 | |
435 | #endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H |
436 | |