1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2018 Free Software Foundation, Inc.
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)
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
31 #include <experimental/filesystem>
35 #include <ext/stdio_filebuf.h>
39 #include <limits.h> // PATH_MAX
40 #ifdef _GLIBCXX_HAVE_FCNTL_H
41 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
43 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
44 # include <sys/stat.h> // stat, utimensat, fchmodat
46 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
47 # include <sys/statvfs.h> // statvfs
49 #ifdef _GLIBCXX_USE_SENDFILE
50 # include <sys/sendfile.h> // sendfile
52 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
53 # include <utime.h> // utime
56 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
57 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
58 #include "ops-common.h"
60 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
62 # define utime _wutime
64 # define chmod _wchmod
67 namespace fs
= std::filesystem
;
70 fs::absolute(const path
& p
)
72 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
74 path ret
= absolute(p
, ec
);
76 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p
,
77 std::make_error_code(errc::not_supported
)));
80 return current_path() / p
;
85 fs::absolute(const path
& p
, error_code
& ec
)
87 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
88 ec
= std::make_error_code(errc::not_supported
);
92 return current_path() / p
;
98 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
99 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
101 inline bool is_dot(char c
) { return c
== '.'; }
104 inline bool is_dot(const fs::path
& path
)
106 const auto& filename
= path
.native();
107 return filename
.size() == 1 && is_dot(filename
[0]);
110 inline bool is_dotdot(const fs::path
& path
)
112 const auto& filename
= path
.native();
113 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
116 struct free_as_in_malloc
118 void operator()(void* p
) const { ::free(p
); }
121 using char_ptr
= std::unique_ptr
<char[], free_as_in_malloc
>;
125 fs::canonical(const path
& p
, error_code
& ec
)
128 const path pa
= absolute(p
, ec
);
132 #ifdef _GLIBCXX_USE_REALPATH
133 char_ptr buf
{ nullptr };
134 # if _XOPEN_VERSION < 700
135 // Not safe to call realpath(path, NULL)
136 buf
.reset( (char*)::malloc(PATH_MAX
) );
138 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
146 if (errno
!= ENAMETOOLONG
)
148 ec
.assign(errno
, std::generic_category());
156 ec
= make_error_code(std::errc::no_such_file_or_directory
);
159 // else: we know there are (currently) no unresolvable symlink loops
161 result
= pa
.root_path();
164 for (auto& f
: pa
.relative_path())
167 int max_allowed_symlinks
= 40;
169 while (!cmpts
.empty() && !ec
)
171 path f
= std::move(cmpts
.front());
176 // ignore empty element
180 if (!is_directory(result
, ec
) && !ec
)
181 ec
.assign(ENOTDIR
, std::generic_category());
183 else if (is_dotdot(f
))
185 auto parent
= result
.parent_path();
187 result
= pa
.root_path();
195 if (is_symlink(result
, ec
))
197 path link
= read_symlink(result
, ec
);
200 if (--max_allowed_symlinks
== 0)
201 ec
.assign(ELOOP
, std::generic_category());
204 if (link
.is_absolute())
206 result
= link
.root_path();
207 link
= link
.relative_path();
210 result
= result
.parent_path();
212 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
219 if (ec
|| !exists(result
, ec
))
226 fs::canonical(const path
& p
)
229 path res
= canonical(p
, ec
);
231 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
237 fs::copy(const path
& from
, const path
& to
, copy_options options
)
240 copy(from
, to
, options
, ec
);
242 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
245 namespace std::filesystem
247 // Need this as there's no 'perm_options::none' enumerator.
248 inline bool is_set(fs::perm_options obj
, fs::perm_options bits
)
250 return (obj
& bits
) != fs::perm_options
{};
254 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
255 #ifdef NEED_DO_COPY_FILE
257 fs::do_copy_file(const char* from
, const char* to
,
258 copy_options_existing_file options
,
259 stat_type
* from_st
, stat_type
* to_st
,
260 std::error_code
& ec
) noexcept
263 fs::file_status t
, f
;
265 if (to_st
== nullptr)
267 if (::stat(to
, &st1
))
269 const int err
= errno
;
270 if (!is_not_found_errno(err
))
272 ec
.assign(err
, std::generic_category());
279 else if (to_st
== from_st
)
282 if (to_st
== nullptr)
283 t
= fs::file_status
{fs::file_type::not_found
};
285 t
= make_file_status(*to_st
);
287 if (from_st
== nullptr)
289 if (::stat(from
, &st2
))
291 ec
.assign(errno
, std::generic_category());
297 f
= make_file_status(*from_st
);
298 // _GLIBCXX_RESOLVE_LIB_DEFECTS
299 // 2712. copy_file() has a number of unspecified error conditions
300 if (!is_regular_file(f
))
302 ec
= std::make_error_code(std::errc::not_supported
);
308 if (!is_regular_file(t
))
310 ec
= std::make_error_code(std::errc::not_supported
);
314 if (to_st
->st_dev
== from_st
->st_dev
315 && to_st
->st_ino
== from_st
->st_ino
)
317 ec
= std::make_error_code(std::errc::file_exists
);
326 else if (options
.update
)
328 const auto from_mtime
= file_time(*from_st
, ec
);
331 if ((from_mtime
<= file_time(*to_st
, ec
)) || ec
)
334 else if (!options
.overwrite
)
336 ec
= std::make_error_code(std::errc::file_exists
);
339 else if (!is_regular_file(t
))
341 ec
= std::make_error_code(std::errc::not_supported
);
347 ~CloseFD() { if (fd
!= -1) ::close(fd
); }
348 bool close() { return ::close(std::exchange(fd
, -1)) == 0; }
352 CloseFD in
= { ::open(from
, O_RDONLY
) };
355 ec
.assign(errno
, std::generic_category());
358 int oflag
= O_WRONLY
|O_CREAT
;
359 if (options
.overwrite
|| options
.update
)
363 CloseFD out
= { ::open(to
, oflag
, S_IWUSR
) };
366 if (errno
== EEXIST
&& options
.skip
)
369 ec
.assign(errno
, std::generic_category());
373 #ifdef _GLIBCXX_USE_FCHMOD
374 if (::fchmod(out
.fd
, from_st
->st_mode
))
375 #elif defined _GLIBCXX_USE_FCHMODAT
376 if (::fchmodat(AT_FDCWD
, to
, from_st
->st_mode
, 0))
378 if (::chmod(to
, from_st
->st_mode
))
381 ec
.assign(errno
, std::generic_category());
385 size_t count
= from_st
->st_size
;
386 #ifdef _GLIBCXX_USE_SENDFILE
388 ssize_t n
= ::sendfile(out
.fd
, in
.fd
, &offset
, count
);
389 if (n
< 0 && errno
!= ENOSYS
&& errno
!= EINVAL
)
391 ec
.assign(errno
, std::generic_category());
394 if ((size_t)n
== count
)
396 if (!out
.close() || !in
.close())
398 ec
.assign(errno
, std::generic_category());
406 #endif // _GLIBCXX_USE_SENDFILE
409 __gnu_cxx::stdio_filebuf
<char> sbin(in
.fd
, ios::in
|ios::binary
);
410 __gnu_cxx::stdio_filebuf
<char> sbout(out
.fd
, ios::out
|ios::binary
);
417 #ifdef _GLIBCXX_USE_SENDFILE
423 const auto p1
= sbin
.pubseekoff(n
, ios::beg
, ios::in
);
424 const auto p2
= sbout
.pubseekoff(n
, ios::beg
, ios::out
);
426 const std::streampos
errpos(std::streamoff(-1));
427 if (p1
== errpos
|| p2
== errpos
)
429 ec
= std::make_error_code(std::errc::io_error
);
435 if (count
&& !(std::ostream(&sbout
) << &sbin
))
437 ec
= std::make_error_code(std::errc::io_error
);
440 if (!sbout
.close() || !sbin
.close())
442 ec
.assign(errno
, std::generic_category());
448 #endif // NEED_DO_COPY_FILE
449 #endif // _GLIBCXX_HAVE_SYS_STAT_H
452 fs::copy(const path
& from
, const path
& to
, copy_options options
,
455 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
456 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
457 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
458 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
461 stat_type from_st
, to_st
;
462 // _GLIBCXX_RESOLVE_LIB_DEFECTS
463 // 2681. filesystem::copy() cannot copy symlinks
464 if (use_lstat
|| copy_symlinks
465 ? ::lstat(from
.c_str(), &from_st
)
466 : ::stat(from
.c_str(), &from_st
))
468 ec
.assign(errno
, std::generic_category());
472 ? ::lstat(to
.c_str(), &to_st
)
473 : ::stat(to
.c_str(), &to_st
))
475 if (!is_not_found_errno(errno
))
477 ec
.assign(errno
, std::generic_category());
480 t
= file_status
{file_type::not_found
};
483 t
= make_file_status(to_st
);
484 f
= make_file_status(from_st
);
486 if (exists(t
) && !is_other(t
) && !is_other(f
)
487 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
489 ec
= std::make_error_code(std::errc::file_exists
);
492 if (is_other(f
) || is_other(t
))
494 ec
= std::make_error_code(std::errc::not_supported
);
497 if (is_directory(f
) && is_regular_file(t
))
499 ec
= std::make_error_code(std::errc::is_a_directory
);
507 else if (!exists(t
) && copy_symlinks
)
508 copy_symlink(from
, to
, ec
);
510 // Not clear what should be done here.
511 // "Otherwise report an error as specified in Error reporting (7)."
512 ec
= std::make_error_code(std::errc::invalid_argument
);
514 else if (is_regular_file(f
))
516 if (is_set(options
, copy_options::directories_only
))
518 else if (create_symlinks
)
519 create_symlink(from
, to
, ec
);
520 else if (is_set(options
, copy_options::create_hard_links
))
521 create_hard_link(from
, to
, ec
);
522 else if (is_directory(t
))
523 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
524 copy_file_options(options
), &from_st
, nullptr, ec
);
527 auto ptr
= exists(t
) ? &to_st
: &from_st
;
528 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
532 // _GLIBCXX_RESOLVE_LIB_DEFECTS
533 // 2682. filesystem::copy() won't create a symlink to a directory
534 else if (is_directory(f
) && create_symlinks
)
535 ec
= std::make_error_code(errc::is_a_directory
);
536 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
537 || options
== copy_options::none
))
540 if (!create_directory(to
, from
, ec
))
542 // set an unused bit in options to disable further recursion
543 if (!is_set(options
, copy_options::recursive
))
544 options
|= static_cast<copy_options
>(4096);
545 for (const directory_entry
& x
: directory_iterator(from
))
546 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
548 // _GLIBCXX_RESOLVE_LIB_DEFECTS
549 // 2683. filesystem::copy() says "no effects"
555 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
558 bool result
= copy_file(from
, to
, option
, ec
);
560 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
566 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
569 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
570 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
571 nullptr, nullptr, ec
);
573 ec
= std::make_error_code(std::errc::not_supported
);
580 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
583 copy_symlink(existing_symlink
, new_symlink
, ec
);
585 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
586 existing_symlink
, new_symlink
, ec
));
590 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
591 error_code
& ec
) noexcept
593 auto p
= read_symlink(existing_symlink
, ec
);
596 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
599 create_directory_symlink(p
, new_symlink
, ec
);
603 create_symlink(p
, new_symlink
, ec
);
608 fs::create_directories(const path
& p
)
611 bool result
= create_directories(p
, ec
);
613 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
619 fs::create_directories(const path
& p
, error_code
& ec
)
623 ec
= std::make_error_code(errc::invalid_argument
);
626 std::stack
<path
> missing
;
629 while (pp
.has_filename() && status(pp
, ec
).type() == file_type::not_found
)
632 const auto& filename
= pp
.filename();
633 if (!is_dot(filename
) && !is_dotdot(filename
))
635 pp
= pp
.parent_path();
637 if (missing
.size() > 1000) // sanity check
639 ec
= std::make_error_code(std::errc::filename_too_long
);
644 if (ec
|| missing
.empty())
649 const path
& top
= missing
.top();
650 create_directory(top
, ec
);
651 if (ec
&& is_directory(top
))
655 while (!missing
.empty() && !ec
);
657 return missing
.empty();
663 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
665 bool created
= false;
666 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
667 ::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
668 if (::mkdir(p
.c_str(), mode
))
670 const int err
= errno
;
671 if (err
!= EEXIST
|| !is_directory(p
))
672 ec
.assign(err
, std::generic_category());
682 ec
= std::make_error_code(std::errc::not_supported
);
689 fs::create_directory(const path
& p
)
692 bool result
= create_directory(p
, ec
);
694 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
700 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
702 return create_dir(p
, perms::all
, ec
);
707 fs::create_directory(const path
& p
, const path
& attributes
)
710 bool result
= create_directory(p
, attributes
, ec
);
712 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
718 fs::create_directory(const path
& p
, const path
& attributes
,
719 error_code
& ec
) noexcept
721 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
723 if (::stat(attributes
.c_str(), &st
))
725 ec
.assign(errno
, std::generic_category());
728 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
730 ec
= std::make_error_code(std::errc::not_supported
);
737 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
740 create_directory_symlink(to
, new_symlink
, ec
);
742 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
743 to
, new_symlink
, ec
));
747 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
748 error_code
& ec
) noexcept
750 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
751 ec
= std::make_error_code(std::errc::not_supported
);
753 create_symlink(to
, new_symlink
, ec
);
759 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
762 create_hard_link(to
, new_hard_link
, ec
);
764 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
765 to
, new_hard_link
, ec
));
769 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
770 error_code
& ec
) noexcept
772 #ifdef _GLIBCXX_HAVE_UNISTD_H
773 if (::link(to
.c_str(), new_hard_link
.c_str()))
774 ec
.assign(errno
, std::generic_category());
778 ec
= std::make_error_code(std::errc::not_supported
);
783 fs::create_symlink(const path
& to
, const path
& new_symlink
)
786 create_symlink(to
, new_symlink
, ec
);
788 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
789 to
, new_symlink
, ec
));
793 fs::create_symlink(const path
& to
, const path
& new_symlink
,
794 error_code
& ec
) noexcept
796 #ifdef _GLIBCXX_HAVE_UNISTD_H
797 if (::symlink(to
.c_str(), new_symlink
.c_str()))
798 ec
.assign(errno
, std::generic_category());
802 ec
= std::make_error_code(std::errc::not_supported
);
811 path p
= current_path(ec
);
813 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
818 fs::current_path(error_code
& ec
)
821 #ifdef _GLIBCXX_HAVE_UNISTD_H
823 if (char_ptr cwd
= char_ptr
{::getcwd(nullptr, 0)})
829 ec
.assign(errno
, std::generic_category());
831 long path_max
= pathconf(".", _PC_PATH_MAX
);
835 else if (path_max
> 10240)
839 for (char_ptr buf
; p
.empty(); size
*= 2)
841 buf
.reset((char*)malloc(size
));
844 if (getcwd(buf
.get(), size
))
849 else if (errno
!= ERANGE
)
851 ec
.assign(errno
, std::generic_category());
857 ec
= std::make_error_code(std::errc::not_enough_memory
);
862 #else // _GLIBCXX_HAVE_UNISTD_H
863 ec
= std::make_error_code(std::errc::not_supported
);
869 fs::current_path(const path
& p
)
874 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
878 fs::current_path(const path
& p
, error_code
& ec
) noexcept
880 #ifdef _GLIBCXX_HAVE_UNISTD_H
881 if (::chdir(p
.c_str()))
882 ec
.assign(errno
, std::generic_category());
886 ec
= std::make_error_code(std::errc::not_supported
);
891 fs::equivalent(const path
& p1
, const path
& p2
)
894 auto result
= equivalent(p1
, p2
, ec
);
896 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
902 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
904 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
908 if (::stat(p1
.c_str(), &st1
) == 0)
909 s1
= make_file_status(st1
);
910 else if (is_not_found_errno(errno
))
911 s1
.type(file_type::not_found
);
915 if (::stat(p2
.c_str(), &st2
) == 0)
916 s2
= make_file_status(st2
);
917 else if (is_not_found_errno(errno
))
918 s2
.type(file_type::not_found
);
922 if (exists(s1
) && exists(s2
))
924 if (is_other(s1
) && is_other(s2
))
926 ec
= std::make_error_code(std::errc::not_supported
);
930 if (is_other(s1
) || is_other(s2
))
932 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
934 else if (!exists(s1
) && !exists(s2
))
935 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
937 ec
.assign(err
, std::generic_category());
942 ec
= std::make_error_code(std::errc::not_supported
);
948 fs::file_size(const path
& p
)
951 auto sz
= file_size(p
, ec
);
953 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
959 template<typename Accessor
, typename T
>
961 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
963 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
965 if (::stat(p
.c_str(), &st
))
967 ec
.assign(errno
, std::generic_category());
973 ec
= std::make_error_code(std::errc::not_supported
);
980 fs::file_size(const path
& p
, error_code
& ec
) noexcept
984 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
985 S() : type(file_type::not_found
) { }
989 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
990 if (s
.type
== file_type::regular
)
994 if (s
.type
== file_type::directory
)
995 ec
= std::make_error_code(std::errc::is_a_directory
);
997 ec
= std::make_error_code(std::errc::not_supported
);
1003 fs::hard_link_count(const path
& p
)
1006 auto count
= hard_link_count(p
, ec
);
1008 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
1013 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
1015 return do_stat(p
, ec
, std::mem_fn(&stat::st_nlink
),
1016 static_cast<uintmax_t>(-1));
1020 fs::is_empty(const path
& p
)
1023 bool e
= is_empty(p
, ec
);
1025 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1031 fs::is_empty(const path
& p
, error_code
& ec
)
1033 auto s
= status(p
, ec
);
1036 bool empty
= fs::is_directory(s
)
1037 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1038 : fs::file_size(p
, ec
) == 0;
1039 return ec
? false : empty
;
1043 fs::last_write_time(const path
& p
)
1046 auto t
= last_write_time(p
, ec
);
1048 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1053 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1055 return do_stat(p
, ec
, [&ec
](const auto& st
) { return file_time(st
, ec
); },
1056 file_time_type::min());
1060 fs::last_write_time(const path
& p
, file_time_type new_time
)
1063 last_write_time(p
, new_time
, ec
);
1065 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1069 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
1070 file_time_type new_time
, error_code
& ec
) noexcept
1072 auto d
= new_time
.time_since_epoch();
1073 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1074 #if _GLIBCXX_USE_UTIMENSAT
1075 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1076 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
1079 ns
+= chrono::seconds(1);
1081 struct ::timespec ts
[2];
1083 ts
[0].tv_nsec
= UTIME_OMIT
;
1084 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1085 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1086 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1087 ec
.assign(errno
, std::generic_category());
1090 #elif _GLIBCXX_HAVE_UTIME_H
1092 times
.modtime
= s
.count();
1093 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1095 if (::utime(p
.c_str(), ×
))
1096 ec
.assign(errno
, std::generic_category());
1100 ec
= std::make_error_code(std::errc::not_supported
);
1105 fs::permissions(const path
& p
, perms prms
, perm_options opts
)
1108 permissions(p
, prms
, opts
, ec
);
1110 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1114 fs::permissions(const path
& p
, perms prms
, perm_options opts
,
1115 error_code
& ec
) noexcept
1117 const bool replace
= is_set(opts
, perm_options::replace
);
1118 const bool add
= is_set(opts
, perm_options::add
);
1119 const bool remove
= is_set(opts
, perm_options::remove
);
1120 const bool nofollow
= is_set(opts
, perm_options::nofollow
);
1121 if (((int)replace
+ (int)add
+ (int)remove
) != 1)
1123 ec
= std::make_error_code(std::errc::invalid_argument
);
1127 prms
&= perms::mask
;
1130 if (add
|| remove
|| nofollow
)
1132 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
1135 auto curr
= st
.permissions();
1139 prms
= curr
& ~prms
;
1143 #if _GLIBCXX_USE_FCHMODAT
1144 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
1145 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
1148 if (nofollow
&& is_symlink(st
))
1149 ec
= std::make_error_code(std::errc::operation_not_supported
);
1150 else if (::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
1155 ec
.assign(err
, std::generic_category());
1161 fs::proximate(const path
& p
, const path
& base
)
1163 return weakly_canonical(p
).lexically_proximate(weakly_canonical(base
));
1167 fs::proximate(const path
& p
, const path
& base
, error_code
& ec
)
1170 const auto p2
= weakly_canonical(p
, ec
);
1173 const auto base2
= weakly_canonical(base
, ec
);
1175 result
= p2
.lexically_proximate(base2
);
1181 fs::read_symlink(const path
& p
)
1184 path tgt
= read_symlink(p
, ec
);
1186 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1190 fs::path
fs::read_symlink(const path
& p
, error_code
& ec
)
1193 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1195 if (::lstat(p
.c_str(), &st
))
1197 ec
.assign(errno
, std::generic_category());
1200 std::string
buf(st
.st_size
? st
.st_size
+ 1 : 128, '\0');
1203 ssize_t len
= ::readlink(p
.c_str(), buf
.data(), buf
.size());
1206 ec
.assign(errno
, std::generic_category());
1209 else if (len
== (ssize_t
)buf
.size())
1211 if (buf
.size() > 4096)
1213 ec
.assign(ENAMETOOLONG
, std::generic_category());
1216 buf
.resize(buf
.size() * 2);
1228 ec
= std::make_error_code(std::errc::not_supported
);
1234 fs::relative(const path
& p
, const path
& base
)
1236 return weakly_canonical(p
).lexically_relative(weakly_canonical(base
));
1240 fs::relative(const path
& p
, const path
& base
, error_code
& ec
)
1242 auto result
= weakly_canonical(p
, ec
);
1245 cbase
= weakly_canonical(base
, ec
);
1247 result
= result
.lexically_relative(cbase
);
1254 fs::remove(const path
& p
)
1257 const bool result
= fs::remove(p
, ec
);
1259 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1264 fs::remove(const path
& p
, error_code
& ec
) noexcept
1266 if (::remove(p
.c_str()) == 0)
1271 else if (errno
== ENOENT
)
1274 ec
.assign(errno
, std::generic_category());
1280 fs::remove_all(const path
& p
)
1283 const auto result
= remove_all(p
, ec
);
1285 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1290 fs::remove_all(const path
& p
, error_code
& ec
)
1292 const auto s
= symlink_status(p
, ec
);
1293 if (!status_known(s
))
1297 if (s
.type() == file_type::not_found
)
1300 uintmax_t count
= 0;
1301 if (s
.type() == file_type::directory
)
1303 for (directory_iterator
d(p
, ec
), end
; !ec
&& d
!= end
; d
.increment(ec
))
1304 count
+= fs::remove_all(d
->path(), ec
);
1305 if (ec
.value() == ENOENT
)
1311 if (fs::remove(p
, ec
))
1313 return ec
? -1 : count
;
1317 fs::rename(const path
& from
, const path
& to
)
1320 rename(from
, to
, ec
);
1322 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1326 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1328 if (::rename(from
.c_str(), to
.c_str()))
1329 ec
.assign(errno
, std::generic_category());
1335 fs::resize_file(const path
& p
, uintmax_t size
)
1338 resize_file(p
, size
, ec
);
1340 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1344 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1346 #ifdef _GLIBCXX_HAVE_UNISTD_H
1347 if (size
> static_cast<uintmax_t>(std::numeric_limits
<off_t
>::max()))
1348 ec
.assign(EINVAL
, std::generic_category());
1349 else if (::truncate(p
.c_str(), size
))
1350 ec
.assign(errno
, std::generic_category());
1354 ec
= std::make_error_code(std::errc::not_supported
);
1360 fs::space(const path
& p
)
1363 space_info s
= space(p
, ec
);
1365 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1370 fs::space(const path
& p
, error_code
& ec
) noexcept
1373 static_cast<uintmax_t>(-1),
1374 static_cast<uintmax_t>(-1),
1375 static_cast<uintmax_t>(-1)
1377 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1379 if (::statvfs(p
.c_str(), &f
))
1380 ec
.assign(errno
, std::generic_category());
1384 f
.f_blocks
* f
.f_frsize
,
1385 f
.f_bfree
* f
.f_frsize
,
1386 f
.f_bavail
* f
.f_frsize
1391 ec
= std::make_error_code(std::errc::not_supported
);
1396 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1398 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1402 if (::stat(p
.c_str(), &st
))
1405 ec
.assign(err
, std::generic_category());
1406 if (is_not_found_errno(err
))
1407 status
.type(file_type::not_found
);
1409 else if (err
== EOVERFLOW
)
1410 status
.type(file_type::unknown
);
1415 status
= make_file_status(st
);
1422 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1426 if (::lstat(p
.c_str(), &st
))
1429 ec
.assign(err
, std::generic_category());
1430 if (is_not_found_errno(err
))
1431 status
.type(file_type::not_found
);
1435 status
= make_file_status(st
);
1443 fs::status(const fs::path
& p
)
1446 auto result
= status(p
, ec
);
1447 if (result
.type() == file_type::none
)
1448 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1453 fs::symlink_status(const fs::path
& p
)
1456 auto result
= symlink_status(p
, ec
);
1457 if (result
.type() == file_type::none
)
1458 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1462 fs::path
fs::temp_directory_path()
1465 path tmp
= temp_directory_path(ec
);
1467 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1471 fs::path
fs::temp_directory_path(error_code
& ec
)
1473 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1474 ec
= std::make_error_code(std::errc::not_supported
);
1477 const char* tmpdir
= nullptr;
1478 const char* env
[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1479 for (auto e
= env
; tmpdir
== nullptr && *e
!= nullptr; ++e
)
1480 tmpdir
= ::getenv(*e
);
1481 path p
= tmpdir
? tmpdir
: "/tmp";
1482 auto st
= status(p
, ec
);
1485 if (is_directory(st
))
1491 ec
= std::make_error_code(std::errc::not_a_directory
);
1498 fs::weakly_canonical(const path
& p
)
1501 if (exists(status(p
)))
1502 return canonical(p
);
1505 auto iter
= p
.begin(), end
= p
.end();
1506 // find leading elements of p that exist:
1509 tmp
= result
/ *iter
;
1510 if (exists(status(tmp
)))
1517 result
= canonical(result
);
1518 // append the non-existing elements:
1522 return result
.lexically_normal();
1526 fs::weakly_canonical(const path
& p
, error_code
& ec
)
1529 file_status st
= status(p
, ec
);
1531 return canonical(p
, ec
);
1532 else if (status_known(st
))
1538 auto iter
= p
.begin(), end
= p
.end();
1539 // find leading elements of p that exist:
1542 tmp
= result
/ *iter
;
1543 st
= status(tmp
, ec
);
1548 if (status_known(st
))
1556 result
= canonical(result
, ec
);
1561 // append the non-existing elements:
1565 result
= result
.lexically_normal();