[PATCH] Adjust lazy macro definition
[official-gcc.git] / libstdc++-v3 / src / filesystem / std-ops.cc
blobe266fa6d3f8701a68219053da4827cd53f58cf8d
1 // Filesystem 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 # define NEED_DO_COPY_FILE
28 # define NEED_DO_SPACE
29 #endif
31 #include <filesystem>
32 #include <experimental/filesystem>
33 #include <functional>
34 #include <ostream>
35 #include <stack>
36 #include <ext/stdio_filebuf.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <limits.h> // PATH_MAX
41 #ifdef _GLIBCXX_HAVE_FCNTL_H
42 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
43 #endif
44 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
45 # include <sys/stat.h> // stat, utimensat, fchmodat
46 #endif
47 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
48 # include <sys/statvfs.h> // statvfs
49 #endif
50 #ifdef _GLIBCXX_USE_SENDFILE
51 # include <sys/sendfile.h> // sendfile
52 #endif
53 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
54 # include <utime.h> // utime
55 #endif
56 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
57 # include <windows.h>
58 #endif
60 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
61 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
62 #include "ops-common.h"
64 namespace fs = std::filesystem;
65 namespace posix = std::filesystem::__gnu_posix;
67 fs::path
68 fs::absolute(const path& p)
70 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
71 error_code ec;
72 path ret = absolute(p, ec);
73 if (ec)
74 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
75 ec));
76 return ret;
77 #else
78 return current_path() / p;
79 #endif
82 fs::path
83 fs::absolute(const path& p, error_code& ec)
85 path ret;
86 if (p.empty())
88 ec = make_error_code(std::errc::no_such_file_or_directory);
89 return ret;
91 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
92 const wstring& s = p.native();
93 uint32_t len = 1024;
94 wstring buf;
97 buf.resize(len);
98 len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr);
100 while (len > buf.size());
102 if (len == 0)
103 ec.assign((int)GetLastError(), std::system_category());
104 else
106 ec.clear();
107 buf.resize(len);
108 ret = std::move(buf);
110 #else
111 ec.clear();
112 ret = current_path();
113 ret /= p;
114 #endif
115 return ret;
118 namespace
120 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
121 inline bool is_dot(wchar_t c) { return c == L'.'; }
122 #else
123 inline bool is_dot(char c) { return c == '.'; }
124 #endif
126 inline bool is_dot(const fs::path& path)
128 const auto& filename = path.native();
129 return filename.size() == 1 && is_dot(filename[0]);
132 inline bool is_dotdot(const fs::path& path)
134 const auto& filename = path.native();
135 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
138 struct free_as_in_malloc
140 void operator()(void* p) const { ::free(p); }
143 using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
146 fs::path
147 fs::canonical(const path& p, error_code& ec)
149 path result;
150 const path pa = absolute(p, ec);
151 if (ec)
152 return result;
154 #ifdef _GLIBCXX_USE_REALPATH
155 char_ptr buf{ nullptr };
156 # if _XOPEN_VERSION < 700
157 // Not safe to call realpath(path, NULL)
158 using char_type = fs::path::value_type;
159 buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
160 # endif
161 if (char* rp = ::realpath(pa.c_str(), buf.get()))
163 if (buf == nullptr)
164 buf.reset(rp);
165 result.assign(rp);
166 ec.clear();
167 return result;
169 if (errno != ENAMETOOLONG)
171 ec.assign(errno, std::generic_category());
172 return result;
174 #endif
176 if (!exists(pa, ec))
178 if (!ec)
179 ec = make_error_code(std::errc::no_such_file_or_directory);
180 return result;
182 // else: we know there are (currently) no unresolvable symlink loops
184 result = pa.root_path();
186 deque<path> cmpts;
187 for (auto& f : pa.relative_path())
188 cmpts.push_back(f);
190 int max_allowed_symlinks = 40;
192 while (!cmpts.empty() && !ec)
194 path f = std::move(cmpts.front());
195 cmpts.pop_front();
197 if (f.empty())
199 // ignore empty element
201 else if (is_dot(f))
203 if (!is_directory(result, ec) && !ec)
204 ec.assign(ENOTDIR, std::generic_category());
206 else if (is_dotdot(f))
208 auto parent = result.parent_path();
209 if (parent.empty())
210 result = pa.root_path();
211 else
212 result.swap(parent);
214 else
216 result /= f;
218 if (is_symlink(result, ec))
220 path link = read_symlink(result, ec);
221 if (!ec)
223 if (--max_allowed_symlinks == 0)
224 ec.assign(ELOOP, std::generic_category());
225 else
227 if (link.is_absolute())
229 result = link.root_path();
230 link = link.relative_path();
232 else
233 result = result.parent_path();
235 cmpts.insert(cmpts.begin(), link.begin(), link.end());
242 if (ec || !exists(result, ec))
243 result.clear();
245 return result;
248 fs::path
249 fs::canonical(const path& p)
251 error_code ec;
252 path res = canonical(p, ec);
253 if (ec)
254 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
255 p, ec));
256 return res;
259 void
260 fs::copy(const path& from, const path& to, copy_options options)
262 error_code ec;
263 copy(from, to, options, ec);
264 if (ec)
265 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
268 namespace std::filesystem
270 // Need this as there's no 'perm_options::none' enumerator.
271 inline bool is_set(fs::perm_options obj, fs::perm_options bits)
273 return (obj & bits) != fs::perm_options{};
277 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
278 #ifdef NEED_DO_COPY_FILE
279 bool
280 fs::do_copy_file(const path::value_type* from, const path::value_type* to,
281 copy_options_existing_file options,
282 stat_type* from_st, stat_type* to_st,
283 std::error_code& ec) noexcept
285 stat_type st1, st2;
286 fs::file_status t, f;
288 if (to_st == nullptr)
290 if (posix::stat(to, &st1))
292 const int err = errno;
293 if (!is_not_found_errno(err))
295 ec.assign(err, std::generic_category());
296 return false;
299 else
300 to_st = &st1;
302 else if (to_st == from_st)
303 to_st = nullptr;
305 if (to_st == nullptr)
306 t = fs::file_status{fs::file_type::not_found};
307 else
308 t = make_file_status(*to_st);
310 if (from_st == nullptr)
312 if (posix::stat(from, &st2))
314 ec.assign(errno, std::generic_category());
315 return false;
317 else
318 from_st = &st2;
320 f = make_file_status(*from_st);
321 // _GLIBCXX_RESOLVE_LIB_DEFECTS
322 // 2712. copy_file() has a number of unspecified error conditions
323 if (!is_regular_file(f))
325 ec = std::make_error_code(std::errc::not_supported);
326 return false;
329 if (exists(t))
331 if (!is_regular_file(t))
333 ec = std::make_error_code(std::errc::not_supported);
334 return false;
337 if (to_st->st_dev == from_st->st_dev
338 && to_st->st_ino == from_st->st_ino)
340 ec = std::make_error_code(std::errc::file_exists);
341 return false;
344 if (options.skip)
346 ec.clear();
347 return false;
349 else if (options.update)
351 const auto from_mtime = file_time(*from_st, ec);
352 if (ec)
353 return false;
354 if ((from_mtime <= file_time(*to_st, ec)) || ec)
355 return false;
357 else if (!options.overwrite)
359 ec = std::make_error_code(std::errc::file_exists);
360 return false;
362 else if (!is_regular_file(t))
364 ec = std::make_error_code(std::errc::not_supported);
365 return false;
369 struct CloseFD {
370 ~CloseFD() { if (fd != -1) posix::close(fd); }
371 bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
372 int fd;
375 CloseFD in = { posix::open(from, O_RDONLY) };
376 if (in.fd == -1)
378 ec.assign(errno, std::generic_category());
379 return false;
381 int oflag = O_WRONLY|O_CREAT;
382 if (options.overwrite || options.update)
383 oflag |= O_TRUNC;
384 else
385 oflag |= O_EXCL;
386 CloseFD out = { posix::open(to, oflag, S_IWUSR) };
387 if (out.fd == -1)
389 if (errno == EEXIST && options.skip)
390 ec.clear();
391 else
392 ec.assign(errno, std::generic_category());
393 return false;
396 #if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
397 if (::fchmod(out.fd, from_st->st_mode))
398 #elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
399 if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
400 #else
401 if (posix::chmod(to, from_st->st_mode))
402 #endif
404 ec.assign(errno, std::generic_category());
405 return false;
408 size_t count = from_st->st_size;
409 #if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
410 off_t offset = 0;
411 ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
412 if (n < 0 && errno != ENOSYS && errno != EINVAL)
414 ec.assign(errno, std::generic_category());
415 return false;
417 if ((size_t)n == count)
419 if (!out.close() || !in.close())
421 ec.assign(errno, std::generic_category());
422 return false;
424 ec.clear();
425 return true;
427 else if (n > 0)
428 count -= n;
429 #endif // _GLIBCXX_USE_SENDFILE
431 using std::ios;
432 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
433 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
435 if (sbin.is_open())
436 in.fd = -1;
437 if (sbout.is_open())
438 out.fd = -1;
440 #ifdef _GLIBCXX_USE_SENDFILE
441 if (n != 0)
443 if (n < 0)
444 n = 0;
446 const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in);
447 const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out);
449 const std::streampos errpos(std::streamoff(-1));
450 if (p1 == errpos || p2 == errpos)
452 ec = std::make_error_code(std::errc::io_error);
453 return false;
456 #endif
458 if (count && !(std::ostream(&sbout) << &sbin))
460 ec = std::make_error_code(std::errc::io_error);
461 return false;
463 if (!sbout.close() || !sbin.close())
465 ec.assign(errno, std::generic_category());
466 return false;
468 ec.clear();
469 return true;
471 #endif // NEED_DO_COPY_FILE
472 #endif // _GLIBCXX_HAVE_SYS_STAT_H
474 void
475 fs::copy(const path& from, const path& to, copy_options options,
476 error_code& ec)
478 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
479 const bool create_symlinks = is_set(options, copy_options::create_symlinks);
480 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
481 const bool use_lstat = create_symlinks || skip_symlinks;
483 file_status f, t;
484 stat_type from_st, to_st;
485 // _GLIBCXX_RESOLVE_LIB_DEFECTS
486 // 2681. filesystem::copy() cannot copy symlinks
487 if (use_lstat || copy_symlinks
488 ? posix::lstat(from.c_str(), &from_st)
489 : posix::stat(from.c_str(), &from_st))
491 ec.assign(errno, std::generic_category());
492 return;
494 if (use_lstat
495 ? posix::lstat(to.c_str(), &to_st)
496 : posix::stat(to.c_str(), &to_st))
498 if (!is_not_found_errno(errno))
500 ec.assign(errno, std::generic_category());
501 return;
503 t = file_status{file_type::not_found};
505 else
506 t = make_file_status(to_st);
507 f = make_file_status(from_st);
509 if (exists(t) && !is_other(t) && !is_other(f)
510 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
512 ec = std::make_error_code(std::errc::file_exists);
513 return;
515 if (is_other(f) || is_other(t))
517 ec = std::make_error_code(std::errc::not_supported);
518 return;
520 if (is_directory(f) && is_regular_file(t))
522 ec = std::make_error_code(std::errc::is_a_directory);
523 return;
526 if (is_symlink(f))
528 if (skip_symlinks)
529 ec.clear();
530 else if (!exists(t) && copy_symlinks)
531 copy_symlink(from, to, ec);
532 else
533 // Not clear what should be done here.
534 // "Otherwise report an error as specified in Error reporting (7)."
535 ec = std::make_error_code(std::errc::invalid_argument);
537 else if (is_regular_file(f))
539 if (is_set(options, copy_options::directories_only))
540 ec.clear();
541 else if (create_symlinks)
542 create_symlink(from, to, ec);
543 else if (is_set(options, copy_options::create_hard_links))
544 create_hard_link(from, to, ec);
545 else if (is_directory(t))
546 do_copy_file(from.c_str(), (to / from.filename()).c_str(),
547 copy_file_options(options), &from_st, nullptr, ec);
548 else
550 auto ptr = exists(t) ? &to_st : &from_st;
551 do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
552 &from_st, ptr, ec);
555 // _GLIBCXX_RESOLVE_LIB_DEFECTS
556 // 2682. filesystem::copy() won't create a symlink to a directory
557 else if (is_directory(f) && create_symlinks)
558 ec = std::make_error_code(errc::is_a_directory);
559 else if (is_directory(f) && (is_set(options, copy_options::recursive)
560 || options == copy_options::none))
562 if (!exists(t))
563 if (!create_directory(to, from, ec))
564 return;
565 // set an unused bit in options to disable further recursion
566 if (!is_set(options, copy_options::recursive))
567 options |= static_cast<copy_options>(4096);
568 for (const directory_entry& x : directory_iterator(from))
569 copy(x.path(), to/x.path().filename(), options, ec);
571 // _GLIBCXX_RESOLVE_LIB_DEFECTS
572 // 2683. filesystem::copy() says "no effects"
573 else
574 ec.clear();
577 bool
578 fs::copy_file(const path& from, const path& to, copy_options option)
580 error_code ec;
581 bool result = copy_file(from, to, option, ec);
582 if (ec)
583 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
584 ec));
585 return result;
588 bool
589 fs::copy_file(const path& from, const path& to, copy_options options,
590 error_code& ec)
592 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
593 return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
594 nullptr, nullptr, ec);
595 #else
596 ec = std::make_error_code(std::errc::not_supported);
597 return false;
598 #endif
602 void
603 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
605 error_code ec;
606 copy_symlink(existing_symlink, new_symlink, ec);
607 if (ec)
608 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
609 existing_symlink, new_symlink, ec));
612 void
613 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
614 error_code& ec) noexcept
616 auto p = read_symlink(existing_symlink, ec);
617 if (ec)
618 return;
619 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
620 if (is_directory(p))
622 create_directory_symlink(p, new_symlink, ec);
623 return;
625 #endif
626 create_symlink(p, new_symlink, ec);
630 bool
631 fs::create_directories(const path& p)
633 error_code ec;
634 bool result = create_directories(p, ec);
635 if (ec)
636 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
637 ec));
638 return result;
641 bool
642 fs::create_directories(const path& p, error_code& ec)
644 if (p.empty())
646 ec = std::make_error_code(errc::invalid_argument);
647 return false;
649 std::stack<path> missing;
650 path pp = p;
652 while (pp.has_filename() && status(pp, ec).type() == file_type::not_found)
654 ec.clear();
655 const auto& filename = pp.filename();
656 if (!is_dot(filename) && !is_dotdot(filename))
657 missing.push(pp);
658 pp = pp.parent_path();
660 if (missing.size() > 1000) // sanity check
662 ec = std::make_error_code(std::errc::filename_too_long);
663 return false;
667 if (ec || missing.empty())
668 return false;
672 const path& top = missing.top();
673 create_directory(top, ec);
674 if (ec && is_directory(top))
675 ec.clear();
676 missing.pop();
678 while (!missing.empty() && !ec);
680 return missing.empty();
683 namespace
685 bool
686 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
688 bool created = false;
689 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
690 posix::mode_t mode
691 = static_cast<std::underlying_type_t<fs::perms>>(perm);
692 if (posix::mkdir(p.c_str(), mode))
694 const int err = errno;
695 if (err != EEXIST || !is_directory(p, ec))
696 ec.assign(err, std::generic_category());
698 else
700 ec.clear();
701 created = true;
703 #else
704 ec = std::make_error_code(std::errc::not_supported);
705 #endif
706 return created;
708 } // namespace
710 bool
711 fs::create_directory(const path& p)
713 error_code ec;
714 bool result = create_directory(p, ec);
715 if (ec)
716 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
717 ec));
718 return result;
721 bool
722 fs::create_directory(const path& p, error_code& ec) noexcept
724 return create_dir(p, perms::all, ec);
728 bool
729 fs::create_directory(const path& p, const path& attributes)
731 error_code ec;
732 bool result = create_directory(p, attributes, ec);
733 if (ec)
734 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
735 ec));
736 return result;
739 bool
740 fs::create_directory(const path& p, const path& attributes,
741 error_code& ec) noexcept
743 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
744 stat_type st;
745 if (posix::stat(attributes.c_str(), &st))
747 ec.assign(errno, std::generic_category());
748 return false;
750 return create_dir(p, static_cast<perms>(st.st_mode), ec);
751 #else
752 ec = std::make_error_code(std::errc::not_supported);
753 return false;
754 #endif
758 void
759 fs::create_directory_symlink(const path& to, const path& new_symlink)
761 error_code ec;
762 create_directory_symlink(to, new_symlink, ec);
763 if (ec)
764 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
765 to, new_symlink, ec));
768 void
769 fs::create_directory_symlink(const path& to, const path& new_symlink,
770 error_code& ec) noexcept
772 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
773 ec = std::make_error_code(std::errc::not_supported);
774 #else
775 create_symlink(to, new_symlink, ec);
776 #endif
780 void
781 fs::create_hard_link(const path& to, const path& new_hard_link)
783 error_code ec;
784 create_hard_link(to, new_hard_link, ec);
785 if (ec)
786 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
787 to, new_hard_link, ec));
790 void
791 fs::create_hard_link(const path& to, const path& new_hard_link,
792 error_code& ec) noexcept
794 #ifdef _GLIBCXX_HAVE_LINK
795 if (::link(to.c_str(), new_hard_link.c_str()))
796 ec.assign(errno, std::generic_category());
797 else
798 ec.clear();
799 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
800 if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
801 ec.clear();
802 else
803 ec.assign((int)GetLastError(), generic_category());
804 #else
805 ec = std::make_error_code(std::errc::not_supported);
806 #endif
809 void
810 fs::create_symlink(const path& to, const path& new_symlink)
812 error_code ec;
813 create_symlink(to, new_symlink, ec);
814 if (ec)
815 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
816 to, new_symlink, ec));
819 void
820 fs::create_symlink(const path& to, const path& new_symlink,
821 error_code& ec) noexcept
823 #ifdef _GLIBCXX_HAVE_SYMLINK
824 if (::symlink(to.c_str(), new_symlink.c_str()))
825 ec.assign(errno, std::generic_category());
826 else
827 ec.clear();
828 #else
829 ec = std::make_error_code(std::errc::not_supported);
830 #endif
834 fs::path
835 fs::current_path()
837 error_code ec;
838 path p = current_path(ec);
839 if (ec)
840 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
841 return p;
844 fs::path
845 fs::current_path(error_code& ec)
847 path p;
848 #ifdef _GLIBCXX_HAVE_UNISTD_H
849 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
850 if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
852 p.assign(cwd.get());
853 ec.clear();
855 else
856 ec.assign(errno, std::generic_category());
857 #else
858 #ifdef _PC_PATH_MAX
859 long path_max = pathconf(".", _PC_PATH_MAX);
860 size_t size;
861 if (path_max == -1)
862 size = 1024;
863 else if (path_max > 10240)
864 size = 10240;
865 else
866 size = path_max;
867 #elif defined(PATH_MAX)
868 size_t size = PATH_MAX;
869 #else
870 size_t size = 1024;
871 #endif
872 for (char_ptr buf; p.empty(); size *= 2)
874 using char_type = fs::path::value_type;
875 buf.reset((char_type*)malloc(size * sizeof(char_type)));
876 if (buf)
878 if (getcwd(buf.get(), size))
880 p.assign(buf.get());
881 ec.clear();
883 else if (errno != ERANGE)
885 ec.assign(errno, std::generic_category());
886 return {};
889 else
891 ec = std::make_error_code(std::errc::not_enough_memory);
892 return {};
895 #endif // __GLIBC__
896 #else // _GLIBCXX_HAVE_UNISTD_H
897 ec = std::make_error_code(std::errc::not_supported);
898 #endif
899 return p;
902 void
903 fs::current_path(const path& p)
905 error_code ec;
906 current_path(p, ec);
907 if (ec)
908 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
911 void
912 fs::current_path(const path& p, error_code& ec) noexcept
914 #ifdef _GLIBCXX_HAVE_UNISTD_H
915 if (posix::chdir(p.c_str()))
916 ec.assign(errno, std::generic_category());
917 else
918 ec.clear();
919 #else
920 ec = std::make_error_code(std::errc::not_supported);
921 #endif
924 bool
925 fs::equivalent(const path& p1, const path& p2)
927 error_code ec;
928 auto result = equivalent(p1, p2, ec);
929 if (ec)
930 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
931 p1, p2, ec));
932 return result;
935 bool
936 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
938 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
939 int err = 0;
940 file_status s1, s2;
941 stat_type st1, st2;
942 if (posix::stat(p1.c_str(), &st1) == 0)
943 s1 = make_file_status(st1);
944 else if (is_not_found_errno(errno))
945 s1.type(file_type::not_found);
946 else
947 err = errno;
949 if (posix::stat(p2.c_str(), &st2) == 0)
950 s2 = make_file_status(st2);
951 else if (is_not_found_errno(errno))
952 s2.type(file_type::not_found);
953 else
954 err = errno;
956 if (exists(s1) && exists(s2))
958 if (is_other(s1) && is_other(s2))
960 ec = std::make_error_code(std::errc::not_supported);
961 return false;
963 ec.clear();
964 if (is_other(s1) || is_other(s2))
965 return false;
966 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
968 else if (!exists(s1) && !exists(s2))
969 ec = std::make_error_code(std::errc::no_such_file_or_directory);
970 else if (err)
971 ec.assign(err, std::generic_category());
972 else
973 ec.clear();
974 return false;
975 #else
976 ec = std::make_error_code(std::errc::not_supported);
977 #endif
978 return false;
981 std::uintmax_t
982 fs::file_size(const path& p)
984 error_code ec;
985 auto sz = file_size(p, ec);
986 if (ec)
987 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
988 return sz;
991 namespace
993 template<typename Accessor, typename T>
994 inline T
995 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
997 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
998 posix::stat_type st;
999 if (posix::stat(p.c_str(), &st))
1001 ec.assign(errno, std::generic_category());
1002 return deflt;
1004 ec.clear();
1005 return f(st);
1006 #else
1007 ec = std::make_error_code(std::errc::not_supported);
1008 return deflt;
1009 #endif
1013 std::uintmax_t
1014 fs::file_size(const path& p, error_code& ec) noexcept
1016 struct S
1018 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
1019 S() : type(file_type::not_found) { }
1020 file_type type;
1021 size_t size;
1023 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
1024 if (s.type == file_type::regular)
1025 return s.size;
1026 if (!ec)
1028 if (s.type == file_type::directory)
1029 ec = std::make_error_code(std::errc::is_a_directory);
1030 else
1031 ec = std::make_error_code(std::errc::not_supported);
1033 return -1;
1036 std::uintmax_t
1037 fs::hard_link_count(const path& p)
1039 error_code ec;
1040 auto count = hard_link_count(p, ec);
1041 if (ec)
1042 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
1043 return count;
1046 std::uintmax_t
1047 fs::hard_link_count(const path& p, error_code& ec) noexcept
1049 return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
1050 static_cast<uintmax_t>(-1));
1053 bool
1054 fs::is_empty(const path& p)
1056 error_code ec;
1057 bool e = is_empty(p, ec);
1058 if (ec)
1059 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1060 p, ec));
1061 return e;
1064 bool
1065 fs::is_empty(const path& p, error_code& ec)
1067 auto s = status(p, ec);
1068 if (ec)
1069 return false;
1070 bool empty = fs::is_directory(s)
1071 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1072 : fs::file_size(p, ec) == 0;
1073 return ec ? false : empty;
1076 fs::file_time_type
1077 fs::last_write_time(const path& p)
1079 error_code ec;
1080 auto t = last_write_time(p, ec);
1081 if (ec)
1082 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1083 return t;
1086 fs::file_time_type
1087 fs::last_write_time(const path& p, error_code& ec) noexcept
1089 return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
1090 file_time_type::min());
1093 void
1094 fs::last_write_time(const path& p, file_time_type new_time)
1096 error_code ec;
1097 last_write_time(p, new_time, ec);
1098 if (ec)
1099 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1102 void
1103 fs::last_write_time(const path& p __attribute__((__unused__)),
1104 file_time_type new_time, error_code& ec) noexcept
1106 auto d = new_time.time_since_epoch();
1107 auto s = chrono::duration_cast<chrono::seconds>(d);
1108 #if _GLIBCXX_USE_UTIMENSAT
1109 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1110 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1112 --s;
1113 ns += chrono::seconds(1);
1115 struct ::timespec ts[2];
1116 ts[0].tv_sec = 0;
1117 ts[0].tv_nsec = UTIME_OMIT;
1118 ts[1].tv_sec = static_cast<std::time_t>(s.count());
1119 ts[1].tv_nsec = static_cast<long>(ns.count());
1120 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1121 ec.assign(errno, std::generic_category());
1122 else
1123 ec.clear();
1124 #elif _GLIBCXX_HAVE_UTIME_H
1125 posix::utimbuf times;
1126 times.modtime = s.count();
1127 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1128 times.modtime);
1129 if (posix::utime(p.c_str(), &times))
1130 ec.assign(errno, std::generic_category());
1131 else
1132 ec.clear();
1133 #else
1134 ec = std::make_error_code(std::errc::not_supported);
1135 #endif
1138 void
1139 fs::permissions(const path& p, perms prms, perm_options opts)
1141 error_code ec;
1142 permissions(p, prms, opts, ec);
1143 if (ec)
1144 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1147 void
1148 fs::permissions(const path& p, perms prms, perm_options opts,
1149 error_code& ec) noexcept
1151 const bool replace = is_set(opts, perm_options::replace);
1152 const bool add = is_set(opts, perm_options::add);
1153 const bool remove = is_set(opts, perm_options::remove);
1154 const bool nofollow = is_set(opts, perm_options::nofollow);
1155 if (((int)replace + (int)add + (int)remove) != 1)
1157 ec = std::make_error_code(std::errc::invalid_argument);
1158 return;
1161 prms &= perms::mask;
1163 file_status st;
1164 if (add || remove || nofollow)
1166 st = nofollow ? symlink_status(p, ec) : status(p, ec);
1167 if (ec)
1168 return;
1169 auto curr = st.permissions();
1170 if (add)
1171 prms |= curr;
1172 else if (remove)
1173 prms = curr & ~prms;
1176 int err = 0;
1177 #if _GLIBCXX_USE_FCHMODAT
1178 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1179 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1180 err = errno;
1181 #else
1182 if (nofollow && is_symlink(st))
1183 ec = std::make_error_code(std::errc::operation_not_supported);
1184 else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
1185 err = errno;
1186 #endif
1188 if (err)
1189 ec.assign(err, std::generic_category());
1190 else
1191 ec.clear();
1194 fs::path
1195 fs::proximate(const path& p, const path& base)
1197 return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
1200 fs::path
1201 fs::proximate(const path& p, const path& base, error_code& ec)
1203 path result;
1204 const auto p2 = weakly_canonical(p, ec);
1205 if (!ec)
1207 const auto base2 = weakly_canonical(base, ec);
1208 if (!ec)
1209 result = p2.lexically_proximate(base2);
1211 return result;
1214 fs::path
1215 fs::read_symlink(const path& p)
1217 error_code ec;
1218 path tgt = read_symlink(p, ec);
1219 if (ec)
1220 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1221 return tgt;
1224 fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
1226 path result;
1227 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1228 stat_type st;
1229 if (::lstat(p.c_str(), &st))
1231 ec.assign(errno, std::generic_category());
1232 return result;
1234 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1237 ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
1238 if (len == -1)
1240 ec.assign(errno, std::generic_category());
1241 return result;
1243 else if (len == (ssize_t)buf.size())
1245 if (buf.size() > 4096)
1247 ec.assign(ENAMETOOLONG, std::generic_category());
1248 return result;
1250 buf.resize(buf.size() * 2);
1252 else
1254 buf.resize(len);
1255 result.assign(buf);
1256 ec.clear();
1257 break;
1260 while (true);
1261 #else
1262 ec = std::make_error_code(std::errc::not_supported);
1263 #endif
1264 return result;
1267 fs::path
1268 fs::relative(const path& p, const path& base)
1270 return weakly_canonical(p).lexically_relative(weakly_canonical(base));
1273 fs::path
1274 fs::relative(const path& p, const path& base, error_code& ec)
1276 auto result = weakly_canonical(p, ec);
1277 fs::path cbase;
1278 if (!ec)
1279 cbase = weakly_canonical(base, ec);
1280 if (!ec)
1281 result = result.lexically_relative(cbase);
1282 if (ec)
1283 result.clear();
1284 return result;
1287 bool
1288 fs::remove(const path& p)
1290 error_code ec;
1291 const bool result = fs::remove(p, ec);
1292 if (ec)
1293 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1294 return result;
1297 bool
1298 fs::remove(const path& p, error_code& ec) noexcept
1300 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1301 if (exists(symlink_status(p, ec)))
1303 if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
1304 || DeleteFileW(p.c_str()))
1306 ec.clear();
1307 return true;
1309 else if (!ec)
1310 ec.assign((int)GetLastError(), generic_category());
1312 #else
1313 if (::remove(p.c_str()) == 0)
1315 ec.clear();
1316 return true;
1318 else if (errno == ENOENT)
1319 ec.clear();
1320 else
1321 ec.assign(errno, std::generic_category());
1322 #endif
1323 return false;
1327 std::uintmax_t
1328 fs::remove_all(const path& p)
1330 error_code ec;
1331 const auto result = remove_all(p, ec);
1332 if (ec)
1333 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1334 return result;
1337 std::uintmax_t
1338 fs::remove_all(const path& p, error_code& ec)
1340 const auto s = symlink_status(p, ec);
1341 if (!status_known(s))
1342 return -1;
1344 ec.clear();
1345 if (s.type() == file_type::not_found)
1346 return 0;
1348 uintmax_t count = 0;
1349 if (s.type() == file_type::directory)
1351 for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
1352 count += fs::remove_all(d->path(), ec);
1353 if (ec.value() == ENOENT)
1354 ec.clear();
1355 else if (ec)
1356 return -1;
1359 if (fs::remove(p, ec))
1360 ++count;
1361 return ec ? -1 : count;
1364 void
1365 fs::rename(const path& from, const path& to)
1367 error_code ec;
1368 rename(from, to, ec);
1369 if (ec)
1370 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1373 void
1374 fs::rename(const path& from, const path& to, error_code& ec) noexcept
1376 if (posix::rename(from.c_str(), to.c_str()))
1377 ec.assign(errno, std::generic_category());
1378 else
1379 ec.clear();
1382 void
1383 fs::resize_file(const path& p, uintmax_t size)
1385 error_code ec;
1386 resize_file(p, size, ec);
1387 if (ec)
1388 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1391 void
1392 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1394 #ifdef _GLIBCXX_HAVE_UNISTD_H
1395 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1396 ec.assign(EINVAL, std::generic_category());
1397 else if (posix::truncate(p.c_str(), size))
1398 ec.assign(errno, std::generic_category());
1399 else
1400 ec.clear();
1401 #else
1402 ec = std::make_error_code(std::errc::not_supported);
1403 #endif
1407 fs::space_info
1408 fs::space(const path& p)
1410 error_code ec;
1411 space_info s = space(p, ec);
1412 if (ec)
1413 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1414 return s;
1417 #ifdef NEED_DO_SPACE
1418 void
1419 fs::do_space(const __gnu_posix::char_type* pathname,
1420 uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
1421 std::error_code& ec)
1423 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1424 struct ::statvfs f;
1425 if (::statvfs(pathname, &f))
1426 ec.assign(errno, std::generic_category());
1427 else
1429 if (f.f_frsize != (unsigned long)-1)
1431 const uintmax_t fragment_size = f.f_frsize;
1432 const fsblkcnt_t unknown = -1;
1433 if (f.f_blocks != unknown)
1434 capacity = f.f_blocks * fragment_size;
1435 if (f.f_bfree != unknown)
1436 free = f.f_bfree * fragment_size;
1437 if (f.f_bavail != unknown)
1438 available = f.f_bavail * fragment_size;
1440 ec.clear();
1442 #elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
1443 ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
1444 if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
1446 if (bytes_total.QuadPart != 0)
1447 capacity = bytes_total.QuadPart;
1448 if (bytes_free.QuadPart != 0)
1449 free = bytes_free.QuadPart;
1450 if (bytes_avail.QuadPart != 0)
1451 available = bytes_avail.QuadPart;
1452 ec.clear();
1454 else
1455 ec.assign((int)GetLastError(), std::system_category());
1456 #else
1457 ec = std::make_error_code(std::errc::not_supported);
1458 #endif
1460 #endif // NEED_DO_SPACE
1462 fs::space_info
1463 fs::space(const path& p, error_code& ec) noexcept
1465 space_info info = {
1466 static_cast<uintmax_t>(-1),
1467 static_cast<uintmax_t>(-1),
1468 static_cast<uintmax_t>(-1)
1470 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1471 path dir = absolute(p);
1472 dir.remove_filename();
1473 auto str = dir.c_str();
1474 #else
1475 auto str = p.c_str();
1476 #endif
1477 do_space(str, info.capacity, info.free, info.available, ec);
1478 return info;
1481 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1482 fs::file_status
1483 fs::status(const fs::path& p, error_code& ec) noexcept
1485 file_status status;
1486 stat_type st;
1487 if (posix::stat(p.c_str(), &st))
1489 int err = errno;
1490 ec.assign(err, std::generic_category());
1491 if (is_not_found_errno(err))
1492 status.type(file_type::not_found);
1493 #ifdef EOVERFLOW
1494 else if (err == EOVERFLOW)
1495 status.type(file_type::unknown);
1496 #endif
1498 else
1500 status = make_file_status(st);
1501 ec.clear();
1503 return status;
1506 fs::file_status
1507 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1509 file_status status;
1510 stat_type st;
1511 if (posix::lstat(p.c_str(), &st))
1513 int err = errno;
1514 ec.assign(err, std::generic_category());
1515 if (is_not_found_errno(err))
1516 status.type(file_type::not_found);
1518 else
1520 status = make_file_status(st);
1521 ec.clear();
1523 return status;
1525 #endif
1527 fs::file_status
1528 fs::status(const fs::path& p)
1530 std::error_code ec;
1531 auto result = status(p, ec);
1532 if (result.type() == file_type::none)
1533 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1534 return result;
1537 fs::file_status
1538 fs::symlink_status(const fs::path& p)
1540 std::error_code ec;
1541 auto result = symlink_status(p, ec);
1542 if (result.type() == file_type::none)
1543 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1544 return result;
1547 fs::path fs::temp_directory_path()
1549 error_code ec;
1550 path tmp = temp_directory_path(ec);
1551 if (ec)
1552 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1553 return tmp;
1556 fs::path fs::temp_directory_path(error_code& ec)
1558 path p;
1559 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1560 unsigned len = 1024;
1561 std::wstring buf;
1564 buf.resize(len);
1565 len = GetTempPathW(buf.size(), buf.data());
1566 } while (len > buf.size());
1568 if (len == 0)
1570 ec.assign((int)GetLastError(), std::system_category());
1571 return p;
1573 buf.resize(len);
1574 p = std::move(buf);
1575 #else
1576 const char* tmpdir = nullptr;
1577 const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1578 for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1579 tmpdir = ::getenv(*e);
1580 p = tmpdir ? tmpdir : "/tmp";
1581 #endif
1582 auto st = status(p, ec);
1583 if (ec)
1584 p.clear();
1585 else if (!is_directory(st))
1587 p.clear();
1588 ec = std::make_error_code(std::errc::not_a_directory);
1590 return p;
1593 fs::path
1594 fs::weakly_canonical(const path& p)
1596 path result;
1597 if (exists(status(p)))
1598 return canonical(p);
1600 path tmp;
1601 auto iter = p.begin(), end = p.end();
1602 // find leading elements of p that exist:
1603 while (iter != end)
1605 tmp = result / *iter;
1606 if (exists(status(tmp)))
1607 swap(result, tmp);
1608 else
1609 break;
1610 ++iter;
1612 // canonicalize:
1613 if (!result.empty())
1614 result = canonical(result);
1615 // append the non-existing elements:
1616 while (iter != end)
1617 result /= *iter++;
1618 // normalize:
1619 return result.lexically_normal();
1622 fs::path
1623 fs::weakly_canonical(const path& p, error_code& ec)
1625 path result;
1626 file_status st = status(p, ec);
1627 if (exists(st))
1628 return canonical(p, ec);
1629 else if (status_known(st))
1630 ec.clear();
1631 else
1632 return result;
1634 path tmp;
1635 auto iter = p.begin(), end = p.end();
1636 // find leading elements of p that exist:
1637 while (iter != end)
1639 tmp = result / *iter;
1640 st = status(tmp, ec);
1641 if (exists(st))
1642 swap(result, tmp);
1643 else
1645 if (status_known(st))
1646 ec.clear();
1647 break;
1649 ++iter;
1651 // canonicalize:
1652 if (!ec && !result.empty())
1653 result = canonical(result, ec);
1654 if (ec)
1655 result.clear();
1656 else
1658 // append the non-existing elements:
1659 while (iter != end)
1660 result /= *iter++;
1661 // normalize:
1662 result = result.lexically_normal();
1664 return result;