hppa: Modify TLS patterns to provide both 32 and 64-bit support.
[official-gcc.git] / libstdc++-v3 / src / c++17 / fs_ops.cc
blobc94d260632f68fdeebbb1ea42deca64af0ea23b5
1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2023 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
30 #ifndef _GNU_SOURCE
31 // Cygwin needs this for secure_getenv
32 # define _GNU_SOURCE 1
33 #endif
35 #include <bits/largefile-config.h>
36 #include <filesystem>
37 #include <functional>
38 #include <ostream>
39 #include <stack>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #include <limits.h> // PATH_MAX
44 #ifdef _GLIBCXX_HAVE_FCNTL_H
45 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
46 #endif
47 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
48 # include <sys/stat.h> // stat, utimensat, fchmodat
49 #endif
50 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
51 # include <sys/statvfs.h> // statvfs
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 # define WIN32_LEAN_AND_MEAN
58 # include <windows.h>
59 #endif
61 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
62 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
63 #include "../filesystem/ops-common.h"
65 #pragma GCC diagnostic ignored "-Wunused-parameter"
67 namespace fs = std::filesystem;
68 namespace posix = std::filesystem::__gnu_posix;
70 fs::path
71 fs::absolute(const path& p)
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 ec));
78 return ret;
81 fs::path
82 fs::absolute(const path& p, error_code& ec)
84 path ret;
85 if (p.empty())
87 ec = make_error_code(std::errc::invalid_argument);
88 return ret;
90 ec.clear();
91 if (p.is_absolute())
93 ret = p;
94 return ret;
97 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
98 // s must remain null-terminated
99 wstring_view s = p.native();
101 if (p.has_root_directory()) // implies !p.has_root_name()
103 // GetFullPathNameW("//") gives unwanted result (PR 88884).
104 // If there are multiple directory separators at the start,
105 // skip all but the last of them.
106 const auto pos = s.find_first_not_of(L"/\\");
107 __glibcxx_assert(pos != 0);
108 s.remove_prefix(std::min(s.length(), pos) - 1);
111 uint32_t len = 1024;
112 wstring buf;
115 buf.resize(len);
116 len = GetFullPathNameW(s.data(), len, buf.data(), nullptr);
118 while (len > buf.size());
120 if (len == 0)
121 ec = __last_system_error();
122 else
124 buf.resize(len);
125 ret = std::move(buf);
127 #else
128 ret = current_path(ec);
129 ret /= p;
130 #endif
131 return ret;
134 namespace
136 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
137 inline bool is_dot(wchar_t c) { return c == L'.'; }
138 #else
139 inline bool is_dot(char c) { return c == '.'; }
140 #endif
142 inline bool is_dot(const fs::path& path)
144 const auto& filename = path.native();
145 return filename.size() == 1 && is_dot(filename[0]);
148 inline bool is_dotdot(const fs::path& path)
150 const auto& filename = path.native();
151 return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
154 struct free_as_in_malloc
156 void operator()(void* p) const { ::free(p); }
159 using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
162 fs::path
163 fs::canonical(const path& p, error_code& ec)
165 path result;
166 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
167 const path pa = absolute(p.lexically_normal(), ec);
168 #else
169 const path pa = absolute(p, ec);
170 #endif
171 if (ec)
172 return result;
174 #ifdef _GLIBCXX_USE_REALPATH
175 char_ptr buf{ nullptr };
176 # if _XOPEN_VERSION < 700
177 // Not safe to call realpath(path, NULL)
178 using char_type = fs::path::value_type;
179 buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
180 # endif
181 if (char* rp = ::realpath(pa.c_str(), buf.get()))
183 if (buf == nullptr)
184 buf.reset(rp);
185 result.assign(rp);
186 ec.clear();
187 return result;
189 if (errno != ENAMETOOLONG)
191 ec.assign(errno, std::generic_category());
192 return result;
194 #endif
196 if (!exists(pa, ec))
198 if (!ec)
199 ec = make_error_code(std::errc::no_such_file_or_directory);
200 return result;
202 // else: we know there are (currently) no unresolvable symlink loops
204 result = pa.root_path();
206 deque<path> cmpts;
207 for (auto& f : pa.relative_path())
208 cmpts.push_back(f);
210 int max_allowed_symlinks = 40;
212 while (!cmpts.empty() && !ec)
214 path f = std::move(cmpts.front());
215 cmpts.pop_front();
217 if (f.empty())
219 // ignore empty element
221 else if (is_dot(f))
223 if (!is_directory(result, ec) && !ec)
224 ec.assign(ENOTDIR, std::generic_category());
226 else if (is_dotdot(f))
228 auto parent = result.parent_path();
229 if (parent.empty())
230 result = pa.root_path();
231 else
232 result.swap(parent);
234 else
236 result /= f;
238 if (is_symlink(result, ec))
240 path link = read_symlink(result, ec);
241 if (!ec)
243 if (--max_allowed_symlinks == 0)
244 ec.assign(ELOOP, std::generic_category());
245 else
247 if (link.is_absolute())
249 result = link.root_path();
250 link = link.relative_path();
252 else
253 result = result.parent_path();
255 cmpts.insert(cmpts.begin(), link.begin(), link.end());
262 if (ec || !exists(result, ec))
263 result.clear();
265 return result;
268 fs::path
269 fs::canonical(const path& p)
271 error_code ec;
272 path res = canonical(p, ec);
273 if (ec)
274 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
275 p, ec));
276 return res;
279 void
280 fs::copy(const path& from, const path& to, copy_options options)
282 error_code ec;
283 copy(from, to, options, ec);
284 if (ec)
285 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
288 namespace std::filesystem
290 // Need this as there's no 'perm_options::none' enumerator.
291 static inline bool is_set(fs::perm_options obj, fs::perm_options bits)
293 return (obj & bits) != fs::perm_options{};
297 namespace
299 struct internal_file_clock : fs::__file_clock
301 using __file_clock::_S_to_sys;
302 using __file_clock::_S_from_sys;
304 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
305 static fs::file_time_type
306 from_stat(const fs::stat_type& st, std::error_code& ec) noexcept
308 const auto sys_time = fs::file_time(st, ec);
309 if (sys_time == sys_time.min())
310 return fs::file_time_type::min();
311 return _S_from_sys(sys_time);
313 #endif
317 void
318 fs::copy(const path& from, const path& to, copy_options options,
319 error_code& ec)
321 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
322 const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
323 const bool create_symlinks = is_set(options, copy_options::create_symlinks);
324 const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
325 const bool use_lstat = create_symlinks || skip_symlinks;
327 file_status f, t;
328 stat_type from_st, to_st;
329 // _GLIBCXX_RESOLVE_LIB_DEFECTS
330 // 2681. filesystem::copy() cannot copy symlinks
331 if (use_lstat || copy_symlinks
332 ? posix::lstat(from.c_str(), &from_st)
333 : posix::stat(from.c_str(), &from_st))
335 ec.assign(errno, std::generic_category());
336 return;
338 if (use_lstat
339 ? posix::lstat(to.c_str(), &to_st)
340 : posix::stat(to.c_str(), &to_st))
342 if (!is_not_found_errno(errno))
344 ec.assign(errno, std::generic_category());
345 return;
347 t = file_status{file_type::not_found};
349 else
350 t = make_file_status(to_st);
351 f = make_file_status(from_st);
353 if (exists(t) && !is_other(t) && !is_other(f)
354 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
356 ec = std::make_error_code(std::errc::file_exists);
357 return;
359 if (is_other(f) || is_other(t))
361 ec = std::make_error_code(std::errc::invalid_argument);
362 return;
364 if (is_directory(f) && is_regular_file(t))
366 ec = std::make_error_code(std::errc::is_a_directory);
367 return;
370 if (is_symlink(f))
372 if (skip_symlinks)
373 ec.clear();
374 else if (!exists(t) && copy_symlinks)
375 copy_symlink(from, to, ec);
376 else
377 // Not clear what should be done here.
378 // "Otherwise report an error as specified in Error reporting (7)."
379 ec = std::make_error_code(std::errc::invalid_argument);
381 else if (is_regular_file(f))
383 if (is_set(options, copy_options::directories_only))
384 ec.clear();
385 else if (create_symlinks)
386 create_symlink(from, to, ec);
387 else if (is_set(options, copy_options::create_hard_links))
388 create_hard_link(from, to, ec);
389 else if (is_directory(t))
390 do_copy_file(from.c_str(), (to / from.filename()).c_str(),
391 copy_file_options(options), &from_st, nullptr, ec);
392 else
394 auto ptr = exists(t) ? &to_st : &from_st;
395 do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
396 &from_st, ptr, ec);
399 // _GLIBCXX_RESOLVE_LIB_DEFECTS
400 // 2682. filesystem::copy() won't create a symlink to a directory
401 else if (is_directory(f) && create_symlinks)
402 ec = std::make_error_code(errc::is_a_directory);
403 else if (is_directory(f) && (is_set(options, copy_options::recursive)
404 || options == copy_options::none))
406 if (!exists(t))
407 if (!create_directory(to, from, ec))
408 return;
409 // set an unused bit in options to disable further recursion
410 if (!is_set(options, copy_options::recursive))
411 options |= static_cast<copy_options>(4096);
412 for (const directory_entry& x : directory_iterator(from, ec))
414 copy(x.path(), to/x.path().filename(), options, ec);
415 if (ec)
416 return;
419 // _GLIBCXX_RESOLVE_LIB_DEFECTS
420 // 2683. filesystem::copy() says "no effects"
421 else
422 ec.clear();
423 #else
424 ec = std::make_error_code(std::errc::function_not_supported);
425 #endif
428 bool
429 fs::copy_file(const path& from, const path& to, copy_options option)
431 error_code ec;
432 bool result = copy_file(from, to, option, ec);
433 if (ec)
434 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
435 ec));
436 return result;
439 bool
440 fs::copy_file(const path& from, const path& to, copy_options options,
441 error_code& ec)
443 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
444 return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
445 nullptr, nullptr, ec);
446 #else
447 ec = std::make_error_code(std::errc::function_not_supported);
448 return false;
449 #endif
453 void
454 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
456 error_code ec;
457 copy_symlink(existing_symlink, new_symlink, ec);
458 if (ec)
459 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
460 existing_symlink, new_symlink, ec));
463 void
464 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
465 error_code& ec) noexcept
467 auto p = read_symlink(existing_symlink, ec);
468 if (ec)
469 return;
470 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
471 if (is_directory(p))
473 create_directory_symlink(p, new_symlink, ec);
474 return;
476 #endif
477 create_symlink(p, new_symlink, ec);
481 bool
482 fs::create_directories(const path& p)
484 error_code ec;
485 bool result = create_directories(p, ec);
486 if (ec)
487 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
488 ec));
489 return result;
492 bool
493 fs::create_directories(const path& p, error_code& ec)
495 if (p.empty())
497 ec = std::make_error_code(errc::invalid_argument);
498 return false;
501 file_status st = status(p, ec);
502 if (is_directory(st))
503 return false;
504 else if (ec && !status_known(st))
505 return false;
506 else if (exists(st))
508 if (!ec)
509 ec = std::make_error_code(std::errc::not_a_directory);
510 return false;
513 __glibcxx_assert(st.type() == file_type::not_found);
514 // !exists(p) so there must be at least one non-existent component in p.
516 std::stack<path> missing;
517 path pp = p;
519 // Strip any trailing slash
520 if (pp.has_relative_path() && !pp.has_filename())
521 pp = pp.parent_path();
525 const auto& filename = pp.filename();
526 if (is_dot(filename) || is_dotdot(filename))
527 pp = pp.parent_path();
528 else
530 missing.push(std::move(pp));
531 if (missing.size() > 1000) // sanity check
533 ec = std::make_error_code(std::errc::filename_too_long);
534 return false;
536 pp = missing.top().parent_path();
539 if (pp.empty())
540 break;
542 st = status(pp, ec);
543 if (exists(st))
545 if (ec)
546 return false;
547 if (!is_directory(st))
549 ec = std::make_error_code(std::errc::not_a_directory);
550 return false;
554 if (ec && exists(st))
555 return false;
557 while (st.type() == file_type::not_found);
559 __glibcxx_assert(!missing.empty());
561 bool created;
564 const path& top = missing.top();
565 created = create_directory(top, ec);
566 if (ec)
567 return false;
568 missing.pop();
570 while (!missing.empty());
572 return created;
575 namespace
577 bool
578 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
580 bool created = false;
581 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
582 posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
583 if (posix::mkdir(p.c_str(), mode))
585 const int err = errno;
586 if (err != EEXIST || !is_directory(p, ec))
587 ec.assign(err, std::generic_category());
589 else
591 ec.clear();
592 created = true;
594 #else
595 ec = std::make_error_code(std::errc::function_not_supported);
596 #endif
597 return created;
599 } // namespace
601 bool
602 fs::create_directory(const path& p)
604 error_code ec;
605 bool result = create_directory(p, ec);
606 if (ec)
607 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
608 ec));
609 return result;
612 bool
613 fs::create_directory(const path& p, error_code& ec) noexcept
615 return create_dir(p, perms::all, ec);
619 bool
620 fs::create_directory(const path& p, const path& attributes)
622 error_code ec;
623 bool result = create_directory(p, attributes, ec);
624 if (ec)
625 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
626 ec));
627 return result;
630 bool
631 fs::create_directory(const path& p, const path& attributes,
632 error_code& ec) noexcept
634 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
635 stat_type st;
636 if (posix::stat(attributes.c_str(), &st))
638 ec.assign(errno, std::generic_category());
639 return false;
641 return create_dir(p, static_cast<perms>(st.st_mode), ec);
642 #else
643 ec = std::make_error_code(std::errc::function_not_supported);
644 return false;
645 #endif
649 void
650 fs::create_directory_symlink(const path& to, const path& new_symlink)
652 error_code ec;
653 create_directory_symlink(to, new_symlink, ec);
654 if (ec)
655 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
656 to, new_symlink, ec));
659 void
660 fs::create_directory_symlink(const path& to, const path& new_symlink,
661 error_code& ec) noexcept
663 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
664 ec = std::make_error_code(std::errc::function_not_supported);
665 #else
666 create_symlink(to, new_symlink, ec);
667 #endif
671 void
672 fs::create_hard_link(const path& to, const path& new_hard_link)
674 error_code ec;
675 create_hard_link(to, new_hard_link, ec);
676 if (ec)
677 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
678 to, new_hard_link, ec));
681 void
682 fs::create_hard_link(const path& to, const path& new_hard_link,
683 error_code& ec) noexcept
685 #ifdef _GLIBCXX_HAVE_LINK
686 if (::link(to.c_str(), new_hard_link.c_str()))
687 ec.assign(errno, std::generic_category());
688 else
689 ec.clear();
690 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
691 if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
692 ec.clear();
693 else
694 ec = __last_system_error();
695 #else
696 ec = std::make_error_code(std::errc::function_not_supported);
697 #endif
700 void
701 fs::create_symlink(const path& to, const path& new_symlink)
703 error_code ec;
704 create_symlink(to, new_symlink, ec);
705 if (ec)
706 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
707 to, new_symlink, ec));
710 void
711 fs::create_symlink(const path& to, const path& new_symlink,
712 error_code& ec) noexcept
714 #ifdef _GLIBCXX_HAVE_SYMLINK
715 if (::symlink(to.c_str(), new_symlink.c_str()))
716 ec.assign(errno, std::generic_category());
717 else
718 ec.clear();
719 #else
720 ec = std::make_error_code(std::errc::function_not_supported);
721 #endif
725 fs::path
726 fs::current_path()
728 error_code ec;
729 path p = current_path(ec);
730 if (ec)
731 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
732 return p;
735 fs::path
736 fs::current_path(error_code& ec)
738 path p;
739 #if defined _GLIBCXX_HAVE_UNISTD_H && ! defined __AVR__
740 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
741 if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
743 p.assign(cwd.get());
744 ec.clear();
746 else
747 ec.assign(errno, std::generic_category());
748 #else
749 #ifdef _PC_PATH_MAX
750 long path_max = pathconf(".", _PC_PATH_MAX);
751 size_t size;
752 if (path_max == -1)
753 size = 1024;
754 else if (path_max > 10240)
755 size = 10240;
756 else
757 size = path_max;
758 #elif defined(PATH_MAX)
759 size_t size = PATH_MAX;
760 #else
761 size_t size = 1024;
762 #endif
763 for (char_ptr buf; p.empty(); size *= 2)
765 using char_type = fs::path::value_type;
766 buf.reset((char_type*)malloc(size * sizeof(char_type)));
767 if (buf)
769 if (getcwd(buf.get(), size))
771 p.assign(buf.get());
772 ec.clear();
774 else if (errno != ERANGE)
776 ec.assign(errno, std::generic_category());
777 return {};
780 else
782 ec = std::make_error_code(std::errc::not_enough_memory);
783 return {};
786 #endif // __GLIBC__
787 #else // _GLIBCXX_HAVE_UNISTD_H
788 ec = std::make_error_code(std::errc::function_not_supported);
789 #endif
790 return p;
793 void
794 fs::current_path(const path& p)
796 error_code ec;
797 current_path(p, ec);
798 if (ec)
799 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
802 void
803 fs::current_path(const path& p, error_code& ec) noexcept
805 #ifdef _GLIBCXX_HAVE_UNISTD_H
806 if (posix::chdir(p.c_str()))
807 ec.assign(errno, std::generic_category());
808 else
809 ec.clear();
810 #else
811 ec = std::make_error_code(std::errc::function_not_supported);
812 #endif
815 bool
816 fs::equivalent(const path& p1, const path& p2)
818 error_code ec;
819 auto result = equivalent(p1, p2, ec);
820 if (ec)
821 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
822 p1, p2, ec));
823 return result;
826 bool
827 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
829 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
830 int err = 0;
831 file_status s1, s2;
832 stat_type st1, st2;
833 if (posix::stat(p1.c_str(), &st1) == 0)
834 s1 = make_file_status(st1);
835 else if (is_not_found_errno(errno))
836 s1.type(file_type::not_found);
837 else
838 err = errno;
840 if (posix::stat(p2.c_str(), &st2) == 0)
841 s2 = make_file_status(st2);
842 else if (is_not_found_errno(errno))
843 s2.type(file_type::not_found);
844 else
845 err = errno;
847 if (exists(s1) && exists(s2))
849 if (is_other(s1) && is_other(s2))
851 ec = std::__unsupported();
852 return false;
854 ec.clear();
855 if (is_other(s1) || is_other(s2))
856 return false;
857 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
858 // st_ino is not set, so can't be used to distinguish files
859 if (st1.st_mode != st2.st_mode || st1.st_dev != st2.st_dev)
860 return false;
862 struct auto_handle {
863 explicit auto_handle(const path& p_)
864 : handle(CreateFileW(p_.c_str(), 0,
865 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
866 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0))
869 ~auto_handle()
870 { if (*this) CloseHandle(handle); }
872 explicit operator bool() const
873 { return handle != INVALID_HANDLE_VALUE; }
875 bool get_info()
876 { return GetFileInformationByHandle(handle, &info); }
878 HANDLE handle;
879 BY_HANDLE_FILE_INFORMATION info;
881 auto_handle h1(p1);
882 auto_handle h2(p2);
883 if (!h1 || !h2)
885 if (!h1 && !h2)
886 ec = __last_system_error();
887 return false;
889 if (!h1.get_info() || !h2.get_info())
891 ec = __last_system_error();
892 return false;
894 return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber
895 && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh
896 && h1.info.nFileIndexLow == h2.info.nFileIndexLow;
897 #else
898 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
899 #endif
901 else if (!exists(s1) && !exists(s2))
902 ec = std::make_error_code(std::errc::no_such_file_or_directory);
903 else if (err)
904 ec.assign(err, std::generic_category());
905 else
906 ec.clear();
907 return false;
908 #else
909 ec = std::make_error_code(std::errc::function_not_supported);
910 #endif
911 return false;
914 std::uintmax_t
915 fs::file_size(const path& p)
917 error_code ec;
918 auto sz = file_size(p, ec);
919 if (ec)
920 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
921 return sz;
924 namespace
926 template<typename Accessor, typename T>
927 inline T
928 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
930 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
931 posix::stat_type st;
932 if (posix::stat(p.c_str(), &st))
934 ec.assign(errno, std::generic_category());
935 return deflt;
937 ec.clear();
938 return f(st);
939 #else
940 ec = std::make_error_code(std::errc::function_not_supported);
941 return deflt;
942 #endif
946 std::uintmax_t
947 fs::file_size(const path& p, error_code& ec) noexcept
949 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
950 struct S
952 S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
953 S() : type(file_type::not_found) { }
954 file_type type;
955 uintmax_t size;
957 auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
958 if (s.type == file_type::regular)
959 return s.size;
960 if (!ec)
962 if (s.type == file_type::directory)
963 ec = std::make_error_code(std::errc::is_a_directory);
964 else
965 ec = std::__unsupported();
967 #else
968 ec = std::make_error_code(std::errc::function_not_supported);
969 #endif
970 return -1;
973 std::uintmax_t
974 fs::hard_link_count(const path& p)
976 error_code ec;
977 auto count = hard_link_count(p, ec);
978 if (ec)
979 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
980 return count;
983 std::uintmax_t
984 fs::hard_link_count(const path& p, error_code& ec) noexcept
986 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
987 return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
988 static_cast<uintmax_t>(-1));
989 #else
990 ec = std::make_error_code(std::errc::function_not_supported);
991 return static_cast<uintmax_t>(-1);
992 #endif
995 bool
996 fs::is_empty(const path& p)
998 error_code ec;
999 bool e = is_empty(p, ec);
1000 if (ec)
1001 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1002 p, ec));
1003 return e;
1006 bool
1007 fs::is_empty(const path& p, error_code& ec)
1009 auto s = status(p, ec);
1010 if (ec)
1011 return false;
1012 bool empty = fs::is_directory(s)
1013 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1014 : fs::file_size(p, ec) == 0;
1015 return ec ? false : empty;
1018 fs::file_time_type
1019 fs::last_write_time(const path& p)
1021 error_code ec;
1022 auto t = last_write_time(p, ec);
1023 if (ec)
1024 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1025 return t;
1028 fs::file_time_type
1029 fs::last_write_time(const path& p, error_code& ec) noexcept
1031 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1032 return do_stat(p, ec,
1033 [&ec](const auto& st) {
1034 return internal_file_clock::from_stat(st, ec);
1036 file_time_type::min());
1037 #else
1038 ec = std::make_error_code(std::errc::function_not_supported);
1039 return file_time_type::min();
1040 #endif
1043 void
1044 fs::last_write_time(const path& p, file_time_type new_time)
1046 error_code ec;
1047 last_write_time(p, new_time, ec);
1048 if (ec)
1049 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1052 void
1053 fs::last_write_time(const path& p,
1054 file_time_type new_time, error_code& ec) noexcept
1056 auto d = internal_file_clock::_S_to_sys(new_time).time_since_epoch();
1057 auto s = chrono::duration_cast<chrono::seconds>(d);
1058 #if _GLIBCXX_USE_UTIMENSAT
1059 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1060 if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1062 --s;
1063 ns += chrono::seconds(1);
1065 struct ::timespec ts[2];
1066 ts[0].tv_sec = 0;
1067 ts[0].tv_nsec = UTIME_OMIT;
1068 ts[1].tv_sec = static_cast<std::time_t>(s.count());
1069 ts[1].tv_nsec = static_cast<long>(ns.count());
1070 if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1071 ec.assign(errno, std::generic_category());
1072 else
1073 ec.clear();
1074 #elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
1075 posix::utimbuf times;
1076 times.modtime = s.count();
1077 times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1078 times.modtime);
1079 if (posix::utime(p.c_str(), &times))
1080 ec.assign(errno, std::generic_category());
1081 else
1082 ec.clear();
1083 #else
1084 ec = std::make_error_code(std::errc::function_not_supported);
1085 #endif
1088 void
1089 fs::permissions(const path& p, perms prms, perm_options opts)
1091 error_code ec;
1092 permissions(p, prms, opts, ec);
1093 if (ec)
1094 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1097 void
1098 fs::permissions(const path& p, perms prms, perm_options opts,
1099 error_code& ec) noexcept
1101 const bool replace = is_set(opts, perm_options::replace);
1102 const bool add = is_set(opts, perm_options::add);
1103 const bool remove = is_set(opts, perm_options::remove);
1104 const bool nofollow = is_set(opts, perm_options::nofollow);
1105 if (((int)replace + (int)add + (int)remove) != 1)
1107 ec = std::make_error_code(std::errc::invalid_argument);
1108 return;
1111 prms &= perms::mask;
1113 file_status st;
1114 if (add || remove || nofollow)
1116 st = nofollow ? symlink_status(p, ec) : status(p, ec);
1117 if (ec)
1118 return;
1119 auto curr = st.permissions();
1120 if (add)
1121 prms |= curr;
1122 else if (remove)
1123 prms = curr & ~prms;
1126 int err = 0;
1127 #if _GLIBCXX_USE_FCHMODAT
1128 const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1129 if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1130 err = errno;
1131 #else
1132 if (nofollow && is_symlink(st))
1133 ec = std::__unsupported();
1134 else if (posix::chmod(p.c_str(), static_cast<posix::mode_t>(prms)))
1135 err = errno;
1136 #endif
1138 if (err)
1139 ec.assign(err, std::generic_category());
1140 else
1141 ec.clear();
1144 fs::path
1145 fs::proximate(const path& p, const path& base)
1147 return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
1150 fs::path
1151 fs::proximate(const path& p, const path& base, error_code& ec)
1153 path result;
1154 const auto p2 = weakly_canonical(p, ec);
1155 if (!ec)
1157 const auto base2 = weakly_canonical(base, ec);
1158 if (!ec)
1159 result = p2.lexically_proximate(base2);
1161 return result;
1164 fs::path
1165 fs::read_symlink(const path& p)
1167 error_code ec;
1168 path tgt = read_symlink(p, ec);
1169 if (ec)
1170 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1171 return tgt;
1174 fs::path fs::read_symlink(const path& p, error_code& ec)
1176 path result;
1177 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1178 stat_type st;
1179 if (posix::lstat(p.c_str(), &st))
1181 ec.assign(errno, std::generic_category());
1182 return result;
1184 else if (!fs::is_symlink(make_file_status(st)))
1186 ec.assign(EINVAL, std::generic_category());
1187 return result;
1190 std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1193 ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
1194 if (len == -1)
1196 ec.assign(errno, std::generic_category());
1197 return result;
1199 else if (len == (ssize_t)buf.size())
1201 if (buf.size() > 4096)
1203 ec.assign(ENAMETOOLONG, std::generic_category());
1204 return result;
1206 buf.resize(buf.size() * 2);
1208 else
1210 buf.resize(len);
1211 result.assign(buf);
1212 ec.clear();
1213 break;
1216 while (true);
1217 #else
1218 ec = std::make_error_code(std::errc::function_not_supported);
1219 #endif
1220 return result;
1223 fs::path
1224 fs::relative(const path& p, const path& base)
1226 return weakly_canonical(p).lexically_relative(weakly_canonical(base));
1229 fs::path
1230 fs::relative(const path& p, const path& base, error_code& ec)
1232 auto result = weakly_canonical(p, ec);
1233 fs::path cbase;
1234 if (!ec)
1235 cbase = weakly_canonical(base, ec);
1236 if (!ec)
1237 result = result.lexically_relative(cbase);
1238 if (ec)
1239 result.clear();
1240 return result;
1243 bool
1244 fs::remove(const path& p)
1246 error_code ec;
1247 const bool result = fs::remove(p, ec);
1248 if (ec)
1249 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1250 return result;
1253 bool
1254 fs::remove(const path& p, error_code& ec) noexcept
1256 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1257 auto st = symlink_status(p, ec);
1258 if (exists(st))
1260 if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
1261 || DeleteFileW(p.c_str()))
1263 ec.clear();
1264 return true;
1266 else if (!ec)
1267 ec = __last_system_error();
1269 else if (status_known(st))
1270 ec.clear();
1271 #else
1272 if (::remove(p.c_str()) == 0)
1274 ec.clear();
1275 return true;
1277 else if (errno == ENOENT)
1278 ec.clear();
1279 else
1280 ec.assign(errno, std::generic_category());
1281 #endif
1282 return false;
1285 std::uintmax_t
1286 fs::remove_all(const path& p)
1288 error_code ec;
1289 uintmax_t count = 0;
1290 recursive_directory_iterator dir(p, directory_options{64|128}, ec);
1291 switch (ec.value()) // N.B. assumes ec.category() == std::generic_category()
1293 case 0:
1294 // Iterate over the directory removing everything.
1296 const recursive_directory_iterator end;
1297 while (dir != end)
1299 dir.__erase(); // throws on error
1300 ++count;
1303 // Directory is empty now, will remove it below.
1304 break;
1305 #ifndef __AVR__
1306 case ENOENT:
1307 // Our work here is done.
1308 return 0;
1309 case ENOTDIR:
1310 case ELOOP:
1311 // Not a directory, will remove below.
1312 break;
1313 #endif
1314 default:
1315 // An error occurred.
1316 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1319 // Remove p itself, which is either a non-directory or is now empty.
1320 return count + fs::remove(p);
1323 std::uintmax_t
1324 fs::remove_all(const path& p, error_code& ec)
1326 uintmax_t count = 0;
1327 recursive_directory_iterator dir(p, directory_options{64|128}, ec);
1328 switch (ec.value()) // N.B. assumes ec.category() == std::generic_category()
1330 case 0:
1331 // Iterate over the directory removing everything.
1333 const recursive_directory_iterator end;
1334 while (dir != end)
1336 dir.__erase(&ec);
1337 if (ec)
1338 return -1;
1339 ++count;
1342 // Directory is empty now, will remove it below.
1343 break;
1344 #ifndef __AVR__
1345 case ENOENT:
1346 // Our work here is done.
1347 ec.clear();
1348 return 0;
1349 case ENOTDIR:
1350 case ELOOP:
1351 // Not a directory, will remove below.
1352 break;
1353 #endif
1354 default:
1355 // An error occurred.
1356 return -1;
1359 // Remove p itself, which is either a non-directory or is now empty.
1360 if (int last = fs::remove(p, ec); !ec)
1361 return count + last;
1362 return -1;
1365 void
1366 fs::rename(const path& from, const path& to)
1368 error_code ec;
1369 rename(from, to, ec);
1370 if (ec)
1371 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1374 void
1375 fs::rename(const path& from, const path& to, error_code& ec) noexcept
1377 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1378 const auto to_status = fs::status(to, ec);
1379 if (to_status.type() == file_type::not_found)
1380 ec.clear();
1381 else if (ec)
1382 return;
1384 if (fs::exists(to_status))
1386 const auto from_status = fs::status(from, ec);
1387 if (ec)
1388 return;
1390 if (fs::is_directory(to_status))
1392 if (!fs::is_directory(from_status))
1394 // Cannot rename a non-directory over an existing directory.
1395 ec = std::make_error_code(std::errc::is_a_directory);
1396 return;
1399 else if (fs::is_directory(from_status))
1401 // Cannot rename a directory over an existing non-directory.
1402 ec = std::make_error_code(std::errc::not_a_directory);
1403 return;
1406 #endif
1407 if (posix::rename(from.c_str(), to.c_str()))
1408 ec.assign(errno, std::generic_category());
1409 else
1410 ec.clear();
1413 void
1414 fs::resize_file(const path& p, uintmax_t size)
1416 error_code ec;
1417 resize_file(p, size, ec);
1418 if (ec)
1419 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1422 void
1423 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1425 if (size > static_cast<uintmax_t>(std::numeric_limits<posix::off_t>::max()))
1426 ec.assign(EINVAL, std::generic_category());
1427 else if (posix::truncate(p.c_str(), size))
1428 ec.assign(errno, std::generic_category());
1429 else
1430 ec.clear();
1434 fs::space_info
1435 fs::space(const path& p)
1437 error_code ec;
1438 space_info s = space(p, ec);
1439 if (ec)
1440 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1441 return s;
1444 fs::space_info
1445 fs::space(const path& p, error_code& ec) noexcept
1447 space_info info = {
1448 static_cast<uintmax_t>(-1),
1449 static_cast<uintmax_t>(-1),
1450 static_cast<uintmax_t>(-1)
1452 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1453 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1454 path dir = absolute(p);
1455 dir.remove_filename();
1456 auto str = dir.c_str();
1457 #else
1458 auto str = p.c_str();
1459 #endif
1461 do_space(str, info.capacity, info.free, info.available, ec);
1462 #endif // _GLIBCXX_HAVE_SYS_STAT_H
1464 return info;
1467 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1468 fs::file_status
1469 fs::status(const fs::path& p, error_code& ec) noexcept
1471 file_status status;
1472 auto str = p.c_str();
1474 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1475 // stat() fails if there's a trailing slash (PR 88881)
1476 path p2;
1477 if (p.has_relative_path() && !p.has_filename())
1479 __try
1481 p2 = p.parent_path();
1482 str = p2.c_str();
1484 __catch(const bad_alloc&)
1486 ec = std::make_error_code(std::errc::not_enough_memory);
1487 return status;
1489 str = p2.c_str();
1491 #endif
1493 stat_type st;
1494 if (posix::stat(str, &st))
1496 int err = errno;
1497 ec.assign(err, std::generic_category());
1498 if (is_not_found_errno(err))
1499 status.type(file_type::not_found);
1500 #ifdef EOVERFLOW
1501 else if (err == EOVERFLOW)
1502 status.type(file_type::unknown);
1503 #endif
1505 else
1507 status = make_file_status(st);
1508 ec.clear();
1510 return status;
1513 fs::file_status
1514 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1516 file_status status;
1517 auto str = p.c_str();
1519 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1520 // stat() fails if there's a trailing slash (PR 88881)
1521 path p2;
1522 if (p.has_relative_path() && !p.has_filename())
1524 __try
1526 p2 = p.parent_path();
1527 str = p2.c_str();
1529 __catch(const bad_alloc&)
1531 ec = std::make_error_code(std::errc::not_enough_memory);
1532 return status;
1534 str = p2.c_str();
1536 #endif
1538 stat_type st;
1539 if (posix::lstat(str, &st))
1541 int err = errno;
1542 ec.assign(err, std::generic_category());
1543 if (is_not_found_errno(err))
1544 status.type(file_type::not_found);
1546 else
1548 status = make_file_status(st);
1549 ec.clear();
1551 return status;
1553 #endif
1555 fs::file_status
1556 fs::status(const fs::path& p)
1558 std::error_code ec;
1559 auto result = status(p, ec);
1560 if (result.type() == file_type::none)
1561 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1562 return result;
1565 fs::file_status
1566 fs::symlink_status(const fs::path& p)
1568 std::error_code ec;
1569 auto result = symlink_status(p, ec);
1570 if (result.type() == file_type::none)
1571 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1572 return result;
1575 fs::path
1576 fs::temp_directory_path()
1578 error_code ec;
1579 path p = fs::get_temp_directory_from_env(ec);
1580 if (!ec)
1582 auto st = status(p, ec);
1583 if (!ec && !is_directory(st))
1584 ec = std::make_error_code(std::errc::not_a_directory);
1586 if (ec)
1588 if (p.empty())
1589 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1590 else
1591 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", p, ec));
1593 return p;
1596 fs::path
1597 fs::temp_directory_path(error_code& ec)
1599 path p = fs::get_temp_directory_from_env(ec);
1600 if (!ec)
1602 auto st = status(p, ec);
1603 if (ec)
1604 p.clear();
1605 else if (!is_directory(st))
1607 p.clear();
1608 ec = std::make_error_code(std::errc::not_a_directory);
1611 return p;
1614 fs::path
1615 fs::weakly_canonical(const path& p)
1617 path result;
1618 if (exists(status(p)))
1619 return canonical(p);
1621 path tmp;
1622 auto iter = p.begin(), end = p.end();
1623 // find leading elements of p that exist:
1624 while (iter != end)
1626 tmp = result / *iter;
1627 if (exists(status(tmp)))
1628 swap(result, tmp);
1629 else
1630 break;
1631 ++iter;
1633 // canonicalize:
1634 if (!result.empty())
1635 result = canonical(result);
1636 // append the non-existing elements:
1637 while (iter != end)
1638 result /= *iter++;
1639 // normalize:
1640 return result.lexically_normal();
1643 fs::path
1644 fs::weakly_canonical(const path& p, error_code& ec)
1646 path result;
1647 file_status st = status(p, ec);
1648 if (exists(st))
1649 return canonical(p, ec);
1650 else if (status_known(st))
1651 ec.clear();
1652 else
1653 return result;
1655 path tmp;
1656 auto iter = p.begin(), end = p.end();
1657 // find leading elements of p that exist:
1658 while (iter != end)
1660 tmp = result / *iter;
1661 st = status(tmp, ec);
1662 if (exists(st))
1663 swap(result, tmp);
1664 else
1666 if (status_known(st))
1667 ec.clear();
1668 break;
1670 ++iter;
1672 // canonicalize:
1673 if (!ec && !result.empty())
1674 result = canonical(result, ec);
1675 if (ec)
1676 result.clear();
1677 else
1679 // append the non-existing elements:
1680 while (iter != end)
1681 result /= *iter++;
1682 // normalize:
1683 result = result.lexically_normal();
1685 return result;