PR libstdc++/79283 fix filesystem::read_symlink for /proc
[official-gcc.git] / libstdc++-v3 / src / filesystem / std-ops.cc
blob947be7ef4c568362095ab7e5ab7497a64d058da9
1 // Filesystem 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 # define NEED_DO_COPY_FILE
28 #endif
30 #include <filesystem>
31 #include <experimental/filesystem>
32 #include <functional>
33 #include <ostream>
34 #include <stack>
35 #include <ext/stdio_filebuf.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <limits.h> // PATH_MAX
40 #ifdef _GLIBCXX_HAVE_FCNTL_H
41 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
42 #endif
43 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
44 # include <sys/stat.h> // stat, utimensat, fchmodat
45 #endif
46 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
47 # include <sys/statvfs.h> // statvfs
48 #endif
49 #ifdef _GLIBCXX_USE_SENDFILE
50 # include <sys/sendfile.h> // sendfile
51 #endif
52 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
53 # include <utime.h> // utime
54 #endif
56 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
57 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
58 #include "ops-common.h"
60 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
61 # undef utime
62 # define utime _wutime
63 # undef chmod
64 # define chmod _wchmod
65 #endif
67 namespace fs = std::filesystem;
69 fs::path
70 fs::absolute(const path& p)
72 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
73 error_code ec;
74 path ret = absolute(p, ec);
75 if (ec)
76 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
77 std::make_error_code(errc::not_supported)));
78 return ret;
79 #else
80 return current_path() / p;
81 #endif
84 fs::path
85 fs::absolute(const path& p, error_code& ec)
87 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
88 ec = std::make_error_code(errc::not_supported);
89 return {};
90 #else
91 ec.clear();
92 return current_path() / p;
93 #endif
96 namespace
98 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
99 inline bool is_dot(wchar_t c) { return c == L'.'; }
100 #else
101 inline bool is_dot(char c) { return c == '.'; }
102 #endif
104 inline bool is_dot(const fs::path& path)
106 const auto& filename = path.native();
107 return filename.size() == 1 && is_dot(filename[0]);
110 inline bool is_dotdot(const fs::path& path)
112 const auto& filename = path.native();
113 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
116 struct free_as_in_malloc
118 void operator()(void* p) const { ::free(p); }
121 using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
124 fs::path
125 fs::canonical(const path& p, error_code& ec)
127 path result;
128 const path pa = absolute(p, ec);
129 if (ec)
130 return result;
132 #ifdef _GLIBCXX_USE_REALPATH
133 char_ptr buf{ nullptr };
134 # if _XOPEN_VERSION < 700
135 // Not safe to call realpath(path, NULL)
136 buf.reset( (char*)::malloc(PATH_MAX) );
137 # endif
138 if (char* rp = ::realpath(pa.c_str(), buf.get()))
140 if (buf == nullptr)
141 buf.reset(rp);
142 result.assign(rp);
143 ec.clear();
144 return result;
146 if (errno != ENAMETOOLONG)
148 ec.assign(errno, std::generic_category());
149 return result;
151 #endif
153 if (!exists(pa, ec))
155 if (!ec)
156 ec = make_error_code(std::errc::no_such_file_or_directory);
157 return result;
159 // else: we know there are (currently) no unresolvable symlink loops
161 result = pa.root_path();
163 deque<path> cmpts;
164 for (auto& f : pa.relative_path())
165 cmpts.push_back(f);
167 int max_allowed_symlinks = 40;
169 while (!cmpts.empty() && !ec)
171 path f = std::move(cmpts.front());
172 cmpts.pop_front();
174 if (f.empty())
176 // ignore empty element
178 else if (is_dot(f))
180 if (!is_directory(result, ec) && !ec)
181 ec.assign(ENOTDIR, std::generic_category());
183 else if (is_dotdot(f))
185 auto parent = result.parent_path();
186 if (parent.empty())
187 result = pa.root_path();
188 else
189 result.swap(parent);
191 else
193 result /= f;
195 if (is_symlink(result, ec))
197 path link = read_symlink(result, ec);
198 if (!ec)
200 if (--max_allowed_symlinks == 0)
201 ec.assign(ELOOP, std::generic_category());
202 else
204 if (link.is_absolute())
206 result = link.root_path();
207 link = link.relative_path();
209 else
210 result = result.parent_path();
212 cmpts.insert(cmpts.begin(), link.begin(), link.end());
219 if (ec || !exists(result, ec))
220 result.clear();
222 return result;
225 fs::path
226 fs::canonical(const path& p)
228 error_code ec;
229 path res = canonical(p, ec);
230 if (ec)
231 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
232 p, ec));
233 return res;
236 void
237 fs::copy(const path& from, const path& to, copy_options options)
239 error_code ec;
240 copy(from, to, options, ec);
241 if (ec)
242 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
245 namespace std::filesystem
247 // Need this as there's no 'perm_options::none' enumerator.
248 inline bool is_set(fs::perm_options obj, fs::perm_options bits)
250 return (obj & bits) != fs::perm_options{};
254 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
255 #ifdef NEED_DO_COPY_FILE
256 bool
257 fs::do_copy_file(const char* from, const char* to,
258 copy_options_existing_file options,
259 stat_type* from_st, stat_type* to_st,
260 std::error_code& ec) noexcept
262 stat_type st1, st2;
263 fs::file_status t, f;
265 if (to_st == nullptr)
267 if (::stat(to, &st1))
269 const int err = errno;
270 if (!is_not_found_errno(err))
272 ec.assign(err, std::generic_category());
273 return false;
276 else
277 to_st = &st1;
279 else if (to_st == from_st)
280 to_st = nullptr;
282 if (to_st == nullptr)
283 t = fs::file_status{fs::file_type::not_found};
284 else
285 t = make_file_status(*to_st);
287 if (from_st == nullptr)
289 if (::stat(from, &st2))
291 ec.assign(errno, std::generic_category());
292 return false;
294 else
295 from_st = &st2;
297 f = make_file_status(*from_st);
298 // _GLIBCXX_RESOLVE_LIB_DEFECTS
299 // 2712. copy_file() has a number of unspecified error conditions
300 if (!is_regular_file(f))
302 ec = std::make_error_code(std::errc::not_supported);
303 return false;
306 if (exists(t))
308 if (!is_regular_file(t))
310 ec = std::make_error_code(std::errc::not_supported);
311 return false;
314 if (to_st->st_dev == from_st->st_dev
315 && to_st->st_ino == from_st->st_ino)
317 ec = std::make_error_code(std::errc::file_exists);
318 return false;
321 if (options.skip)
323 ec.clear();
324 return false;
326 else if (options.update)
328 const auto from_mtime = file_time(*from_st, ec);
329 if (ec)
330 return false;
331 if ((from_mtime <= file_time(*to_st, ec)) || ec)
332 return false;
334 else if (!options.overwrite)
336 ec = std::make_error_code(std::errc::file_exists);
337 return false;
339 else if (!is_regular_file(t))
341 ec = std::make_error_code(std::errc::not_supported);
342 return false;
346 struct CloseFD {
347 ~CloseFD() { if (fd != -1) ::close(fd); }
348 bool close() { return ::close(std::exchange(fd, -1)) == 0; }
349 int fd;
352 CloseFD in = { ::open(from, O_RDONLY) };
353 if (in.fd == -1)
355 ec.assign(errno, std::generic_category());
356 return false;
358 int oflag = O_WRONLY|O_CREAT;
359 if (options.overwrite || options.update)
360 oflag |= O_TRUNC;
361 else
362 oflag |= O_EXCL;
363 CloseFD out = { ::open(to, oflag, S_IWUSR) };
364 if (out.fd == -1)
366 if (errno == EEXIST && options.skip)
367 ec.clear();
368 else
369 ec.assign(errno, std::generic_category());
370 return false;
373 #ifdef _GLIBCXX_USE_FCHMOD
374 if (::fchmod(out.fd, from_st->st_mode))
375 #elif defined _GLIBCXX_USE_FCHMODAT
376 if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
377 #else
378 if (::chmod(to, from_st->st_mode))
379 #endif
381 ec.assign(errno, std::generic_category());
382 return false;
385 #ifdef _GLIBCXX_USE_SENDFILE
386 off_t offset = 0;
387 const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
388 if (n < 0 && (errno == ENOSYS || errno == EINVAL))
390 #endif // _GLIBCXX_USE_SENDFILE
391 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
392 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
393 if (sbin.is_open())
394 in.fd = -1;
395 if (sbout.is_open())
396 out.fd = -1;
397 if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
399 ec = std::make_error_code(std::errc::io_error);
400 return false;
402 if (!sbout.close() || !sbin.close())
404 ec.assign(errno, std::generic_category());
405 return false;
408 ec.clear();
409 return true;
411 #ifdef _GLIBCXX_USE_SENDFILE
413 if (n != from_st->st_size)
415 ec.assign(errno, std::generic_category());
416 return false;
418 if (!out.close() || !in.close())
420 ec.assign(errno, std::generic_category());
421 return false;
424 ec.clear();
425 return true;
426 #endif // _GLIBCXX_USE_SENDFILE
428 #endif // NEED_DO_COPY_FILE
429 #endif // _GLIBCXX_HAVE_SYS_STAT_H
431 void
432 fs::copy(const path& from, const path& to, copy_options options,
433 error_code& ec) noexcept
435 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
436 const bool create_symlinks = is_set(options, copy_options::create_symlinks);
437 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
438 const bool use_lstat = create_symlinks || skip_symlinks;
440 file_status f, t;
441 stat_type from_st, to_st;
442 // _GLIBCXX_RESOLVE_LIB_DEFECTS
443 // 2681. filesystem::copy() cannot copy symlinks
444 if (use_lstat || copy_symlinks
445 ? ::lstat(from.c_str(), &from_st)
446 : ::stat(from.c_str(), &from_st))
448 ec.assign(errno, std::generic_category());
449 return;
451 if (use_lstat
452 ? ::lstat(to.c_str(), &to_st)
453 : ::stat(to.c_str(), &to_st))
455 if (!is_not_found_errno(errno))
457 ec.assign(errno, std::generic_category());
458 return;
460 t = file_status{file_type::not_found};
462 else
463 t = make_file_status(to_st);
464 f = make_file_status(from_st);
466 if (exists(t) && !is_other(t) && !is_other(f)
467 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
469 ec = std::make_error_code(std::errc::file_exists);
470 return;
472 if (is_other(f) || is_other(t))
474 ec = std::make_error_code(std::errc::not_supported);
475 return;
477 if (is_directory(f) && is_regular_file(t))
479 ec = std::make_error_code(std::errc::is_a_directory);
480 return;
483 if (is_symlink(f))
485 if (skip_symlinks)
486 ec.clear();
487 else if (!exists(t) && copy_symlinks)
488 copy_symlink(from, to, ec);
489 else
490 // Not clear what should be done here.
491 // "Otherwise report an error as specified in Error reporting (7)."
492 ec = std::make_error_code(std::errc::invalid_argument);
494 else if (is_regular_file(f))
496 if (is_set(options, copy_options::directories_only))
497 ec.clear();
498 else if (create_symlinks)
499 create_symlink(from, to, ec);
500 else if (is_set(options, copy_options::create_hard_links))
501 create_hard_link(from, to, ec);
502 else if (is_directory(t))
503 do_copy_file(from.c_str(), (to / from.filename()).c_str(),
504 copy_file_options(options), &from_st, nullptr, ec);
505 else
507 auto ptr = exists(t) ? &to_st : &from_st;
508 do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
509 &from_st, ptr, ec);
512 // _GLIBCXX_RESOLVE_LIB_DEFECTS
513 // 2682. filesystem::copy() won't create a symlink to a directory
514 else if (is_directory(f) && create_symlinks)
515 ec = std::make_error_code(errc::is_a_directory);
516 else if (is_directory(f) && (is_set(options, copy_options::recursive)
517 || options == copy_options::none))
519 if (!exists(t))
520 if (!create_directory(to, from, ec))
521 return;
522 // set an unused bit in options to disable further recursion
523 if (!is_set(options, copy_options::recursive))
524 options |= static_cast<copy_options>(4096);
525 for (const directory_entry& x : directory_iterator(from))
526 copy(x.path(), to/x.path().filename(), options, ec);
528 // _GLIBCXX_RESOLVE_LIB_DEFECTS
529 // 2683. filesystem::copy() says "no effects"
530 else
531 ec.clear();
534 bool
535 fs::copy_file(const path& from, const path& to, copy_options option)
537 error_code ec;
538 bool result = copy_file(from, to, option, ec);
539 if (ec)
540 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
541 ec));
542 return result;
545 bool
546 fs::copy_file(const path& from, const path& to, copy_options options,
547 error_code& ec) noexcept
549 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
550 return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
551 nullptr, nullptr, ec);
552 #else
553 ec = std::make_error_code(std::errc::not_supported);
554 return false;
555 #endif
559 void
560 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
562 error_code ec;
563 copy_symlink(existing_symlink, new_symlink, ec);
564 if (ec)
565 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
566 existing_symlink, new_symlink, ec));
569 void
570 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
571 error_code& ec) noexcept
573 auto p = read_symlink(existing_symlink, ec);
574 if (ec)
575 return;
576 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
577 if (is_directory(p))
579 create_directory_symlink(p, new_symlink, ec);
580 return;
582 #endif
583 create_symlink(p, new_symlink, ec);
587 bool
588 fs::create_directories(const path& p)
590 error_code ec;
591 bool result = create_directories(p, ec);
592 if (ec)
593 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
594 ec));
595 return result;
598 bool
599 fs::create_directories(const path& p, error_code& ec) noexcept
601 if (p.empty())
603 ec = std::make_error_code(errc::invalid_argument);
604 return false;
606 std::stack<path> missing;
607 path pp = p;
609 while (pp.has_filename() && status(pp, ec).type() == file_type::not_found)
611 ec.clear();
612 const auto& filename = pp.filename();
613 if (!is_dot(filename) && !is_dotdot(filename))
614 missing.push(pp);
615 pp = pp.parent_path();
617 if (missing.size() > 1000) // sanity check
619 ec = std::make_error_code(std::errc::filename_too_long);
620 return false;
624 if (ec || missing.empty())
625 return false;
629 const path& top = missing.top();
630 create_directory(top, ec);
631 if (ec && is_directory(top))
632 ec.clear();
633 missing.pop();
635 while (!missing.empty() && !ec);
637 return missing.empty();
640 namespace
642 bool
643 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
645 bool created = false;
646 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
647 ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
648 if (::mkdir(p.c_str(), mode))
650 const int err = errno;
651 if (err != EEXIST || !is_directory(p))
652 ec.assign(err, std::generic_category());
653 else
654 ec.clear();
656 else
658 ec.clear();
659 created = true;
661 #else
662 ec = std::make_error_code(std::errc::not_supported);
663 #endif
664 return created;
666 } // namespace
668 bool
669 fs::create_directory(const path& p)
671 error_code ec;
672 bool result = create_directory(p, ec);
673 if (ec)
674 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
675 ec));
676 return result;
679 bool
680 fs::create_directory(const path& p, error_code& ec) noexcept
682 return create_dir(p, perms::all, ec);
686 bool
687 fs::create_directory(const path& p, const path& attributes)
689 error_code ec;
690 bool result = create_directory(p, attributes, ec);
691 if (ec)
692 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
693 ec));
694 return result;
697 bool
698 fs::create_directory(const path& p, const path& attributes,
699 error_code& ec) noexcept
701 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
702 stat_type st;
703 if (::stat(attributes.c_str(), &st))
705 ec.assign(errno, std::generic_category());
706 return false;
708 return create_dir(p, static_cast<perms>(st.st_mode), ec);
709 #else
710 ec = std::make_error_code(std::errc::not_supported);
711 return false;
712 #endif
716 void
717 fs::create_directory_symlink(const path& to, const path& new_symlink)
719 error_code ec;
720 create_directory_symlink(to, new_symlink, ec);
721 if (ec)
722 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
723 to, new_symlink, ec));
726 void
727 fs::create_directory_symlink(const path& to, const path& new_symlink,
728 error_code& ec) noexcept
730 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
731 ec = std::make_error_code(std::errc::not_supported);
732 #else
733 create_symlink(to, new_symlink, ec);
734 #endif
738 void
739 fs::create_hard_link(const path& to, const path& new_hard_link)
741 error_code ec;
742 create_hard_link(to, new_hard_link, ec);
743 if (ec)
744 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
745 to, new_hard_link, ec));
748 void
749 fs::create_hard_link(const path& to, const path& new_hard_link,
750 error_code& ec) noexcept
752 #ifdef _GLIBCXX_HAVE_UNISTD_H
753 if (::link(to.c_str(), new_hard_link.c_str()))
754 ec.assign(errno, std::generic_category());
755 else
756 ec.clear();
757 #else
758 ec = std::make_error_code(std::errc::not_supported);
759 #endif
762 void
763 fs::create_symlink(const path& to, const path& new_symlink)
765 error_code ec;
766 create_symlink(to, new_symlink, ec);
767 if (ec)
768 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
769 to, new_symlink, ec));
772 void
773 fs::create_symlink(const path& to, const path& new_symlink,
774 error_code& ec) noexcept
776 #ifdef _GLIBCXX_HAVE_UNISTD_H
777 if (::symlink(to.c_str(), new_symlink.c_str()))
778 ec.assign(errno, std::generic_category());
779 else
780 ec.clear();
781 #else
782 ec = std::make_error_code(std::errc::not_supported);
783 #endif
787 fs::path
788 fs::current_path()
790 error_code ec;
791 path p = current_path(ec);
792 if (ec)
793 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
794 return p;
797 fs::path
798 fs::current_path(error_code& ec)
800 path p;
801 #ifdef _GLIBCXX_HAVE_UNISTD_H
802 #ifdef __GLIBC__
803 if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
805 p.assign(cwd.get());
806 ec.clear();
808 else
809 ec.assign(errno, std::generic_category());
810 #else
811 long path_max = pathconf(".", _PC_PATH_MAX);
812 size_t size;
813 if (path_max == -1)
814 size = 1024;
815 else if (path_max > 10240)
816 size = 10240;
817 else
818 size = path_max;
819 for (char_ptr buf; p.empty(); size *= 2)
821 buf.reset((char*)malloc(size));
822 if (buf)
824 if (getcwd(buf.get(), size))
826 p.assign(buf.get());
827 ec.clear();
829 else if (errno != ERANGE)
831 ec.assign(errno, std::generic_category());
832 return {};
835 else
837 ec = std::make_error_code(std::errc::not_enough_memory);
838 return {};
841 #endif // __GLIBC__
842 #else // _GLIBCXX_HAVE_UNISTD_H
843 ec = std::make_error_code(std::errc::not_supported);
844 #endif
845 return p;
848 void
849 fs::current_path(const path& p)
851 error_code ec;
852 current_path(p, ec);
853 if (ec)
854 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
857 void
858 fs::current_path(const path& p, error_code& ec) noexcept
860 #ifdef _GLIBCXX_HAVE_UNISTD_H
861 if (::chdir(p.c_str()))
862 ec.assign(errno, std::generic_category());
863 else
864 ec.clear();
865 #else
866 ec = std::make_error_code(std::errc::not_supported);
867 #endif
870 bool
871 fs::equivalent(const path& p1, const path& p2)
873 error_code ec;
874 auto result = equivalent(p1, p2, ec);
875 if (ec)
876 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
877 p1, p2, ec));
878 return result;
881 bool
882 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
884 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
885 int err = 0;
886 file_status s1, s2;
887 stat_type st1, st2;
888 if (::stat(p1.c_str(), &st1) == 0)
889 s1 = make_file_status(st1);
890 else if (is_not_found_errno(errno))
891 s1.type(file_type::not_found);
892 else
893 err = errno;
895 if (::stat(p2.c_str(), &st2) == 0)
896 s2 = make_file_status(st2);
897 else if (is_not_found_errno(errno))
898 s2.type(file_type::not_found);
899 else
900 err = errno;
902 if (exists(s1) && exists(s2))
904 if (is_other(s1) && is_other(s2))
906 ec = std::make_error_code(std::errc::not_supported);
907 return false;
909 ec.clear();
910 if (is_other(s1) || is_other(s2))
911 return false;
912 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
914 else if (!exists(s1) && !exists(s2))
915 ec = std::make_error_code(std::errc::no_such_file_or_directory);
916 else if (err)
917 ec.assign(err, std::generic_category());
918 else
919 ec.clear();
920 return false;
921 #else
922 ec = std::make_error_code(std::errc::not_supported);
923 #endif
924 return false;
927 std::uintmax_t
928 fs::file_size(const path& p)
930 error_code ec;
931 auto sz = file_size(p, ec);
932 if (ec)
933 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
934 return sz;
937 namespace
939 template<typename Accessor, typename T>
940 inline T
941 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
943 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
944 fs::stat_type st;
945 if (::stat(p.c_str(), &st))
947 ec.assign(errno, std::generic_category());
948 return deflt;
950 ec.clear();
951 return f(st);
952 #else
953 ec = std::make_error_code(std::errc::not_supported);
954 return deflt;
955 #endif
959 std::uintmax_t
960 fs::file_size(const path& p, error_code& ec) noexcept
962 struct S
964 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
965 S() : type(file_type::not_found) { }
966 file_type type;
967 size_t size;
969 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
970 if (s.type == file_type::regular)
971 return s.size;
972 if (!ec)
974 if (s.type == file_type::directory)
975 ec = std::make_error_code(std::errc::is_a_directory);
976 else
977 ec = std::make_error_code(std::errc::not_supported);
979 return -1;
982 std::uintmax_t
983 fs::hard_link_count(const path& p)
985 error_code ec;
986 auto count = hard_link_count(p, ec);
987 if (ec)
988 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
989 return count;
992 std::uintmax_t
993 fs::hard_link_count(const path& p, error_code& ec) noexcept
995 return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
996 static_cast<uintmax_t>(-1));
999 bool
1000 fs::is_empty(const path& p)
1002 error_code ec;
1003 bool e = is_empty(p, ec);
1004 if (ec)
1005 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1006 p, ec));
1007 return e;
1010 bool
1011 fs::is_empty(const path& p, error_code& ec) noexcept
1013 auto s = status(p, ec);
1014 if (ec)
1015 return false;
1016 bool empty = fs::is_directory(s)
1017 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1018 : fs::file_size(p, ec) == 0;
1019 return ec ? false : empty;
1022 fs::file_time_type
1023 fs::last_write_time(const path& p)
1025 error_code ec;
1026 auto t = last_write_time(p, ec);
1027 if (ec)
1028 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1029 return t;
1032 fs::file_time_type
1033 fs::last_write_time(const path& p, error_code& ec) noexcept
1035 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
1036 file_time_type::min());
1039 void
1040 fs::last_write_time(const path& p, file_time_type new_time)
1042 error_code ec;
1043 last_write_time(p, new_time, ec);
1044 if (ec)
1045 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1048 void
1049 fs::last_write_time(const path& p __attribute__((__unused__)),
1050 file_time_type new_time, error_code& ec) noexcept
1052 auto d = new_time.time_since_epoch();
1053 auto s = chrono::duration_cast<chrono::seconds>(d);
1054 #if _GLIBCXX_USE_UTIMENSAT
1055 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1056 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1058 --s;
1059 ns += chrono::seconds(1);
1061 struct ::timespec ts[2];
1062 ts[0].tv_sec = 0;
1063 ts[0].tv_nsec = UTIME_OMIT;
1064 ts[1].tv_sec = static_cast<std::time_t>(s.count());
1065 ts[1].tv_nsec = static_cast<long>(ns.count());
1066 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1067 ec.assign(errno, std::generic_category());
1068 else
1069 ec.clear();
1070 #elif _GLIBCXX_HAVE_UTIME_H
1071 ::utimbuf times;
1072 times.modtime = s.count();
1073 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1074 times.modtime);
1075 if (::utime(p.c_str(), &times))
1076 ec.assign(errno, std::generic_category());
1077 else
1078 ec.clear();
1079 #else
1080 ec = std::make_error_code(std::errc::not_supported);
1081 #endif
1084 void
1085 fs::permissions(const path& p, perms prms, perm_options opts)
1087 error_code ec;
1088 permissions(p, prms, opts, ec);
1089 if (ec)
1090 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1093 void
1094 fs::permissions(const path& p, perms prms, perm_options opts,
1095 error_code& ec) noexcept
1097 const bool replace = is_set(opts, perm_options::replace);
1098 const bool add = is_set(opts, perm_options::add);
1099 const bool remove = is_set(opts, perm_options::remove);
1100 const bool nofollow = is_set(opts, perm_options::nofollow);
1101 if (((int)replace + (int)add + (int)remove) != 1)
1103 ec = std::make_error_code(std::errc::invalid_argument);
1104 return;
1107 prms &= perms::mask;
1109 file_status st;
1110 if (add || remove || nofollow)
1112 st = nofollow ? symlink_status(p, ec) : status(p, ec);
1113 if (ec)
1114 return;
1115 auto curr = st.permissions();
1116 if (add)
1117 prms |= curr;
1118 else if (remove)
1119 prms = curr & ~prms;
1122 int err = 0;
1123 #if _GLIBCXX_USE_FCHMODAT
1124 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1125 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1126 err = errno;
1127 #else
1128 if (nofollow && is_symlink(st))
1129 ec = std::make_error_code(std::errc::operation_not_supported);
1130 else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
1131 err = errno;
1132 #endif
1134 if (err)
1135 ec.assign(err, std::generic_category());
1136 else
1137 ec.clear();
1140 fs::path
1141 fs::proximate(const path& p, const path& base)
1143 return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
1146 fs::path
1147 fs::proximate(const path& p, const path& base, error_code& ec)
1149 path result;
1150 const auto p2 = weakly_canonical(p, ec);
1151 if (!ec)
1153 const auto base2 = weakly_canonical(base, ec);
1154 if (!ec)
1155 result = p2.lexically_proximate(base2);
1157 return result;
1160 fs::path
1161 fs::read_symlink(const path& p)
1163 error_code ec;
1164 path tgt = read_symlink(p, ec);
1165 if (ec)
1166 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1167 return tgt;
1170 fs::path fs::read_symlink(const path& p, error_code& ec)
1172 path result;
1173 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1174 stat_type st;
1175 if (::lstat(p.c_str(), &st))
1177 ec.assign(errno, std::generic_category());
1178 return result;
1180 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1183 ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
1184 if (len == -1)
1186 ec.assign(errno, std::generic_category());
1187 return result;
1189 else if (len == (ssize_t)buf.size())
1191 if (buf.size() > 4096)
1193 ec.assign(ENAMETOOLONG, std::generic_category());
1194 return result;
1196 buf.resize(buf.size() * 2);
1198 else
1200 buf.resize(len);
1201 result.assign(buf);
1202 ec.clear();
1203 break;
1206 while (true);
1207 #else
1208 ec = std::make_error_code(std::errc::not_supported);
1209 #endif
1210 return result;
1213 fs::path
1214 fs::relative(const path& p, const path& base)
1216 return weakly_canonical(p).lexically_relative(weakly_canonical(base));
1219 fs::path
1220 fs::relative(const path& p, const path& base, error_code& ec)
1222 auto result = weakly_canonical(p, ec);
1223 fs::path cbase;
1224 if (!ec)
1225 cbase = weakly_canonical(base, ec);
1226 if (!ec)
1227 result = result.lexically_relative(cbase);
1228 if (ec)
1229 result.clear();
1230 return result;
1233 bool
1234 fs::remove(const path& p)
1236 error_code ec;
1237 bool result = fs::remove(p, ec);
1238 if (ec)
1239 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1240 return result;
1243 bool
1244 fs::remove(const path& p, error_code& ec) noexcept
1246 if (exists(symlink_status(p, ec)))
1248 if (::remove(p.c_str()) == 0)
1250 ec.clear();
1251 return true;
1253 else
1254 ec.assign(errno, std::generic_category());
1256 return false;
1260 std::uintmax_t
1261 fs::remove_all(const path& p)
1263 error_code ec;
1264 bool result = remove_all(p, ec);
1265 if (ec)
1266 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1267 return result;
1270 std::uintmax_t
1271 fs::remove_all(const path& p, error_code& ec) noexcept
1273 auto fs = symlink_status(p, ec);
1274 uintmax_t count = 0;
1275 if (!ec && fs.type() == file_type::directory)
1276 for (directory_iterator d(p, ec), end; !ec && d != end; ++d)
1277 count += fs::remove_all(d->path(), ec);
1278 if (ec)
1279 return -1;
1280 return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear()
1283 void
1284 fs::rename(const path& from, const path& to)
1286 error_code ec;
1287 rename(from, to, ec);
1288 if (ec)
1289 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1292 void
1293 fs::rename(const path& from, const path& to, error_code& ec) noexcept
1295 if (::rename(from.c_str(), to.c_str()))
1296 ec.assign(errno, std::generic_category());
1297 else
1298 ec.clear();
1301 void
1302 fs::resize_file(const path& p, uintmax_t size)
1304 error_code ec;
1305 resize_file(p, size, ec);
1306 if (ec)
1307 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1310 void
1311 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1313 #ifdef _GLIBCXX_HAVE_UNISTD_H
1314 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1315 ec.assign(EINVAL, std::generic_category());
1316 else if (::truncate(p.c_str(), size))
1317 ec.assign(errno, std::generic_category());
1318 else
1319 ec.clear();
1320 #else
1321 ec = std::make_error_code(std::errc::not_supported);
1322 #endif
1326 fs::space_info
1327 fs::space(const path& p)
1329 error_code ec;
1330 space_info s = space(p, ec);
1331 if (ec)
1332 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1333 return s;
1336 fs::space_info
1337 fs::space(const path& p, error_code& ec) noexcept
1339 space_info info = {
1340 static_cast<uintmax_t>(-1),
1341 static_cast<uintmax_t>(-1),
1342 static_cast<uintmax_t>(-1)
1344 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1345 struct ::statvfs f;
1346 if (::statvfs(p.c_str(), &f))
1347 ec.assign(errno, std::generic_category());
1348 else
1350 info = space_info{
1351 f.f_blocks * f.f_frsize,
1352 f.f_bfree * f.f_frsize,
1353 f.f_bavail * f.f_frsize
1355 ec.clear();
1357 #else
1358 ec = std::make_error_code(std::errc::not_supported);
1359 #endif
1360 return info;
1363 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1364 fs::file_status
1365 fs::status(const fs::path& p, error_code& ec) noexcept
1367 file_status status;
1368 stat_type st;
1369 if (::stat(p.c_str(), &st))
1371 int err = errno;
1372 ec.assign(err, std::generic_category());
1373 if (is_not_found_errno(err))
1374 status.type(file_type::not_found);
1375 #ifdef EOVERFLOW
1376 else if (err == EOVERFLOW)
1377 status.type(file_type::unknown);
1378 #endif
1380 else
1382 status = make_file_status(st);
1383 ec.clear();
1385 return status;
1388 fs::file_status
1389 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1391 file_status status;
1392 stat_type st;
1393 if (::lstat(p.c_str(), &st))
1395 int err = errno;
1396 ec.assign(err, std::generic_category());
1397 if (is_not_found_errno(err))
1398 status.type(file_type::not_found);
1400 else
1402 status = make_file_status(st);
1403 ec.clear();
1405 return status;
1407 #endif
1409 fs::file_status
1410 fs::status(const fs::path& p)
1412 std::error_code ec;
1413 auto result = status(p, ec);
1414 if (result.type() == file_type::none)
1415 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1416 return result;
1419 fs::file_status
1420 fs::symlink_status(const fs::path& p)
1422 std::error_code ec;
1423 auto result = symlink_status(p, ec);
1424 if (result.type() == file_type::none)
1425 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1426 return result;
1429 fs::path fs::temp_directory_path()
1431 error_code ec;
1432 path tmp = temp_directory_path(ec);
1433 if (ec)
1434 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1435 return tmp;
1438 fs::path fs::temp_directory_path(error_code& ec)
1440 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1441 ec = std::make_error_code(std::errc::not_supported);
1442 return {}; // TODO
1443 #else
1444 const char* tmpdir = nullptr;
1445 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1446 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1447 tmpdir = ::getenv(*e);
1448 path p = tmpdir ? tmpdir : "/tmp";
1449 auto st = status(p, ec);
1450 if (!ec)
1452 if (is_directory(st))
1454 ec.clear();
1455 return p;
1457 else
1458 ec = std::make_error_code(std::errc::not_a_directory);
1460 return {};
1461 #endif
1464 fs::path
1465 fs::weakly_canonical(const path& p)
1467 path result;
1468 if (exists(status(p)))
1469 return canonical(p);
1471 path tmp;
1472 auto iter = p.begin(), end = p.end();
1473 // find leading elements of p that exist:
1474 while (iter != end)
1476 tmp = result / *iter;
1477 if (exists(status(tmp)))
1478 swap(result, tmp);
1479 else
1480 break;
1481 ++iter;
1483 // canonicalize:
1484 result = canonical(result);
1485 // append the non-existing elements:
1486 while (iter != end)
1487 result /= *iter++;
1488 // normalize:
1489 return result.lexically_normal();
1492 fs::path
1493 fs::weakly_canonical(const path& p, error_code& ec)
1495 path result;
1496 file_status st = status(p, ec);
1497 if (exists(st))
1498 return canonical(p, ec);
1499 else if (status_known(st))
1500 ec.clear();
1501 else
1502 return result;
1504 path tmp;
1505 auto iter = p.begin(), end = p.end();
1506 // find leading elements of p that exist:
1507 while (iter != end)
1509 tmp = result / *iter;
1510 st = status(tmp, ec);
1511 if (exists(st))
1512 swap(result, tmp);
1513 else
1515 if (status_known(st))
1516 ec.clear();
1517 break;
1519 ++iter;
1521 // canonicalize:
1522 if (!ec)
1523 result = canonical(result, ec);
1524 if (ec)
1525 result.clear();
1526 else
1528 // append the non-existing elements:
1529 while (iter != end)
1530 result /= *iter++;
1531 // normalize:
1532 result = result.lexically_normal();
1534 return result;