[PATCH] Adjust lazy macro definition
[official-gcc.git] / libstdc++-v3 / src / filesystem / ops.cc
blob40cadbf627014a9a42adfb1dbdec7bd263496394
1 // Filesystem TS operations -*- C++ -*-
3 // Copyright (C) 2014-2018 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
29 #include <experimental/filesystem>
30 #include <functional>
31 #include <ostream>
32 #include <stack>
33 #include <ext/stdio_filebuf.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <limits.h> // PATH_MAX
38 #ifdef _GLIBCXX_HAVE_FCNTL_H
39 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
40 #endif
41 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
42 # include <sys/stat.h> // stat, utimensat, fchmodat
43 #endif
44 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
45 # include <sys/statvfs.h> // statvfs
46 #endif
47 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
48 # include <utime.h> // utime
49 #endif
50 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
51 # include <windows.h>
52 #endif
54 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
55 namespace experimental { namespace filesystem {
56 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
57 #include "ops-common.h"
59 namespace fs = std::experimental::filesystem;
60 namespace posix = std::filesystem::__gnu_posix;
62 fs::path
63 fs::absolute(const path& p, const path& base)
65 const bool has_root_dir = p.has_root_directory();
66 const bool has_root_name = p.has_root_name();
67 path abs;
68 if (has_root_dir && has_root_name)
69 abs = p;
70 else
72 abs = base.is_absolute() ? base : absolute(base);
73 if (has_root_dir)
74 abs = abs.root_name() / p;
75 else if (has_root_name)
76 abs = p.root_name() / abs.root_directory() / abs.relative_path()
77 / p.relative_path();
78 else
79 abs = abs / p;
81 return abs;
84 namespace
86 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
87 inline bool is_dot(wchar_t c) { return c == L'.'; }
88 #else
89 inline bool is_dot(char c) { return c == '.'; }
90 #endif
92 inline bool is_dot(const fs::path& path)
94 const auto& filename = path.native();
95 return filename.size() == 1 && is_dot(filename[0]);
98 inline bool is_dotdot(const fs::path& path)
100 const auto& filename = path.native();
101 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
104 struct free_as_in_malloc
106 void operator()(void* p) const { ::free(p); }
109 using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
112 fs::path
113 fs::canonical(const path& p, const path& base, error_code& ec)
115 const path pa = absolute(p, base);
116 path result;
118 #ifdef _GLIBCXX_USE_REALPATH
119 char_ptr buf{ nullptr };
120 # if _XOPEN_VERSION < 700
121 // Not safe to call realpath(path, NULL)
122 using char_type = fs::path::value_type;
123 buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
124 # endif
125 if (char* rp = ::realpath(pa.c_str(), buf.get()))
127 if (buf == nullptr)
128 buf.reset(rp);
129 result.assign(rp);
130 ec.clear();
131 return result;
133 if (errno != ENAMETOOLONG)
135 ec.assign(errno, std::generic_category());
136 return result;
138 #endif
140 if (!exists(pa, ec))
142 if (!ec)
143 ec = make_error_code(std::errc::no_such_file_or_directory);
144 return result;
146 // else: we know there are (currently) no unresolvable symlink loops
148 result = pa.root_path();
150 deque<path> cmpts;
151 for (auto& f : pa.relative_path())
152 cmpts.push_back(f);
154 int max_allowed_symlinks = 40;
156 while (!cmpts.empty() && !ec)
158 path f = std::move(cmpts.front());
159 cmpts.pop_front();
161 if (is_dot(f))
163 if (!is_directory(result, ec) && !ec)
164 ec.assign(ENOTDIR, std::generic_category());
166 else if (is_dotdot(f))
168 auto parent = result.parent_path();
169 if (parent.empty())
170 result = pa.root_path();
171 else
172 result.swap(parent);
174 else
176 result /= f;
178 if (is_symlink(result, ec))
180 path link = read_symlink(result, ec);
181 if (!ec)
183 if (--max_allowed_symlinks == 0)
184 ec.assign(ELOOP, std::generic_category());
185 else
187 if (link.is_absolute())
189 result = link.root_path();
190 link = link.relative_path();
192 else
193 result.remove_filename();
195 cmpts.insert(cmpts.begin(), link.begin(), link.end());
202 if (ec || !exists(result, ec))
203 result.clear();
205 return result;
208 fs::path
209 fs::canonical(const path& p, error_code& ec)
211 path cur = current_path(ec);
212 if (ec.value())
213 return {};
214 return canonical(p, cur, ec);
217 fs::path
218 fs::canonical(const path& p, const path& base)
220 error_code ec;
221 path can = canonical(p, base, ec);
222 if (ec)
223 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, base,
224 ec));
225 return can;
228 void
229 fs::copy(const path& from, const path& to, copy_options options)
231 error_code ec;
232 copy(from, to, options, ec);
233 if (ec.value())
234 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
237 namespace
239 using std::filesystem::is_set;
241 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
242 using posix::stat_type;
244 using std::filesystem::is_not_found_errno;
245 using std::filesystem::file_time;
246 using std::filesystem::do_copy_file;
247 #endif // _GLIBCXX_HAVE_SYS_STAT_H
249 } // namespace
251 void
252 fs::copy(const path& from, const path& to, copy_options options,
253 error_code& ec) noexcept
255 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
256 const bool create_symlinks = is_set(options, copy_options::create_symlinks);
257 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
258 const bool use_lstat = create_symlinks || skip_symlinks;
260 file_status f, t;
261 stat_type from_st, to_st;
262 // _GLIBCXX_RESOLVE_LIB_DEFECTS
263 // 2681. filesystem::copy() cannot copy symlinks
264 if (use_lstat || copy_symlinks
265 ? posix::lstat(from.c_str(), &from_st)
266 : posix::stat(from.c_str(), &from_st))
268 ec.assign(errno, std::generic_category());
269 return;
271 if (use_lstat
272 ? posix::lstat(to.c_str(), &to_st)
273 : posix::stat(to.c_str(), &to_st))
275 if (!is_not_found_errno(errno))
277 ec.assign(errno, std::generic_category());
278 return;
280 t = file_status{file_type::not_found};
282 else
283 t = make_file_status(to_st);
284 f = make_file_status(from_st);
286 if (exists(t) && !is_other(t) && !is_other(f)
287 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
289 ec = std::make_error_code(std::errc::file_exists);
290 return;
292 if (is_other(f) || is_other(t))
294 ec = std::make_error_code(std::errc::not_supported);
295 return;
297 if (is_directory(f) && is_regular_file(t))
299 ec = std::make_error_code(std::errc::is_a_directory);
300 return;
303 if (is_symlink(f))
305 if (skip_symlinks)
306 ec.clear();
307 else if (!exists(t) && copy_symlinks)
308 copy_symlink(from, to, ec);
309 else
310 // Not clear what should be done here.
311 // "Otherwise report an error as specified in Error reporting (7)."
312 ec = std::make_error_code(std::errc::invalid_argument);
314 else if (is_regular_file(f))
316 if (is_set(options, copy_options::directories_only))
317 ec.clear();
318 else if (create_symlinks)
319 create_symlink(from, to, ec);
320 else if (is_set(options, copy_options::create_hard_links))
321 create_hard_link(from, to, ec);
322 else if (is_directory(t))
323 do_copy_file(from.c_str(), (to / from.filename()).c_str(),
324 copy_file_options(options), &from_st, nullptr, ec);
325 else
327 auto ptr = exists(t) ? &to_st : &from_st;
328 do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
329 &from_st, ptr, ec);
332 // _GLIBCXX_RESOLVE_LIB_DEFECTS
333 // 2682. filesystem::copy() won't create a symlink to a directory
334 else if (is_directory(f) && create_symlinks)
335 ec = std::make_error_code(errc::is_a_directory);
336 else if (is_directory(f) && (is_set(options, copy_options::recursive)
337 || options == copy_options::none))
339 if (!exists(t))
340 if (!create_directory(to, from, ec))
341 return;
342 // set an unused bit in options to disable further recursion
343 if (!is_set(options, copy_options::recursive))
344 options |= static_cast<copy_options>(4096);
345 for (const directory_entry& x : directory_iterator(from))
346 copy(x.path(), to/x.path().filename(), options, ec);
348 // _GLIBCXX_RESOLVE_LIB_DEFECTS
349 // 2683. filesystem::copy() says "no effects"
350 else
351 ec.clear();
354 bool
355 fs::copy_file(const path& from, const path& to, copy_options option)
357 error_code ec;
358 bool result = copy_file(from, to, option, ec);
359 if (ec.value())
360 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
361 ec));
362 return result;
365 bool
366 fs::copy_file(const path& from, const path& to, copy_options options,
367 error_code& ec) noexcept
369 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
370 return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
371 nullptr, nullptr, ec);
372 #else
373 ec = std::make_error_code(std::errc::not_supported);
374 return false;
375 #endif
379 void
380 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
382 error_code ec;
383 copy_symlink(existing_symlink, new_symlink, ec);
384 if (ec.value())
385 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
386 existing_symlink, new_symlink, ec));
389 void
390 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
391 error_code& ec) noexcept
393 auto p = read_symlink(existing_symlink, ec);
394 if (ec.value())
395 return;
396 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
397 if (is_directory(p))
399 create_directory_symlink(p, new_symlink, ec);
400 return;
402 #endif
403 create_symlink(p, new_symlink, ec);
407 bool
408 fs::create_directories(const path& p)
410 error_code ec;
411 bool result = create_directories(p, ec);
412 if (ec.value())
413 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
414 ec));
415 return result;
418 bool
419 fs::create_directories(const path& p, error_code& ec) noexcept
421 if (p.empty())
423 ec = std::make_error_code(errc::invalid_argument);
424 return false;
426 std::stack<path> missing;
427 path pp = p;
429 while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
431 ec.clear();
432 const auto& filename = pp.filename();
433 if (!is_dot(filename) && !is_dotdot(filename))
434 missing.push(pp);
435 pp.remove_filename();
438 if (ec || missing.empty())
439 return false;
443 const path& top = missing.top();
444 create_directory(top, ec);
445 if (ec && is_directory(top))
446 ec.clear();
447 missing.pop();
449 while (!missing.empty() && !ec);
451 return missing.empty();
454 namespace
456 bool
457 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
459 bool created = false;
460 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
461 posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
462 if (posix::mkdir(p.c_str(), mode))
464 const int err = errno;
465 if (err != EEXIST || !is_directory(p, ec))
466 ec.assign(err, std::generic_category());
468 else
470 ec.clear();
471 created = true;
473 #else
474 ec = std::make_error_code(std::errc::not_supported);
475 #endif
476 return created;
478 } // namespace
480 bool
481 fs::create_directory(const path& p)
483 error_code ec;
484 bool result = create_directory(p, ec);
485 if (ec.value())
486 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
487 ec));
488 return result;
491 bool
492 fs::create_directory(const path& p, error_code& ec) noexcept
494 return create_dir(p, perms::all, ec);
498 bool
499 fs::create_directory(const path& p, const path& attributes)
501 error_code ec;
502 bool result = create_directory(p, attributes, ec);
503 if (ec.value())
504 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
505 ec));
506 return result;
509 bool
510 fs::create_directory(const path& p, const path& attributes,
511 error_code& ec) noexcept
513 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
514 stat_type st;
515 if (posix::stat(attributes.c_str(), &st))
517 ec.assign(errno, std::generic_category());
518 return false;
520 return create_dir(p, static_cast<perms>(st.st_mode), ec);
521 #else
522 ec = std::make_error_code(std::errc::not_supported);
523 return false;
524 #endif
528 void
529 fs::create_directory_symlink(const path& to, const path& new_symlink)
531 error_code ec;
532 create_directory_symlink(to, new_symlink, ec);
533 if (ec.value())
534 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
535 to, new_symlink, ec));
538 void
539 fs::create_directory_symlink(const path& to, const path& new_symlink,
540 error_code& ec) noexcept
542 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
543 ec = std::make_error_code(std::errc::not_supported);
544 #else
545 create_symlink(to, new_symlink, ec);
546 #endif
550 void
551 fs::create_hard_link(const path& to, const path& new_hard_link)
553 error_code ec;
554 create_hard_link(to, new_hard_link, ec);
555 if (ec.value())
556 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
557 to, new_hard_link, ec));
560 void
561 fs::create_hard_link(const path& to, const path& new_hard_link,
562 error_code& ec) noexcept
564 #ifdef _GLIBCXX_HAVE_LINK
565 if (::link(to.c_str(), new_hard_link.c_str()))
566 ec.assign(errno, std::generic_category());
567 else
568 ec.clear();
569 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
570 if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
571 ec.clear();
572 else
573 ec.assign((int)GetLastError(), generic_category());
574 #else
575 ec = std::make_error_code(std::errc::not_supported);
576 #endif
579 void
580 fs::create_symlink(const path& to, const path& new_symlink)
582 error_code ec;
583 create_symlink(to, new_symlink, ec);
584 if (ec.value())
585 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
586 to, new_symlink, ec));
589 void
590 fs::create_symlink(const path& to, const path& new_symlink,
591 error_code& ec) noexcept
593 #ifdef _GLIBCXX_HAVE_SYMLINK
594 if (::symlink(to.c_str(), new_symlink.c_str()))
595 ec.assign(errno, std::generic_category());
596 else
597 ec.clear();
598 #else
599 ec = std::make_error_code(std::errc::not_supported);
600 #endif
603 fs::path
604 fs::current_path()
606 error_code ec;
607 path p = current_path(ec);
608 if (ec.value())
609 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
610 return p;
613 fs::path
614 fs::current_path(error_code& ec)
616 path p;
617 #ifdef _GLIBCXX_HAVE_UNISTD_H
618 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
619 if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
621 p.assign(cwd.get());
622 ec.clear();
624 else
625 ec.assign(errno, std::generic_category());
626 #else
627 #ifdef _PC_PATH_MAX
628 long path_max = pathconf(".", _PC_PATH_MAX);
629 size_t size;
630 if (path_max == -1)
631 size = 1024;
632 else if (path_max > 10240)
633 size = 10240;
634 else
635 size = path_max;
636 #elif defined(PATH_MAX)
637 size_t size = PATH_MAX;
638 #else
639 size_t size = 1024;
640 #endif
641 for (char_ptr buf; p.empty(); size *= 2)
643 using char_type = fs::path::value_type;
644 buf.reset((char_type*)malloc(size * sizeof(char_type)));
645 if (buf)
647 if (getcwd(buf.get(), size))
649 p.assign(buf.get());
650 ec.clear();
652 else if (errno != ERANGE)
654 ec.assign(errno, std::generic_category());
655 return {};
658 else
660 ec = std::make_error_code(std::errc::not_enough_memory);
661 return {};
664 #endif // __GLIBC__
665 #else // _GLIBCXX_HAVE_UNISTD_H
666 ec = std::make_error_code(std::errc::not_supported);
667 #endif
668 return p;
671 void
672 fs::current_path(const path& p)
674 error_code ec;
675 current_path(p, ec);
676 if (ec.value())
677 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
680 void
681 fs::current_path(const path& p, error_code& ec) noexcept
683 #ifdef _GLIBCXX_HAVE_UNISTD_H
684 if (posix::chdir(p.c_str()))
685 ec.assign(errno, std::generic_category());
686 else
687 ec.clear();
688 #else
689 ec = std::make_error_code(std::errc::not_supported);
690 #endif
693 bool
694 fs::equivalent(const path& p1, const path& p2)
696 error_code ec;
697 auto result = equivalent(p1, p2, ec);
698 if (ec)
699 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
700 p1, p2, ec));
701 return result;
704 bool
705 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
707 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
708 int err = 0;
709 file_status s1, s2;
710 stat_type st1, st2;
711 if (posix::stat(p1.c_str(), &st1) == 0)
712 s1 = make_file_status(st1);
713 else if (is_not_found_errno(errno))
714 s1.type(file_type::not_found);
715 else
716 err = errno;
718 if (posix::stat(p2.c_str(), &st2) == 0)
719 s2 = make_file_status(st2);
720 else if (is_not_found_errno(errno))
721 s2.type(file_type::not_found);
722 else
723 err = errno;
725 if (exists(s1) && exists(s2))
727 if (is_other(s1) && is_other(s2))
729 ec = std::make_error_code(std::errc::not_supported);
730 return false;
732 ec.clear();
733 if (is_other(s1) || is_other(s2))
734 return false;
735 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
737 else if (!exists(s1) && !exists(s2))
738 ec = std::make_error_code(std::errc::no_such_file_or_directory);
739 else if (err)
740 ec.assign(err, std::generic_category());
741 else
742 ec.clear();
743 return false;
744 #else
745 ec = std::make_error_code(std::errc::not_supported);
746 #endif
747 return false;
750 std::uintmax_t
751 fs::file_size(const path& p)
753 error_code ec;
754 auto sz = file_size(p, ec);
755 if (ec.value())
756 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
757 return sz;
760 namespace
762 template<typename Accessor, typename T>
763 inline T
764 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
766 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
767 stat_type st;
768 if (posix::stat(p.c_str(), &st))
770 ec.assign(errno, std::generic_category());
771 return deflt;
773 ec.clear();
774 return f(st);
775 #else
776 ec = std::make_error_code(std::errc::not_supported);
777 return deflt;
778 #endif
782 std::uintmax_t
783 fs::file_size(const path& p, error_code& ec) noexcept
785 struct S
787 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
788 S() : type(file_type::not_found) { }
789 file_type type;
790 size_t size;
792 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
793 if (s.type == file_type::regular)
794 return s.size;
795 if (!ec)
797 if (s.type == file_type::directory)
798 ec = std::make_error_code(std::errc::is_a_directory);
799 else
800 ec = std::make_error_code(std::errc::not_supported);
802 return -1;
805 std::uintmax_t
806 fs::hard_link_count(const path& p)
808 error_code ec;
809 auto count = hard_link_count(p, ec);
810 if (ec.value())
811 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
812 return count;
815 std::uintmax_t
816 fs::hard_link_count(const path& p, error_code& ec) noexcept
818 return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
819 static_cast<uintmax_t>(-1));
822 bool
823 fs::is_empty(const path& p)
825 error_code ec;
826 bool e = is_empty(p, ec);
827 if (ec)
828 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
829 p, ec));
830 return e;
833 bool
834 fs::is_empty(const path& p, error_code& ec) noexcept
836 auto s = status(p, ec);
837 if (ec)
838 return false;
839 bool empty = fs::is_directory(s)
840 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
841 : fs::file_size(p, ec) == 0;
842 return ec ? false : empty;
845 fs::file_time_type
846 fs::last_write_time(const path& p)
848 error_code ec;
849 auto t = last_write_time(p, ec);
850 if (ec.value())
851 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
852 return t;
855 fs::file_time_type
856 fs::last_write_time(const path& p, error_code& ec) noexcept
858 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
859 file_time_type::min());
862 void
863 fs::last_write_time(const path& p, file_time_type new_time)
865 error_code ec;
866 last_write_time(p, new_time, ec);
867 if (ec.value())
868 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
871 void
872 fs::last_write_time(const path& p __attribute__((__unused__)),
873 file_time_type new_time, error_code& ec) noexcept
875 auto d = new_time.time_since_epoch();
876 auto s = chrono::duration_cast<chrono::seconds>(d);
877 #if _GLIBCXX_USE_UTIMENSAT
878 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
879 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
881 --s;
882 ns += chrono::seconds(1);
884 struct ::timespec ts[2];
885 ts[0].tv_sec = 0;
886 ts[0].tv_nsec = UTIME_OMIT;
887 ts[1].tv_sec = static_cast<std::time_t>(s.count());
888 ts[1].tv_nsec = static_cast<long>(ns.count());
889 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
890 ec.assign(errno, std::generic_category());
891 else
892 ec.clear();
893 #elif _GLIBCXX_HAVE_UTIME_H
894 posix::utimbuf times;
895 times.modtime = s.count();
896 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
897 times.modtime);
898 if (posix::utime(p.c_str(), &times))
899 ec.assign(errno, std::generic_category());
900 else
901 ec.clear();
902 #else
903 ec = std::make_error_code(std::errc::not_supported);
904 #endif
907 void
908 fs::permissions(const path& p, perms prms)
910 error_code ec;
911 permissions(p, prms, ec);
912 if (ec.value())
913 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
916 void
917 fs::permissions(const path& p, perms prms, error_code& ec) noexcept
919 const bool add = is_set(prms, perms::add_perms);
920 const bool remove = is_set(prms, perms::remove_perms);
921 const bool nofollow = is_set(prms, perms::symlink_nofollow);
922 if (add && remove)
924 ec = std::make_error_code(std::errc::invalid_argument);
925 return;
928 prms &= perms::mask;
930 file_status st;
931 if (add || remove || nofollow)
933 st = nofollow ? symlink_status(p, ec) : status(p, ec);
934 if (ec)
935 return;
936 auto curr = st.permissions();
937 if (add)
938 prms |= curr;
939 else if (remove)
940 prms = curr & ~prms;
943 int err = 0;
944 #if _GLIBCXX_USE_FCHMODAT
945 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
946 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
947 err = errno;
948 #else
949 if (nofollow && is_symlink(st))
950 ec = std::make_error_code(std::errc::operation_not_supported);
951 else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
952 err = errno;
953 #endif
955 if (err)
956 ec.assign(err, std::generic_category());
957 else
958 ec.clear();
961 fs::path
962 fs::read_symlink(const path& p)
964 error_code ec;
965 path tgt = read_symlink(p, ec);
966 if (ec.value())
967 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
968 return tgt;
971 fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
973 path result;
974 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
975 stat_type st;
976 if (::lstat(p.c_str(), &st))
978 ec.assign(errno, std::generic_category());
979 return result;
981 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
984 ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
985 if (len == -1)
987 ec.assign(errno, std::generic_category());
988 return result;
990 else if (len == (ssize_t)buf.size())
992 if (buf.size() > 4096)
994 ec.assign(ENAMETOOLONG, std::generic_category());
995 return result;
997 buf.resize(buf.size() * 2);
999 else
1001 buf.resize(len);
1002 result.assign(buf);
1003 ec.clear();
1004 break;
1007 while (true);
1008 #else
1009 ec = std::make_error_code(std::errc::not_supported);
1010 #endif
1011 return result;
1015 bool
1016 fs::remove(const path& p)
1018 error_code ec;
1019 bool result = fs::remove(p, ec);
1020 if (ec)
1021 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1022 return result;
1025 bool
1026 fs::remove(const path& p, error_code& ec) noexcept
1028 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1029 if (exists(symlink_status(p, ec)))
1031 if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
1032 || DeleteFileW(p.c_str()))
1034 ec.clear();
1035 return true;
1037 else if (!ec)
1038 ec.assign((int)GetLastError(), generic_category());
1040 #else
1041 if (::remove(p.c_str()) == 0)
1043 ec.clear();
1044 return true;
1046 else if (errno == ENOENT)
1047 ec.clear();
1048 else
1049 ec.assign(errno, std::generic_category());
1050 #endif
1051 return false;
1055 std::uintmax_t
1056 fs::remove_all(const path& p)
1058 error_code ec;
1059 const auto result = remove_all(p, ec);
1060 if (ec)
1061 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1062 return result;
1065 std::uintmax_t
1066 fs::remove_all(const path& p, error_code& ec) noexcept
1068 const auto s = symlink_status(p, ec);
1069 if (!status_known(s))
1070 return -1;
1072 ec.clear();
1073 if (s.type() == file_type::not_found)
1074 return 0;
1076 uintmax_t count = 0;
1077 if (s.type() == file_type::directory)
1079 for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
1080 count += fs::remove_all(d->path(), ec);
1081 if (ec.value() == ENOENT)
1082 ec.clear();
1083 else if (ec)
1084 return -1;
1087 if (fs::remove(p, ec))
1088 ++count;
1089 return ec ? -1 : count;
1092 void
1093 fs::rename(const path& from, const path& to)
1095 error_code ec;
1096 rename(from, to, ec);
1097 if (ec.value())
1098 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1101 void
1102 fs::rename(const path& from, const path& to, error_code& ec) noexcept
1104 if (posix::rename(from.c_str(), to.c_str()))
1105 ec.assign(errno, std::generic_category());
1106 else
1107 ec.clear();
1110 void
1111 fs::resize_file(const path& p, uintmax_t size)
1113 error_code ec;
1114 resize_file(p, size, ec);
1115 if (ec.value())
1116 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1119 void
1120 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1122 #ifdef _GLIBCXX_HAVE_UNISTD_H
1123 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1124 ec.assign(EINVAL, std::generic_category());
1125 else if (posix::truncate(p.c_str(), size))
1126 ec.assign(errno, std::generic_category());
1127 else
1128 ec.clear();
1129 #else
1130 ec = std::make_error_code(std::errc::not_supported);
1131 #endif
1135 fs::space_info
1136 fs::space(const path& p)
1138 error_code ec;
1139 space_info s = space(p, ec);
1140 if (ec.value())
1141 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1142 return s;
1145 fs::space_info
1146 fs::space(const path& p, error_code& ec) noexcept
1148 space_info info = {
1149 static_cast<uintmax_t>(-1),
1150 static_cast<uintmax_t>(-1),
1151 static_cast<uintmax_t>(-1)
1153 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1154 path dir = absolute(p);
1155 dir.remove_filename();
1156 auto str = dir.c_str();
1157 #else
1158 auto str = p.c_str();
1159 #endif
1160 std::filesystem::do_space(str, info.capacity, info.free, info.available, ec);
1161 return info;
1164 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1165 fs::file_status
1166 fs::status(const fs::path& p, error_code& ec) noexcept
1168 file_status status;
1169 stat_type st;
1170 if (posix::stat(p.c_str(), &st))
1172 int err = errno;
1173 ec.assign(err, std::generic_category());
1174 if (is_not_found_errno(err))
1175 status.type(file_type::not_found);
1176 #ifdef EOVERFLOW
1177 else if (err == EOVERFLOW)
1178 status.type(file_type::unknown);
1179 #endif
1181 else
1183 status = make_file_status(st);
1184 ec.clear();
1186 return status;
1189 fs::file_status
1190 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1192 file_status status;
1193 stat_type st;
1194 if (posix::lstat(p.c_str(), &st))
1196 int err = errno;
1197 ec.assign(err, std::generic_category());
1198 if (is_not_found_errno(err))
1199 status.type(file_type::not_found);
1201 else
1203 status = make_file_status(st);
1204 ec.clear();
1206 return status;
1208 #endif
1210 fs::file_status
1211 fs::status(const fs::path& p)
1213 std::error_code ec;
1214 auto result = status(p, ec);
1215 if (result.type() == file_type::none)
1216 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1217 return result;
1220 fs::file_status
1221 fs::symlink_status(const fs::path& p)
1223 std::error_code ec;
1224 auto result = symlink_status(p, ec);
1225 if (result.type() == file_type::none)
1226 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1227 return result;
1230 fs::path
1231 fs::system_complete(const path& p)
1233 error_code ec;
1234 path comp = system_complete(p, ec);
1235 if (ec.value())
1236 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1237 return comp;
1240 fs::path
1241 fs::system_complete(const path& p, error_code& ec)
1243 path base = current_path(ec);
1244 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1245 if (p.is_absolute() || !p.has_root_name()
1246 || p.root_name() == base.root_name())
1247 return absolute(p, base);
1248 // else TODO
1249 ec = std::make_error_code(std::errc::not_supported);
1250 return {};
1251 #else
1252 if (ec.value())
1253 return {};
1254 return absolute(p, base);
1255 #endif
1258 fs::path fs::temp_directory_path()
1260 error_code ec;
1261 path tmp = temp_directory_path(ec);
1262 if (ec.value())
1263 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1264 return tmp;
1267 fs::path fs::temp_directory_path(error_code& ec)
1269 path p;
1270 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1271 unsigned len = 1024;
1272 std::wstring buf;
1275 buf.resize(len);
1276 len = GetTempPathW(buf.size(), buf.data());
1277 } while (len > buf.size());
1279 if (len == 0)
1281 ec.assign((int)GetLastError(), std::system_category());
1282 return p;
1284 buf.resize(len);
1285 p = std::move(buf);
1286 #else
1287 const char* tmpdir = nullptr;
1288 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1289 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1290 tmpdir = ::getenv(*e);
1291 p = tmpdir ? tmpdir : "/tmp";
1292 auto st = status(p, ec);
1293 if (ec)
1294 p.clear();
1295 else if (!is_directory(st))
1297 p.clear();
1298 ec = std::make_error_code(std::errc::not_a_directory);
1300 #endif
1301 return p;