Use tree_vector_builder::new_unary_operation for folding
[official-gcc.git] / libstdc++-v3 / src / filesystem / ops.cc
blob1ec8883fde9c81d806587a8123e4ca26ff3fdc73
1 // Filesystem TS operations -*- C++ -*-
3 // Copyright (C) 2014-2017 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
51 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
52 namespace experimental { namespace filesystem {
53 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
54 #include "ops-common.h"
56 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
57 # undef utime
58 # define utime _wutime
59 # undef chmod
60 # define chmod _wchmod
61 #endif
63 namespace fs = std::experimental::filesystem;
65 fs::path
66 fs::absolute(const path& p, const path& base)
68 const bool has_root_dir = p.has_root_directory();
69 const bool has_root_name = p.has_root_name();
70 path abs;
71 if (has_root_dir && has_root_name)
72 abs = p;
73 else
75 abs = base.is_absolute() ? base : absolute(base);
76 if (has_root_dir)
77 abs = abs.root_name() / p;
78 else if (has_root_name)
79 abs = p.root_name() / abs.root_directory() / abs.relative_path()
80 / p.relative_path();
81 else
82 abs = abs / p;
84 return abs;
87 namespace
89 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
90 inline bool is_dot(wchar_t c) { return c == L'.'; }
91 #else
92 inline bool is_dot(char c) { return c == '.'; }
93 #endif
95 inline bool is_dot(const fs::path& path)
97 const auto& filename = path.native();
98 return filename.size() == 1 && is_dot(filename[0]);
101 inline bool is_dotdot(const fs::path& path)
103 const auto& filename = path.native();
104 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
107 struct free_as_in_malloc
109 void operator()(void* p) const { ::free(p); }
112 using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
115 fs::path
116 fs::canonical(const path& p, const path& base, error_code& ec)
118 const path pa = absolute(p, base);
119 path result;
121 #ifdef _GLIBCXX_USE_REALPATH
122 char_ptr buf{ nullptr };
123 # if _XOPEN_VERSION < 700
124 // Not safe to call realpath(path, NULL)
125 buf.reset( (char*)::malloc(PATH_MAX) );
126 # endif
127 if (char* rp = ::realpath(pa.c_str(), buf.get()))
129 if (buf == nullptr)
130 buf.reset(rp);
131 result.assign(rp);
132 ec.clear();
133 return result;
135 if (errno != ENAMETOOLONG)
137 ec.assign(errno, std::generic_category());
138 return result;
140 #endif
142 if (!exists(pa, ec))
144 if (!ec)
145 ec = make_error_code(std::errc::no_such_file_or_directory);
146 return result;
148 // else: we know there are (currently) no unresolvable symlink loops
150 result = pa.root_path();
152 deque<path> cmpts;
153 for (auto& f : pa.relative_path())
154 cmpts.push_back(f);
156 int max_allowed_symlinks = 40;
158 while (!cmpts.empty() && !ec)
160 path f = std::move(cmpts.front());
161 cmpts.pop_front();
163 if (is_dot(f))
165 if (!is_directory(result, ec) && !ec)
166 ec.assign(ENOTDIR, std::generic_category());
168 else if (is_dotdot(f))
170 auto parent = result.parent_path();
171 if (parent.empty())
172 result = pa.root_path();
173 else
174 result.swap(parent);
176 else
178 result /= f;
180 if (is_symlink(result, ec))
182 path link = read_symlink(result, ec);
183 if (!ec)
185 if (--max_allowed_symlinks == 0)
186 ec.assign(ELOOP, std::generic_category());
187 else
189 if (link.is_absolute())
191 result = link.root_path();
192 link = link.relative_path();
194 else
195 result.remove_filename();
197 cmpts.insert(cmpts.begin(), link.begin(), link.end());
204 if (ec || !exists(result, ec))
205 result.clear();
207 return result;
210 fs::path
211 fs::canonical(const path& p, error_code& ec)
213 path cur = current_path(ec);
214 if (ec.value())
215 return {};
216 return canonical(p, cur, ec);
219 fs::path
220 fs::canonical(const path& p, const path& base)
222 error_code ec;
223 path can = canonical(p, base, ec);
224 if (ec)
225 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, base,
226 ec));
227 return can;
230 void
231 fs::copy(const path& from, const path& to, copy_options options)
233 error_code ec;
234 copy(from, to, options, ec);
235 if (ec.value())
236 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
239 namespace
241 using std::filesystem::is_set;
243 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
244 typedef struct ::stat stat_type;
246 using std::filesystem::is_not_found_errno;
247 using std::filesystem::file_time;
248 using std::filesystem::do_copy_file;
249 #endif // _GLIBCXX_HAVE_SYS_STAT_H
250 } // namespace
252 void
253 fs::copy(const path& from, const path& to, copy_options options,
254 error_code& ec) noexcept
256 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
257 const bool create_symlinks = is_set(options, copy_options::create_symlinks);
258 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
259 const bool use_lstat = create_symlinks || skip_symlinks;
261 file_status f, t;
262 stat_type from_st, to_st;
263 // _GLIBCXX_RESOLVE_LIB_DEFECTS
264 // 2681. filesystem::copy() cannot copy symlinks
265 if (use_lstat || copy_symlinks
266 ? ::lstat(from.c_str(), &from_st)
267 : ::stat(from.c_str(), &from_st))
269 ec.assign(errno, std::generic_category());
270 return;
272 if (use_lstat
273 ? ::lstat(to.c_str(), &to_st)
274 : ::stat(to.c_str(), &to_st))
276 if (!is_not_found_errno(errno))
278 ec.assign(errno, std::generic_category());
279 return;
281 t = file_status{file_type::not_found};
283 else
284 t = make_file_status(to_st);
285 f = make_file_status(from_st);
287 if (exists(t) && !is_other(t) && !is_other(f)
288 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
290 ec = std::make_error_code(std::errc::file_exists);
291 return;
293 if (is_other(f) || is_other(t))
295 ec = std::make_error_code(std::errc::not_supported);
296 return;
298 if (is_directory(f) && is_regular_file(t))
300 ec = std::make_error_code(std::errc::is_a_directory);
301 return;
304 if (is_symlink(f))
306 if (skip_symlinks)
307 ec.clear();
308 else if (!exists(t) && copy_symlinks)
309 copy_symlink(from, to, ec);
310 else
311 // Not clear what should be done here.
312 // "Otherwise report an error as specified in Error reporting (7)."
313 ec = std::make_error_code(std::errc::invalid_argument);
315 else if (is_regular_file(f))
317 if (is_set(options, copy_options::directories_only))
318 ec.clear();
319 else if (create_symlinks)
320 create_symlink(from, to, ec);
321 else if (is_set(options, copy_options::create_hard_links))
322 create_hard_link(from, to, ec);
323 else if (is_directory(t))
324 do_copy_file(from.c_str(), (to / from.filename()).c_str(),
325 copy_file_options(options), &from_st, nullptr, ec);
326 else
328 auto ptr = exists(t) ? &to_st : &from_st;
329 do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
330 &from_st, ptr, ec);
333 // _GLIBCXX_RESOLVE_LIB_DEFECTS
334 // 2682. filesystem::copy() won't create a symlink to a directory
335 else if (is_directory(f) && create_symlinks)
336 ec = std::make_error_code(errc::is_a_directory);
337 else if (is_directory(f) && (is_set(options, copy_options::recursive)
338 || options == copy_options::none))
340 if (!exists(t))
341 if (!create_directory(to, from, ec))
342 return;
343 // set an unused bit in options to disable further recursion
344 if (!is_set(options, copy_options::recursive))
345 options |= static_cast<copy_options>(4096);
346 for (const directory_entry& x : directory_iterator(from))
347 copy(x.path(), to/x.path().filename(), options, ec);
349 // _GLIBCXX_RESOLVE_LIB_DEFECTS
350 // 2683. filesystem::copy() says "no effects"
351 else
352 ec.clear();
355 bool
356 fs::copy_file(const path& from, const path& to, copy_options option)
358 error_code ec;
359 bool result = copy_file(from, to, option, ec);
360 if (ec.value())
361 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
362 ec));
363 return result;
366 bool
367 fs::copy_file(const path& from, const path& to, copy_options options,
368 error_code& ec) noexcept
370 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
371 return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
372 nullptr, nullptr, ec);
373 #else
374 ec = std::make_error_code(std::errc::not_supported);
375 return false;
376 #endif
380 void
381 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
383 error_code ec;
384 copy_symlink(existing_symlink, new_symlink, ec);
385 if (ec.value())
386 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
387 existing_symlink, new_symlink, ec));
390 void
391 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
392 error_code& ec) noexcept
394 auto p = read_symlink(existing_symlink, ec);
395 if (ec.value())
396 return;
397 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
398 if (is_directory(p))
400 create_directory_symlink(p, new_symlink, ec);
401 return;
403 #endif
404 create_symlink(p, new_symlink, ec);
408 bool
409 fs::create_directories(const path& p)
411 error_code ec;
412 bool result = create_directories(p, ec);
413 if (ec.value())
414 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
415 ec));
416 return result;
419 bool
420 fs::create_directories(const path& p, error_code& ec) noexcept
422 if (p.empty())
424 ec = std::make_error_code(errc::invalid_argument);
425 return false;
427 std::stack<path> missing;
428 path pp = p;
430 while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
432 ec.clear();
433 const auto& filename = pp.filename();
434 if (!is_dot(filename) && !is_dotdot(filename))
435 missing.push(pp);
436 pp.remove_filename();
439 if (ec || missing.empty())
440 return false;
444 const path& top = missing.top();
445 create_directory(top, ec);
446 if (ec && is_directory(top))
447 ec.clear();
448 missing.pop();
450 while (!missing.empty() && !ec);
452 return missing.empty();
455 namespace
457 bool
458 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
460 bool created = false;
461 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
462 ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
463 if (::mkdir(p.c_str(), mode))
465 const int err = errno;
466 if (err != EEXIST || !is_directory(p))
467 ec.assign(err, std::generic_category());
468 else
469 ec.clear();
471 else
473 ec.clear();
474 created = true;
476 #else
477 ec = std::make_error_code(std::errc::not_supported);
478 #endif
479 return created;
481 } // namespace
483 bool
484 fs::create_directory(const path& p)
486 error_code ec;
487 bool result = create_directory(p, ec);
488 if (ec.value())
489 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
490 ec));
491 return result;
494 bool
495 fs::create_directory(const path& p, error_code& ec) noexcept
497 return create_dir(p, perms::all, ec);
501 bool
502 fs::create_directory(const path& p, const path& attributes)
504 error_code ec;
505 bool result = create_directory(p, attributes, ec);
506 if (ec.value())
507 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
508 ec));
509 return result;
512 bool
513 fs::create_directory(const path& p, const path& attributes,
514 error_code& ec) noexcept
516 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
517 stat_type st;
518 if (::stat(attributes.c_str(), &st))
520 ec.assign(errno, std::generic_category());
521 return false;
523 return create_dir(p, static_cast<perms>(st.st_mode), ec);
524 #else
525 ec = std::make_error_code(std::errc::not_supported);
526 return false;
527 #endif
531 void
532 fs::create_directory_symlink(const path& to, const path& new_symlink)
534 error_code ec;
535 create_directory_symlink(to, new_symlink, ec);
536 if (ec.value())
537 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
538 to, new_symlink, ec));
541 void
542 fs::create_directory_symlink(const path& to, const path& new_symlink,
543 error_code& ec) noexcept
545 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
546 ec = std::make_error_code(std::errc::not_supported);
547 #else
548 create_symlink(to, new_symlink, ec);
549 #endif
553 void
554 fs::create_hard_link(const path& to, const path& new_hard_link)
556 error_code ec;
557 create_hard_link(to, new_hard_link, ec);
558 if (ec.value())
559 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
560 to, new_hard_link, ec));
563 void
564 fs::create_hard_link(const path& to, const path& new_hard_link,
565 error_code& ec) noexcept
567 #ifdef _GLIBCXX_HAVE_UNISTD_H
568 if (::link(to.c_str(), new_hard_link.c_str()))
569 ec.assign(errno, std::generic_category());
570 else
571 ec.clear();
572 #else
573 ec = std::make_error_code(std::errc::not_supported);
574 #endif
577 void
578 fs::create_symlink(const path& to, const path& new_symlink)
580 error_code ec;
581 create_symlink(to, new_symlink, ec);
582 if (ec.value())
583 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
584 to, new_symlink, ec));
587 void
588 fs::create_symlink(const path& to, const path& new_symlink,
589 error_code& ec) noexcept
591 #ifdef _GLIBCXX_HAVE_UNISTD_H
592 if (::symlink(to.c_str(), new_symlink.c_str()))
593 ec.assign(errno, std::generic_category());
594 else
595 ec.clear();
596 #else
597 ec = std::make_error_code(std::errc::not_supported);
598 #endif
602 fs::path
603 fs::current_path()
605 error_code ec;
606 path p = current_path(ec);
607 if (ec.value())
608 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
609 return p;
612 fs::path
613 fs::current_path(error_code& ec)
615 path p;
616 #ifdef _GLIBCXX_HAVE_UNISTD_H
617 #ifdef __GLIBC__
618 if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
620 p.assign(cwd.get());
621 ec.clear();
623 else
624 ec.assign(errno, std::generic_category());
625 #else
626 long path_max = pathconf(".", _PC_PATH_MAX);
627 size_t size;
628 if (path_max == -1)
629 size = 1024;
630 else if (path_max > 10240)
631 size = 10240;
632 else
633 size = path_max;
634 for (char_ptr buf; p.empty(); size *= 2)
636 buf.reset((char*)malloc(size));
637 if (buf)
639 if (getcwd(buf.get(), size))
641 p.assign(buf.get());
642 ec.clear();
644 else if (errno != ERANGE)
646 ec.assign(errno, std::generic_category());
647 return {};
650 else
652 ec = std::make_error_code(std::errc::not_enough_memory);
653 return {};
656 #endif // __GLIBC__
657 #else // _GLIBCXX_HAVE_UNISTD_H
658 ec = std::make_error_code(std::errc::not_supported);
659 #endif
660 return p;
663 void
664 fs::current_path(const path& p)
666 error_code ec;
667 current_path(p, ec);
668 if (ec.value())
669 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
672 void
673 fs::current_path(const path& p, error_code& ec) noexcept
675 #ifdef _GLIBCXX_HAVE_UNISTD_H
676 if (::chdir(p.c_str()))
677 ec.assign(errno, std::generic_category());
678 else
679 ec.clear();
680 #else
681 ec = std::make_error_code(std::errc::not_supported);
682 #endif
685 bool
686 fs::equivalent(const path& p1, const path& p2)
688 error_code ec;
689 auto result = equivalent(p1, p2, ec);
690 if (ec)
691 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
692 p1, p2, ec));
693 return result;
696 bool
697 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
699 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
700 int err = 0;
701 file_status s1, s2;
702 stat_type st1, st2;
703 if (::stat(p1.c_str(), &st1) == 0)
704 s1 = make_file_status(st1);
705 else if (is_not_found_errno(errno))
706 s1.type(file_type::not_found);
707 else
708 err = errno;
710 if (::stat(p2.c_str(), &st2) == 0)
711 s2 = make_file_status(st2);
712 else if (is_not_found_errno(errno))
713 s2.type(file_type::not_found);
714 else
715 err = errno;
717 if (exists(s1) && exists(s2))
719 if (is_other(s1) && is_other(s2))
721 ec = std::make_error_code(std::errc::not_supported);
722 return false;
724 ec.clear();
725 if (is_other(s1) || is_other(s2))
726 return false;
727 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
729 else if (!exists(s1) && !exists(s2))
730 ec = std::make_error_code(std::errc::no_such_file_or_directory);
731 else if (err)
732 ec.assign(err, std::generic_category());
733 else
734 ec.clear();
735 return false;
736 #else
737 ec = std::make_error_code(std::errc::not_supported);
738 #endif
739 return false;
742 std::uintmax_t
743 fs::file_size(const path& p)
745 error_code ec;
746 auto sz = file_size(p, ec);
747 if (ec.value())
748 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
749 return sz;
752 namespace
754 template<typename Accessor, typename T>
755 inline T
756 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
758 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
759 stat_type st;
760 if (::stat(p.c_str(), &st))
762 ec.assign(errno, std::generic_category());
763 return deflt;
765 ec.clear();
766 return f(st);
767 #else
768 ec = std::make_error_code(std::errc::not_supported);
769 return deflt;
770 #endif
774 std::uintmax_t
775 fs::file_size(const path& p, error_code& ec) noexcept
777 struct S
779 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
780 S() : type(file_type::not_found) { }
781 file_type type;
782 size_t size;
784 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
785 if (s.type == file_type::regular)
786 return s.size;
787 if (!ec)
789 if (s.type == file_type::directory)
790 ec = std::make_error_code(std::errc::is_a_directory);
791 else
792 ec = std::make_error_code(std::errc::not_supported);
794 return -1;
797 std::uintmax_t
798 fs::hard_link_count(const path& p)
800 error_code ec;
801 auto count = hard_link_count(p, ec);
802 if (ec.value())
803 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
804 return count;
807 std::uintmax_t
808 fs::hard_link_count(const path& p, error_code& ec) noexcept
810 return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
811 static_cast<uintmax_t>(-1));
814 bool
815 fs::is_empty(const path& p)
817 error_code ec;
818 bool e = is_empty(p, ec);
819 if (ec)
820 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
821 p, ec));
822 return e;
825 bool
826 fs::is_empty(const path& p, error_code& ec) noexcept
828 auto s = status(p, ec);
829 if (ec)
830 return false;
831 bool empty = fs::is_directory(s)
832 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
833 : fs::file_size(p, ec) == 0;
834 return ec ? false : empty;
837 fs::file_time_type
838 fs::last_write_time(const path& p)
840 error_code ec;
841 auto t = last_write_time(p, ec);
842 if (ec.value())
843 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
844 return t;
847 fs::file_time_type
848 fs::last_write_time(const path& p, error_code& ec) noexcept
850 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
851 file_time_type::min());
854 void
855 fs::last_write_time(const path& p, file_time_type new_time)
857 error_code ec;
858 last_write_time(p, new_time, ec);
859 if (ec.value())
860 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
863 void
864 fs::last_write_time(const path& p __attribute__((__unused__)),
865 file_time_type new_time, error_code& ec) noexcept
867 auto d = new_time.time_since_epoch();
868 auto s = chrono::duration_cast<chrono::seconds>(d);
869 #if _GLIBCXX_USE_UTIMENSAT
870 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
871 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
873 --s;
874 ns += chrono::seconds(1);
876 struct ::timespec ts[2];
877 ts[0].tv_sec = 0;
878 ts[0].tv_nsec = UTIME_OMIT;
879 ts[1].tv_sec = static_cast<std::time_t>(s.count());
880 ts[1].tv_nsec = static_cast<long>(ns.count());
881 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
882 ec.assign(errno, std::generic_category());
883 else
884 ec.clear();
885 #elif _GLIBCXX_HAVE_UTIME_H
886 ::utimbuf times;
887 times.modtime = s.count();
888 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
889 times.modtime);
890 if (::utime(p.c_str(), &times))
891 ec.assign(errno, std::generic_category());
892 else
893 ec.clear();
894 #else
895 ec = std::make_error_code(std::errc::not_supported);
896 #endif
899 void
900 fs::permissions(const path& p, perms prms)
902 error_code ec;
903 permissions(p, prms, ec);
904 if (ec.value())
905 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
908 void
909 fs::permissions(const path& p, perms prms, error_code& ec) noexcept
911 const bool add = is_set(prms, perms::add_perms);
912 const bool remove = is_set(prms, perms::remove_perms);
913 const bool nofollow = is_set(prms, perms::symlink_nofollow);
914 if (add && remove)
916 ec = std::make_error_code(std::errc::invalid_argument);
917 return;
920 prms &= perms::mask;
922 file_status st;
923 if (add || remove || nofollow)
925 st = nofollow ? symlink_status(p, ec) : status(p, ec);
926 if (ec)
927 return;
928 auto curr = st.permissions();
929 if (add)
930 prms |= curr;
931 else if (remove)
932 prms = curr & ~prms;
935 int err = 0;
936 #if _GLIBCXX_USE_FCHMODAT
937 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
938 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
939 err = errno;
940 #else
941 if (nofollow && is_symlink(st))
942 ec = std::make_error_code(std::errc::operation_not_supported);
943 else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
944 err = errno;
945 #endif
947 if (err)
948 ec.assign(err, std::generic_category());
949 else
950 ec.clear();
953 fs::path
954 fs::read_symlink(const path& p)
956 error_code ec;
957 path tgt = read_symlink(p, ec);
958 if (ec.value())
959 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
960 return tgt;
963 fs::path fs::read_symlink(const path& p, error_code& ec)
965 path result;
966 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
967 stat_type st;
968 if (::lstat(p.c_str(), &st))
970 ec.assign(errno, std::generic_category());
971 return result;
973 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
976 ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
977 if (len == -1)
979 ec.assign(errno, std::generic_category());
980 return result;
982 else if (len == (ssize_t)buf.size())
984 if (buf.size() > 4096)
986 ec.assign(ENAMETOOLONG, std::generic_category());
987 return result;
989 buf.resize(buf.size() * 2);
991 else
993 buf.resize(len);
994 result.assign(buf);
995 ec.clear();
996 break;
999 while (true);
1000 #else
1001 ec = std::make_error_code(std::errc::not_supported);
1002 #endif
1003 return result;
1007 bool
1008 fs::remove(const path& p)
1010 error_code ec;
1011 bool result = fs::remove(p, ec);
1012 if (ec.value())
1013 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1014 return result;
1017 bool
1018 fs::remove(const path& p, error_code& ec) noexcept
1020 if (exists(symlink_status(p, ec)))
1022 if (::remove(p.c_str()) == 0)
1024 ec.clear();
1025 return true;
1027 else
1028 ec.assign(errno, std::generic_category());
1030 return false;
1034 std::uintmax_t
1035 fs::remove_all(const path& p)
1037 error_code ec;
1038 bool result = remove_all(p, ec);
1039 if (ec.value())
1040 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1041 return result;
1044 std::uintmax_t
1045 fs::remove_all(const path& p, error_code& ec) noexcept
1047 auto fs = symlink_status(p, ec);
1048 uintmax_t count = 0;
1049 if (ec.value() == 0 && fs.type() == file_type::directory)
1050 for (directory_iterator d(p, ec), end; ec.value() == 0 && d != end; ++d)
1051 count += fs::remove_all(d->path(), ec);
1052 if (ec.value())
1053 return -1;
1054 return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear()
1057 void
1058 fs::rename(const path& from, const path& to)
1060 error_code ec;
1061 rename(from, to, ec);
1062 if (ec.value())
1063 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1066 void
1067 fs::rename(const path& from, const path& to, error_code& ec) noexcept
1069 if (::rename(from.c_str(), to.c_str()))
1070 ec.assign(errno, std::generic_category());
1071 else
1072 ec.clear();
1075 void
1076 fs::resize_file(const path& p, uintmax_t size)
1078 error_code ec;
1079 resize_file(p, size, ec);
1080 if (ec.value())
1081 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1084 void
1085 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1087 #ifdef _GLIBCXX_HAVE_UNISTD_H
1088 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1089 ec.assign(EINVAL, std::generic_category());
1090 else if (::truncate(p.c_str(), size))
1091 ec.assign(errno, std::generic_category());
1092 else
1093 ec.clear();
1094 #else
1095 ec = std::make_error_code(std::errc::not_supported);
1096 #endif
1100 fs::space_info
1101 fs::space(const path& p)
1103 error_code ec;
1104 space_info s = space(p, ec);
1105 if (ec.value())
1106 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1107 return s;
1110 fs::space_info
1111 fs::space(const path& p, error_code& ec) noexcept
1113 space_info info = {
1114 static_cast<uintmax_t>(-1),
1115 static_cast<uintmax_t>(-1),
1116 static_cast<uintmax_t>(-1)
1118 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1119 struct ::statvfs f;
1120 if (::statvfs(p.c_str(), &f))
1121 ec.assign(errno, std::generic_category());
1122 else
1124 info = space_info{
1125 f.f_blocks * f.f_frsize,
1126 f.f_bfree * f.f_frsize,
1127 f.f_bavail * f.f_frsize
1129 ec.clear();
1131 #else
1132 ec = std::make_error_code(std::errc::not_supported);
1133 #endif
1134 return info;
1137 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1138 fs::file_status
1139 fs::status(const fs::path& p, error_code& ec) noexcept
1141 file_status status;
1142 stat_type st;
1143 if (::stat(p.c_str(), &st))
1145 int err = errno;
1146 ec.assign(err, std::generic_category());
1147 if (is_not_found_errno(err))
1148 status.type(file_type::not_found);
1149 #ifdef EOVERFLOW
1150 else if (err == EOVERFLOW)
1151 status.type(file_type::unknown);
1152 #endif
1154 else
1156 status = make_file_status(st);
1157 ec.clear();
1159 return status;
1162 fs::file_status
1163 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1165 file_status status;
1166 stat_type st;
1167 if (::lstat(p.c_str(), &st))
1169 int err = errno;
1170 ec.assign(err, std::generic_category());
1171 if (is_not_found_errno(err))
1172 status.type(file_type::not_found);
1174 else
1176 status = make_file_status(st);
1177 ec.clear();
1179 return status;
1181 #endif
1183 fs::file_status
1184 fs::status(const fs::path& p)
1186 std::error_code ec;
1187 auto result = status(p, ec);
1188 if (result.type() == file_type::none)
1189 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1190 return result;
1193 fs::file_status
1194 fs::symlink_status(const fs::path& p)
1196 std::error_code ec;
1197 auto result = symlink_status(p, ec);
1198 if (result.type() == file_type::none)
1199 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1200 return result;
1203 fs::path
1204 fs::system_complete(const path& p)
1206 error_code ec;
1207 path comp = system_complete(p, ec);
1208 if (ec.value())
1209 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1210 return comp;
1213 fs::path
1214 fs::system_complete(const path& p, error_code& ec)
1216 path base = current_path(ec);
1217 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1218 if (p.is_absolute() || !p.has_root_name()
1219 || p.root_name() == base.root_name())
1220 return absolute(p, base);
1221 // else TODO
1222 ec = std::make_error_code(std::errc::not_supported);
1223 return {};
1224 #else
1225 if (ec.value())
1226 return {};
1227 return absolute(p, base);
1228 #endif
1231 fs::path fs::temp_directory_path()
1233 error_code ec;
1234 path tmp = temp_directory_path(ec);
1235 if (ec.value())
1236 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1237 return tmp;
1240 fs::path fs::temp_directory_path(error_code& ec)
1242 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1243 ec = std::make_error_code(std::errc::not_supported);
1244 return {}; // TODO
1245 #else
1246 const char* tmpdir = nullptr;
1247 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1248 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1249 tmpdir = ::getenv(*e);
1250 path p = tmpdir ? tmpdir : "/tmp";
1251 auto st = status(p, ec);
1252 if (!ec)
1254 if (is_directory(st))
1256 ec.clear();
1257 return p;
1259 else
1260 ec = std::make_error_code(std::errc::not_a_directory);
1262 return {};
1263 #endif