Update copyright years.
[official-gcc.git] / libstdc++-v3 / src / filesystem / ops.cc
blob777117843b628c79ca823d37545a68e516b207b5
1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2015 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 #include <experimental/filesystem>
26 #include <functional>
27 #include <stack>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #ifdef _GLIBCXX_HAVE_UNISTD_H
32 # include <unistd.h>
33 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
34 # include <sys/types.h>
35 # include <sys/stat.h>
36 # endif
37 #endif
38 #ifdef _GLIBCXX_HAVE_FCNTL_H
39 # include <fcntl.h>
40 #endif
41 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
42 # include <sys/statvfs.h>
43 #endif
44 #ifdef _GLIBCXX_HAVE_GNU_SENDFILE
45 # include <sys/sendfile.h>
46 #else
47 # include <ext/stdio_filebuf.h>
48 # include <ostream>
49 #endif
51 namespace fs = std::experimental::filesystem;
53 fs::path
54 fs::absolute(const path& p, const path& base)
56 const bool has_root_dir = p.has_root_directory();
57 const bool has_root_name = p.has_root_name();
58 path abs;
59 if (has_root_dir && has_root_name)
60 abs = p;
61 else
63 abs = base.is_absolute() ? base : absolute(base);
64 if (has_root_dir)
65 abs = abs.root_name() / p;
66 else if (has_root_name)
67 abs = p.root_name() / abs.root_directory() / abs.relative_path()
68 / p.relative_path();
69 else
70 abs = abs / p;
72 return abs;
75 namespace
77 struct free_as_in_malloc
79 void operator()(void* p) const { ::free(p); }
82 using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
85 fs::path
86 fs::canonical(const path& p, const path& base, error_code& ec)
88 path can;
89 #ifdef _GLIBCXX_USE_REALPATH
90 if (char_ptr rp = char_ptr{::realpath(absolute(p, base).c_str(), nullptr)})
92 can.assign(rp.get());
93 ec.clear();
95 else
96 ec.assign(errno, std::generic_category());
97 #else
98 ec = std::make_error_code(std::errc::not_supported);
99 #endif
100 return can;
103 fs::path
104 fs::canonical(const path& p, error_code& ec)
106 path cur = current_path(ec);
107 if (ec.value())
108 return {};
109 return canonical(p, cur, ec);
112 fs::path
113 fs::canonical(const path& p, const path& base)
115 error_code ec;
116 path can = canonical(p, base, ec);
117 if (ec.value())
118 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, ec));
119 return can;
122 void
123 fs::copy(const path& from, const path& to, copy_options options)
125 error_code ec;
126 copy(from, to, options, ec);
127 if (ec.value())
128 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
131 namespace
133 template<typename Bitmask>
134 bool is_set(Bitmask obj, Bitmask bits)
136 return (obj & bits) != Bitmask::none;
140 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
141 namespace
143 fs::file_status
144 make_file_status(const struct ::stat& st)
146 using fs::file_status;
147 using fs::file_type;
148 using fs::perms;
149 file_type ft;
150 perms perm = static_cast<perms>(st.st_mode) & perms::mask;
151 #ifdef _GLIBCXX_HAVE_S_ISREG
152 if (S_ISREG(st.st_mode))
153 ft = file_type::regular;
154 else if (S_ISDIR(st.st_mode))
155 ft = file_type::directory;
156 else if (S_ISCHR(st.st_mode))
157 ft = file_type::character;
158 else if (S_ISBLK(st.st_mode))
159 ft = file_type::block;
160 else if (S_ISFIFO(st.st_mode))
161 ft = file_type::fifo;
162 else if (S_ISLNK(st.st_mode))
163 ft = file_type::symlink;
164 else if (S_ISSOCK(st.st_mode))
165 ft = file_type::socket;
166 else
167 #endif
168 ft = file_type::unknown;
169 return file_status{ft, perm};
172 inline bool
173 is_not_found_errno(int err)
175 return err == ENOENT || err == ENOTDIR;
178 inline fs::file_time_type
179 file_time(const struct ::stat& st)
181 using namespace std::chrono;
182 return fs::file_time_type{
183 #ifdef _GLIBCXX_USE_ST_MTIM
184 seconds{st.st_mtim.tv_sec} + nanoseconds{st.st_mtim.tv_nsec}
185 #else
186 seconds{st.st_mtime}
187 #endif
191 bool
192 do_copy_file(const fs::path& from, const fs::path& to,
193 fs::copy_options option,
194 struct ::stat* from_st, struct ::stat* to_st,
195 std::error_code& ec) noexcept
197 struct ::stat st1, st2;
198 fs::file_status t, f;
200 if (to_st == nullptr)
202 if (::stat(to.c_str(), &st1))
204 int err = errno;
205 if (!is_not_found_errno(err))
207 ec.assign(err, std::generic_category());
208 return false;
211 else
212 to_st = &st1;
214 else if (to_st == from_st)
215 to_st = nullptr;
217 if (to_st == nullptr)
218 t = fs::file_status{fs::file_type::not_found};
219 else
220 t = make_file_status(*to_st);
222 if (from_st == nullptr)
224 if (::stat(from.c_str(), &st2))
226 ec.assign(errno, std::generic_category());
227 return false;
229 else
230 from_st = &st2;
232 f = make_file_status(*from_st);
234 if (exists(t))
236 if (!is_other(t) && !is_other(f)
237 && to_st->st_dev == from_st->st_dev
238 && to_st->st_ino == from_st->st_ino)
240 ec = std::make_error_code(std::errc::file_exists);
241 return false;
244 if (is_set(option, fs::copy_options::skip_existing))
246 ec.clear();
247 return false;
249 else if (is_set(option, fs::copy_options::update_existing))
251 if (file_time(*from_st) <= file_time(*to_st))
253 ec.clear();
254 return false;
257 else if (!is_set(option, fs::copy_options::overwrite_existing))
259 ec = std::make_error_code(std::errc::file_exists);
260 return false;
264 struct CloseFD {
265 ~CloseFD() { if (fd != -1) ::close(fd); }
266 int fd;
269 CloseFD in = { ::open(from.c_str(), O_RDONLY) };
270 if (in.fd == -1)
272 ec.assign(errno, std::generic_category());
273 return false;
275 CloseFD out = { ::open(to.c_str(), O_WRONLY|O_CREAT) };
276 if (out.fd == -1)
278 ec.assign(errno, std::generic_category());
279 return false;
282 #ifdef _GLIBCXX_HAVE_GNU_SENDFILE
283 auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size);
284 if (n != from_st->st_size)
286 ec.assign(errno, std::generic_category());
287 return false;
289 #else
290 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
291 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
292 if (std::ostream(&sbout) << &sbin)
294 ec.clear();
295 return true;
297 else
299 ec = std::make_error_code(std::errc::io_error);
300 return false;
302 #endif
304 #ifdef _GLIBCXX_HAVE_FCHMOD
305 if (::fchmod(out.fd, from_st->st_mode))
306 #else
307 if (::chmod(to.c_str(), from_st->st_mode))
308 #endif
310 ec.assign(errno, std::generic_category());
311 return false;
313 return true;
316 #endif
318 void
319 fs::copy(const path& from, const path& to, copy_options options,
320 error_code& ec) noexcept
322 bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
323 bool create_symlinks = is_set(options, copy_options::create_symlinks);
324 bool use_lstat = create_symlinks || skip_symlinks;
326 file_status f, t;
327 struct ::stat from_st, to_st;
328 if (use_lstat
329 ? ::lstat(from.c_str(), &from_st)
330 : ::stat(from.c_str(), &from_st))
332 ec.assign(errno, std::generic_category());
333 return;
335 if (use_lstat
336 ? ::lstat(to.c_str(), &to_st)
337 : ::stat(to.c_str(), &to_st))
339 if (!is_not_found_errno(errno))
341 ec.assign(errno, std::generic_category());
342 return;
344 t = file_status{file_type::not_found};
346 else
347 t = make_file_status(to_st);
348 f = make_file_status(from_st);
350 if (exists(t) && !is_other(t) && !is_other(f)
351 && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
353 ec = std::make_error_code(std::errc::file_exists);
354 return;
356 if (is_other(f) || is_other(t))
358 ec = std::make_error_code(std::errc::not_supported);
359 return;
361 if (is_directory(f) && is_regular_file(t))
363 ec = std::make_error_code(std::errc::is_a_directory);
364 return;
367 if (is_symlink(f))
369 if (skip_symlinks)
370 ec.clear();
371 else if (!exists(t) && is_set(options, copy_options::copy_symlinks))
372 copy_symlink(from, to, ec);
373 else
374 // Not clear what should be done here.
375 // "Otherwise report an error as specified in Error reporting (7)."
376 ec = std::make_error_code(std::errc::invalid_argument);
378 else if (is_regular_file(f))
380 if (is_set(options, copy_options::directories_only))
381 ec.clear();
382 else if (create_symlinks)
383 create_symlink(from, to, ec);
384 else if (is_set(options, copy_options::create_hard_links))
385 create_hard_link(from, to, ec);
386 else if (is_directory(t))
387 do_copy_file(from, to / from.filename(), options, &from_st, 0, ec);
388 else
390 auto ptr = exists(t) ? &to_st : &from_st;
391 do_copy_file(from, to, options, &from_st, ptr, ec);
394 else if (is_directory(f) && (is_set(options, copy_options::recursive)
395 || options == copy_options::none))
397 if (!exists(t))
398 if (!create_directory(to, from, ec))
399 return;
400 // set an unused bit in options to disable further recursion
401 if (!is_set(options, copy_options::recursive))
402 options |= static_cast<copy_options>(4096);
403 for (const directory_entry& x : directory_iterator(from))
404 copy(x.path(), to/x.path().filename(), options, ec);
406 // "Otherwise no effects." (should ec.clear() be called?)
409 bool
410 fs::copy_file(const path& from, const path& to, copy_options option)
412 error_code ec;
413 bool result = copy_file(from, to, option, ec);
414 if (ec.value())
415 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
416 ec));
417 return result;
420 bool
421 fs::copy_file(const path& from, const path& to, copy_options option,
422 error_code& ec) noexcept
424 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
425 return do_copy_file(from, to, option, nullptr, nullptr, ec);
426 #else
427 ec = std::make_error_code(std::errc::not_supported);
428 return false;
429 #endif
433 void
434 fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
436 error_code ec;
437 copy_symlink(existing_symlink, new_symlink, ec);
438 if (ec.value())
439 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
440 existing_symlink, new_symlink, ec));
443 void
444 fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
445 error_code& ec) noexcept
447 auto p = read_symlink(existing_symlink, ec);
448 if (ec.value())
449 return;
450 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
451 if (is_directory(p))
453 create_directory_symlink(p, new_symlink, ec);
454 return;
456 #endif
457 create_symlink(p, new_symlink, ec);
461 bool
462 fs::create_directories(const path& p)
464 error_code ec;
465 bool result = create_directories(p, ec);
466 if (ec.value())
467 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
468 ec));
469 return result;
472 bool
473 fs::create_directories(const path& p, error_code& ec) noexcept
475 std::stack<path> missing;
476 path pp = p;
477 ec.clear();
478 while (!p.empty() && !exists(pp, ec) && !ec.value())
480 missing.push(pp);
481 pp = pp.parent_path();
483 while (!missing.empty() && !ec.value())
485 create_directory(missing.top(), ec);
486 missing.pop();
488 return missing.empty();
491 namespace
493 bool
494 create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
496 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
497 ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
498 if (::mkdir(p.c_str(), mode))
500 ec.assign(errno, std::generic_category());
501 return false;
503 else
505 ec.clear();
506 return true;
508 #else
509 ec = std::make_error_code(std::errc::not_supported);
510 return false;
511 #endif
513 } // namespace
515 bool
516 fs::create_directory(const path& p)
518 error_code ec;
519 bool result = create_directory(p, ec);
520 if (ec.value())
521 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
522 ec));
523 return result;
526 bool
527 fs::create_directory(const path& p, error_code& ec) noexcept
529 return create_dir(p, perms::all, ec);
533 bool
534 fs::create_directory(const path& p, const path& attributes)
536 error_code ec;
537 bool result = create_directory(p, attributes, ec);
538 if (ec.value())
539 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
540 ec));
541 return result;
544 bool
545 fs::create_directory(const path& p, const path& attributes,
546 error_code& ec) noexcept
548 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
549 struct ::stat st;
550 if (::stat(attributes.c_str(), &st))
552 ec.assign(errno, std::generic_category());
553 return false;
555 return create_dir(p, static_cast<perms>(st.st_mode), ec);
556 #else
557 ec = std::make_error_code(std::errc::not_supported);
558 return false;
559 #endif
563 void
564 fs::create_directory_symlink(const path& to, const path& new_symlink)
566 error_code ec;
567 create_directory_symlink(to, new_symlink, ec);
568 if (ec.value())
569 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
570 to, new_symlink, ec));
573 void
574 fs::create_directory_symlink(const path& to, const path& new_symlink,
575 error_code& ec) noexcept
577 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
578 ec = std::make_error_code(std::errc::not_supported);
579 #else
580 create_symlink(to, new_symlink, ec);
581 #endif
585 void
586 fs::create_hard_link(const path& to, const path& new_hard_link)
588 error_code ec;
589 create_hard_link(to, new_hard_link, ec);
590 if (ec.value())
591 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
592 to, new_hard_link, ec));
595 void
596 fs::create_hard_link(const path& to, const path& new_hard_link,
597 error_code& ec) noexcept
599 #ifdef _GLIBCXX_HAVE_UNISTD_H
600 if (::link(to.c_str(), new_hard_link.c_str()))
601 ec.assign(errno, std::generic_category());
602 else
603 ec.clear();
604 #else
605 ec = std::make_error_code(std::errc::not_supported);
606 #endif
609 void
610 fs::create_symlink(const path& to, const path& new_symlink)
612 error_code ec;
613 create_symlink(to, new_symlink, ec);
614 if (ec.value())
615 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
616 to, new_symlink, ec));
619 void
620 fs::create_symlink(const path& to, const path& new_symlink,
621 error_code& ec) noexcept
623 #ifdef _GLIBCXX_HAVE_UNISTD_H
624 if (::symlink(to.c_str(), new_symlink.c_str()))
625 ec.assign(errno, std::generic_category());
626 else
627 ec.clear();
628 #else
629 ec = std::make_error_code(std::errc::not_supported);
630 #endif
634 fs::path
635 fs::current_path()
637 error_code ec;
638 path p = current_path(ec);
639 if (ec.value())
640 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
641 return p;
644 fs::path
645 fs::current_path(error_code& ec)
647 path p;
648 #ifdef _GLIBCXX_HAVE_UNISTD_H
649 #ifdef __GLIBC__
650 if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
652 p.assign(cwd.get());
653 ec.clear();
655 else
656 ec.assign(errno, std::generic_category());
657 #else
658 long path_max = pathconf(".", _PC_PATH_MAX);
659 size_t size;
660 if (path_max == -1)
661 size = 1024;
662 else if (path_max > 10240)
663 size = 10240;
664 else
665 size = path_max;
666 for (char_ptr buf; p.empty(); size *= 2)
668 if (char* ptr = realloc(buf.release(), size))
670 buf.reset(ptr);
671 if (char* ptr = getcwd(buf.get(), size))
673 p.assign(buf.get());
674 ec.clear();
676 if (errno != ERANGE)
678 ec.assign(errno, std::generic_category());
679 return {};
682 else
684 ec = std::make_error_code(std::errc::not_enough_memory);
685 return {};
688 #endif // __GLIBC__
689 #else // _GLIBCXX_HAVE_UNISTD_H
690 ec = std::make_error_code(std::errc::not_supported);
691 #endif
692 return p;
695 void
696 fs::current_path(const path& p)
698 error_code ec;
699 current_path(p, ec);
700 if (ec.value())
701 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
704 void
705 fs::current_path(const path& p, error_code& ec) noexcept
707 #ifdef _GLIBCXX_HAVE_UNISTD_H
708 if (int err = ::chdir(p.c_str()))
709 ec.assign(err, std::generic_category());
710 else
711 ec.clear();
712 #else
713 ec = std::make_error_code(std::errc::not_supported);
714 #endif
717 bool
718 fs::equivalent(const path& p1, const path& p2)
720 error_code ec;
721 auto result = equivalent(p1, p2, ec);
722 if (ec.value())
723 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
724 p1, p2, ec));
725 return result;
728 bool
729 fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
731 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
732 struct ::stat st1, st2;
733 if (::stat(p1.c_str(), &st1) == 0 && ::stat(p2.c_str(), &st2) == 0)
735 file_status s1 = make_file_status(st1);
736 file_status s2 = make_file_status(st2);
737 if (is_other(s1) && is_other(s2))
739 ec = std::make_error_code(std::errc::not_supported);
740 return false;
742 ec.clear();
743 return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
745 else if (is_not_found_errno(errno))
747 ec = std::make_error_code(std::errc::no_such_file_or_directory);
748 return false;
750 ec.assign(errno, std::generic_category());
751 #else
752 ec = std::make_error_code(std::errc::not_supported);
753 #endif
754 return false;
757 std::uintmax_t
758 fs::file_size(const path& p)
760 error_code ec;
761 auto sz = file_size(p, ec);
762 if (ec.value())
763 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
764 return sz;
767 namespace
769 template<typename Accessor, typename T>
771 do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
773 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
774 struct ::stat st;
775 if (::stat(p.c_str(), &st))
777 ec.assign(errno, std::generic_category());
778 return deflt;
780 ec.clear();
781 return f(st);
782 #else
783 ec = std::make_error_code(std::errc::not_supported);
784 return deflt;
785 #endif
789 std::uintmax_t
790 fs::file_size(const path& p, error_code& ec) noexcept
792 return do_stat(p, ec, std::mem_fn(&stat::st_size),
793 static_cast<uintmax_t>(-1));
796 std::uintmax_t
797 fs::hard_link_count(const path& p)
799 error_code ec;
800 auto count = hard_link_count(p, ec);
801 if (ec.value())
802 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
803 return count;
806 std::uintmax_t
807 fs::hard_link_count(const path& p, error_code& ec) noexcept
809 return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
810 static_cast<uintmax_t>(-1));
813 bool
814 fs::is_empty(const path& p)
816 return fs::is_directory(status(p))
817 ? fs::directory_iterator(p) == fs::directory_iterator()
818 : fs::file_size(p) == 0;
821 bool
822 fs::is_empty(const path& p, error_code& ec) noexcept
824 auto s = status(p, ec);
825 if (ec.value())
826 return false;
827 return fs::is_directory(s)
828 ? fs::directory_iterator(p, ec) == fs::directory_iterator()
829 : fs::file_size(p, ec) == 0;
832 fs::file_time_type
833 fs::last_write_time(const path& p)
835 error_code ec;
836 auto t = last_write_time(p, ec);
837 if (ec.value())
838 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
839 return t;
842 fs::file_time_type
843 fs::last_write_time(const path& p, error_code& ec) noexcept
845 return do_stat(p, ec, [](const auto& st) { return file_time(st); },
846 file_time_type::min());
849 void
850 fs::last_write_time(const path& p, file_time_type new_time)
852 error_code ec;
853 last_write_time(p, new_time, ec);
854 if (ec.value())
855 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
858 void
859 fs::last_write_time(const path& p, file_time_type new_time,
860 error_code& ec) noexcept
862 auto d = new_time.time_since_epoch();
863 auto s = chrono::duration_cast<chrono::seconds>(d);
864 auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
865 #ifdef _GLIBCXX_USE_UTIMENSAT
866 struct ::timespec ts[2] = {
867 { 0, UTIME_OMIT },
868 { static_cast<std::time_t>(s.count()), static_cast<long>(ns.count()) }
870 if (utimensat(AT_FDCWD, p.c_str(), ts, 0))
871 ec.assign(errno, std::generic_category());
872 else
873 ec.clear();
874 #else
875 ec = std::make_error_code(std::errc::not_supported);
876 #endif
879 void
880 fs::permissions(const path& p, perms prms)
882 error_code ec;
883 permissions(p, prms, ec);
884 if (ec.value())
885 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
888 void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
890 if (int err = ::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0))
891 ec.assign(err, std::generic_category());
892 else
893 ec.clear();
896 fs::path
897 fs::read_symlink(const path& p)
899 error_code ec;
900 path tgt = read_symlink(p, ec);
901 if (ec.value())
902 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
903 return tgt;
906 fs::path fs::read_symlink(const path& p, error_code& ec)
908 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
909 struct ::stat st;
910 if (::lstat(p.c_str(), &st))
912 ec.assign(errno, std::generic_category());
913 return {};
915 std::string buf(st.st_size, '\0');
916 ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
917 if (len == -1)
919 ec.assign(errno, std::generic_category());
920 return {};
922 return path{buf.data(), buf.data()+len};
923 #else
924 ec = std::make_error_code(std::errc::not_supported);
925 return {};
926 #endif
930 bool
931 fs::remove(const path& p)
933 error_code ec;
934 bool result = fs::remove(p, ec);
935 if (ec.value())
936 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
937 return result;
940 bool
941 fs::remove(const path& p, error_code& ec) noexcept
943 if (exists(symlink_status(p, ec)))
945 if (::remove(p.c_str()) == 0)
947 ec.clear();
948 return true;
950 else
951 ec.assign(errno, std::generic_category());
953 return false;
957 std::uintmax_t
958 fs::remove_all(const path& p)
960 error_code ec;
961 bool result = remove_all(p, ec);
962 if (ec.value())
963 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
964 return result;
967 std::uintmax_t
968 fs::remove_all(const path& p, error_code& ec) noexcept
970 auto fs = symlink_status(p, ec);
971 uintmax_t count = 0;
972 if (ec.value() == 0 && fs.type() == file_type::directory)
973 for (directory_iterator d(p, ec), end; ec.value() == 0 && d != end; ++d)
974 count += fs::remove(d->path(), ec);
975 if (ec.value())
976 return -1;
977 return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear()
980 void
981 fs::rename(const path& from, const path& to)
983 error_code ec;
984 rename(from, to, ec);
985 if (ec.value())
986 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
989 void
990 fs::rename(const path& from, const path& to, error_code& ec) noexcept
992 if (::rename(from.c_str(), to.c_str()))
993 ec.assign(errno, std::generic_category());
994 else
995 ec.clear();
998 void
999 fs::resize_file(const path& p, uintmax_t size)
1001 error_code ec;
1002 resize_file(p, size, ec);
1003 if (ec.value())
1004 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1007 void
1008 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1010 #ifdef _GLIBCXX_HAVE_UNISTD_H
1011 if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1012 ec.assign(EINVAL, std::generic_category());
1013 else if (::truncate(p.c_str(), size))
1014 ec.assign(errno, std::generic_category());
1015 else
1016 ec.clear();
1017 #else
1018 ec = std::make_error_code(std::errc::not_supported);
1019 #endif
1023 fs::space_info
1024 fs::space(const path& p)
1026 error_code ec;
1027 space_info s = space(p, ec);
1028 if (ec.value())
1029 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1030 return s;
1033 fs::space_info
1034 fs::space(const path& p, error_code& ec) noexcept
1036 space_info info = {
1037 static_cast<uintmax_t>(-1),
1038 static_cast<uintmax_t>(-1),
1039 static_cast<uintmax_t>(-1)
1041 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1042 struct ::statvfs f;
1043 if (int err = ::statvfs(p.c_str(), &f))
1044 ec.assign(err, std::generic_category());
1045 else
1047 info = space_info{
1048 f.f_blocks * f.f_frsize,
1049 f.f_bfree * f.f_frsize,
1050 f.f_bavail * f.f_frsize
1052 ec.clear();
1054 #endif
1055 return info;
1058 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1059 fs::file_status
1060 fs::status(const fs::path& p, std::error_code& ec) noexcept
1062 file_status status;
1063 struct ::stat st;
1064 if (::stat(p.c_str(), &st))
1066 int err = errno;
1067 ec.assign(err, std::generic_category());
1068 if (is_not_found_errno(err))
1069 status = file_status{file_type::not_found};
1071 else
1073 status = make_file_status(st);
1074 ec.clear();
1076 return status;
1079 fs::file_status
1080 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1082 file_status status;
1083 struct ::stat st;
1084 if (::lstat(p.c_str(), &st))
1086 int err = errno;
1087 ec.assign(err, std::generic_category());
1088 if (is_not_found_errno(err))
1089 status = file_status{file_type::not_found};
1091 else
1093 status = make_file_status(st);
1094 ec.clear();
1096 return status;
1098 #endif
1100 fs::file_status
1101 fs::status(const fs::path& p)
1103 std::error_code ec;
1104 auto s = status(p, ec);
1105 if (ec.value())
1106 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1107 return s;
1110 fs::file_status
1111 fs::symlink_status(const fs::path& p)
1113 std::error_code ec;
1114 auto s = symlink_status(p, ec);
1115 if (ec.value())
1116 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", ec));
1117 return s;
1120 fs::path
1121 fs::system_complete(const path& p)
1123 error_code ec;
1124 path comp = system_complete(p, ec);
1125 if (ec.value())
1126 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1127 return comp;
1130 fs::path
1131 fs::system_complete(const path& p, error_code& ec)
1133 path base = current_path(ec);
1134 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1135 if (p.is_absolute() || !p.has_root_name()
1136 || p.root_name() == base.root_name())
1137 return absolute(p, base);
1138 // else TODO
1139 ec = std::make_error_code(std::errc::not_supported);
1140 return {};
1141 #else
1142 if (ec.value())
1143 return {};
1144 return absolute(p, base);
1145 #endif
1148 fs::path fs::temp_directory_path()
1150 error_code ec;
1151 path tmp = temp_directory_path(ec);
1152 if (ec.value())
1153 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1154 return tmp;
1157 fs::path fs::temp_directory_path(error_code& ec)
1159 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1160 return {}; // TODO
1161 #else
1162 const char* tmpdir = ::getenv("TMPDIR");
1163 if (!tmpdir)
1164 tmpdir = "/tmp";
1165 ec.clear();
1166 return tmpdir;
1167 #endif