1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2019 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
28 # define NEED_DO_SPACE
32 #include <experimental/filesystem>
36 #include <ext/stdio_filebuf.h>
40 #include <limits.h> // PATH_MAX
41 #ifdef _GLIBCXX_HAVE_FCNTL_H
42 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
44 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
45 # include <sys/stat.h> // stat, utimensat, fchmodat
47 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
48 # include <sys/statvfs.h> // statvfs
50 #ifdef _GLIBCXX_USE_SENDFILE
51 # include <sys/sendfile.h> // sendfile
53 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
54 # include <utime.h> // utime
56 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
60 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
61 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
62 #include "ops-common.h"
64 namespace fs
= std::filesystem
;
65 namespace posix
= std::filesystem::__gnu_posix
;
68 fs::absolute(const path
& p
)
70 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
72 path ret
= absolute(p
, ec
);
74 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p
,
78 return current_path() / p
;
83 fs::absolute(const path
& p
, error_code
& ec
)
88 ec
= make_error_code(std::errc::no_such_file_or_directory
);
91 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
92 const wstring
& s
= p
.native();
98 len
= GetFullPathNameW(s
.c_str(), len
, buf
.data(), nullptr);
100 while (len
> buf
.size());
103 ec
.assign((int)GetLastError(), std::system_category());
108 ret
= std::move(buf
);
112 ret
= current_path();
120 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
121 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
123 inline bool is_dot(char c
) { return c
== '.'; }
126 inline bool is_dot(const fs::path
& path
)
128 const auto& filename
= path
.native();
129 return filename
.size() == 1 && is_dot(filename
[0]);
132 inline bool is_dotdot(const fs::path
& path
)
134 const auto& filename
= path
.native();
135 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
138 struct free_as_in_malloc
140 void operator()(void* p
) const { ::free(p
); }
143 using char_ptr
= std::unique_ptr
<fs::path::value_type
[], free_as_in_malloc
>;
147 fs::canonical(const path
& p
, error_code
& ec
)
150 const path pa
= absolute(p
, ec
);
154 #ifdef _GLIBCXX_USE_REALPATH
155 char_ptr buf
{ nullptr };
156 # if _XOPEN_VERSION < 700
157 // Not safe to call realpath(path, NULL)
158 using char_type
= fs::path::value_type
;
159 buf
.reset( (char_type
*)::malloc(PATH_MAX
* sizeof(char_type
)) );
161 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
169 if (errno
!= ENAMETOOLONG
)
171 ec
.assign(errno
, std::generic_category());
179 ec
= make_error_code(std::errc::no_such_file_or_directory
);
182 // else: we know there are (currently) no unresolvable symlink loops
184 result
= pa
.root_path();
187 for (auto& f
: pa
.relative_path())
190 int max_allowed_symlinks
= 40;
192 while (!cmpts
.empty() && !ec
)
194 path f
= std::move(cmpts
.front());
199 // ignore empty element
203 if (!is_directory(result
, ec
) && !ec
)
204 ec
.assign(ENOTDIR
, std::generic_category());
206 else if (is_dotdot(f
))
208 auto parent
= result
.parent_path();
210 result
= pa
.root_path();
218 if (is_symlink(result
, ec
))
220 path link
= read_symlink(result
, ec
);
223 if (--max_allowed_symlinks
== 0)
224 ec
.assign(ELOOP
, std::generic_category());
227 if (link
.is_absolute())
229 result
= link
.root_path();
230 link
= link
.relative_path();
233 result
= result
.parent_path();
235 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
242 if (ec
|| !exists(result
, ec
))
249 fs::canonical(const path
& p
)
252 path res
= canonical(p
, ec
);
254 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
260 fs::copy(const path
& from
, const path
& to
, copy_options options
)
263 copy(from
, to
, options
, ec
);
265 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
268 namespace std::filesystem
270 // Need this as there's no 'perm_options::none' enumerator.
271 inline bool is_set(fs::perm_options obj
, fs::perm_options bits
)
273 return (obj
& bits
) != fs::perm_options
{};
277 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
278 #ifdef NEED_DO_COPY_FILE
280 fs::do_copy_file(const path::value_type
* from
, const path::value_type
* to
,
281 copy_options_existing_file options
,
282 stat_type
* from_st
, stat_type
* to_st
,
283 std::error_code
& ec
) noexcept
286 fs::file_status t
, f
;
288 if (to_st
== nullptr)
290 if (posix::stat(to
, &st1
))
292 const int err
= errno
;
293 if (!is_not_found_errno(err
))
295 ec
.assign(err
, std::generic_category());
302 else if (to_st
== from_st
)
305 if (to_st
== nullptr)
306 t
= fs::file_status
{fs::file_type::not_found
};
308 t
= make_file_status(*to_st
);
310 if (from_st
== nullptr)
312 if (posix::stat(from
, &st2
))
314 ec
.assign(errno
, std::generic_category());
320 f
= make_file_status(*from_st
);
321 // _GLIBCXX_RESOLVE_LIB_DEFECTS
322 // 2712. copy_file() has a number of unspecified error conditions
323 if (!is_regular_file(f
))
325 ec
= std::make_error_code(std::errc::not_supported
);
331 if (!is_regular_file(t
))
333 ec
= std::make_error_code(std::errc::not_supported
);
337 if (to_st
->st_dev
== from_st
->st_dev
338 && to_st
->st_ino
== from_st
->st_ino
)
340 ec
= std::make_error_code(std::errc::file_exists
);
349 else if (options
.update
)
351 const auto from_mtime
= file_time(*from_st
, ec
);
354 if ((from_mtime
<= file_time(*to_st
, ec
)) || ec
)
357 else if (!options
.overwrite
)
359 ec
= std::make_error_code(std::errc::file_exists
);
362 else if (!is_regular_file(t
))
364 ec
= std::make_error_code(std::errc::not_supported
);
370 ~CloseFD() { if (fd
!= -1) posix::close(fd
); }
371 bool close() { return posix::close(std::exchange(fd
, -1)) == 0; }
375 CloseFD in
= { posix::open(from
, O_RDONLY
) };
378 ec
.assign(errno
, std::generic_category());
381 int oflag
= O_WRONLY
|O_CREAT
;
382 if (options
.overwrite
|| options
.update
)
386 CloseFD out
= { posix::open(to
, oflag
, S_IWUSR
) };
389 if (errno
== EEXIST
&& options
.skip
)
392 ec
.assign(errno
, std::generic_category());
396 #if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
397 if (::fchmod(out
.fd
, from_st
->st_mode
))
398 #elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
399 if (::fchmodat(AT_FDCWD
, to
, from_st
->st_mode
, 0))
401 if (posix::chmod(to
, from_st
->st_mode
))
404 ec
.assign(errno
, std::generic_category());
408 size_t count
= from_st
->st_size
;
409 #if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
411 ssize_t n
= ::sendfile(out
.fd
, in
.fd
, &offset
, count
);
412 if (n
< 0 && errno
!= ENOSYS
&& errno
!= EINVAL
)
414 ec
.assign(errno
, std::generic_category());
417 if ((size_t)n
== count
)
419 if (!out
.close() || !in
.close())
421 ec
.assign(errno
, std::generic_category());
429 #endif // _GLIBCXX_USE_SENDFILE
432 __gnu_cxx::stdio_filebuf
<char> sbin(in
.fd
, ios::in
|ios::binary
);
433 __gnu_cxx::stdio_filebuf
<char> sbout(out
.fd
, ios::out
|ios::binary
);
440 #ifdef _GLIBCXX_USE_SENDFILE
446 const auto p1
= sbin
.pubseekoff(n
, ios::beg
, ios::in
);
447 const auto p2
= sbout
.pubseekoff(n
, ios::beg
, ios::out
);
449 const std::streampos
errpos(std::streamoff(-1));
450 if (p1
== errpos
|| p2
== errpos
)
452 ec
= std::make_error_code(std::errc::io_error
);
458 if (count
&& !(std::ostream(&sbout
) << &sbin
))
460 ec
= std::make_error_code(std::errc::io_error
);
463 if (!sbout
.close() || !sbin
.close())
465 ec
.assign(errno
, std::generic_category());
471 #endif // NEED_DO_COPY_FILE
472 #endif // _GLIBCXX_HAVE_SYS_STAT_H
475 fs::copy(const path
& from
, const path
& to
, copy_options options
,
478 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
479 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
480 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
481 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
484 stat_type from_st
, to_st
;
485 // _GLIBCXX_RESOLVE_LIB_DEFECTS
486 // 2681. filesystem::copy() cannot copy symlinks
487 if (use_lstat
|| copy_symlinks
488 ? posix::lstat(from
.c_str(), &from_st
)
489 : posix::stat(from
.c_str(), &from_st
))
491 ec
.assign(errno
, std::generic_category());
495 ? posix::lstat(to
.c_str(), &to_st
)
496 : posix::stat(to
.c_str(), &to_st
))
498 if (!is_not_found_errno(errno
))
500 ec
.assign(errno
, std::generic_category());
503 t
= file_status
{file_type::not_found
};
506 t
= make_file_status(to_st
);
507 f
= make_file_status(from_st
);
509 if (exists(t
) && !is_other(t
) && !is_other(f
)
510 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
512 ec
= std::make_error_code(std::errc::file_exists
);
515 if (is_other(f
) || is_other(t
))
517 ec
= std::make_error_code(std::errc::not_supported
);
520 if (is_directory(f
) && is_regular_file(t
))
522 ec
= std::make_error_code(std::errc::is_a_directory
);
530 else if (!exists(t
) && copy_symlinks
)
531 copy_symlink(from
, to
, ec
);
533 // Not clear what should be done here.
534 // "Otherwise report an error as specified in Error reporting (7)."
535 ec
= std::make_error_code(std::errc::invalid_argument
);
537 else if (is_regular_file(f
))
539 if (is_set(options
, copy_options::directories_only
))
541 else if (create_symlinks
)
542 create_symlink(from
, to
, ec
);
543 else if (is_set(options
, copy_options::create_hard_links
))
544 create_hard_link(from
, to
, ec
);
545 else if (is_directory(t
))
546 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
547 copy_file_options(options
), &from_st
, nullptr, ec
);
550 auto ptr
= exists(t
) ? &to_st
: &from_st
;
551 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
555 // _GLIBCXX_RESOLVE_LIB_DEFECTS
556 // 2682. filesystem::copy() won't create a symlink to a directory
557 else if (is_directory(f
) && create_symlinks
)
558 ec
= std::make_error_code(errc::is_a_directory
);
559 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
560 || options
== copy_options::none
))
563 if (!create_directory(to
, from
, ec
))
565 // set an unused bit in options to disable further recursion
566 if (!is_set(options
, copy_options::recursive
))
567 options
|= static_cast<copy_options
>(4096);
568 for (const directory_entry
& x
: directory_iterator(from
))
569 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
571 // _GLIBCXX_RESOLVE_LIB_DEFECTS
572 // 2683. filesystem::copy() says "no effects"
578 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
581 bool result
= copy_file(from
, to
, option
, ec
);
583 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
589 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
592 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
593 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
594 nullptr, nullptr, ec
);
596 ec
= std::make_error_code(std::errc::not_supported
);
603 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
606 copy_symlink(existing_symlink
, new_symlink
, ec
);
608 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
609 existing_symlink
, new_symlink
, ec
));
613 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
614 error_code
& ec
) noexcept
616 auto p
= read_symlink(existing_symlink
, ec
);
619 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
622 create_directory_symlink(p
, new_symlink
, ec
);
626 create_symlink(p
, new_symlink
, ec
);
631 fs::create_directories(const path
& p
)
634 bool result
= create_directories(p
, ec
);
636 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
642 fs::create_directories(const path
& p
, error_code
& ec
)
646 ec
= std::make_error_code(errc::invalid_argument
);
650 file_status st
= symlink_status(p
, ec
);
651 if (is_directory(st
))
653 else if (ec
&& !status_known(st
))
658 ec
= std::make_error_code(std::errc::not_a_directory
);
662 std::stack
<path
> missing
;
665 // Strip any trailing slash
666 if (pp
.has_relative_path() && !pp
.has_filename())
667 pp
= pp
.parent_path();
671 const auto& filename
= pp
.filename();
672 if (is_dot(filename
) || is_dotdot(filename
))
673 pp
= pp
.parent_path();
676 missing
.push(std::move(pp
));
677 if (missing
.size() > 1000) // sanity check
679 ec
= std::make_error_code(std::errc::filename_too_long
);
682 pp
= missing
.top().parent_path();
693 if (!is_directory(st
))
695 ec
= std::make_error_code(std::errc::not_a_directory
);
700 if (ec
&& exists(st
))
703 while (st
.type() == file_type::not_found
);
708 const path
& top
= missing
.top();
709 created
= create_directory(top
, ec
);
714 while (!missing
.empty());
722 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
724 bool created
= false;
725 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
727 = static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
728 if (posix::mkdir(p
.c_str(), mode
))
730 const int err
= errno
;
731 if (err
!= EEXIST
|| !is_directory(p
, ec
))
732 ec
.assign(err
, std::generic_category());
740 ec
= std::make_error_code(std::errc::not_supported
);
747 fs::create_directory(const path
& p
)
750 bool result
= create_directory(p
, ec
);
752 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
758 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
760 return create_dir(p
, perms::all
, ec
);
765 fs::create_directory(const path
& p
, const path
& attributes
)
768 bool result
= create_directory(p
, attributes
, ec
);
770 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
776 fs::create_directory(const path
& p
, const path
& attributes
,
777 error_code
& ec
) noexcept
779 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
781 if (posix::stat(attributes
.c_str(), &st
))
783 ec
.assign(errno
, std::generic_category());
786 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
788 ec
= std::make_error_code(std::errc::not_supported
);
795 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
798 create_directory_symlink(to
, new_symlink
, ec
);
800 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
801 to
, new_symlink
, ec
));
805 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
806 error_code
& ec
) noexcept
808 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
809 ec
= std::make_error_code(std::errc::not_supported
);
811 create_symlink(to
, new_symlink
, ec
);
817 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
820 create_hard_link(to
, new_hard_link
, ec
);
822 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
823 to
, new_hard_link
, ec
));
827 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
828 error_code
& ec
) noexcept
830 #ifdef _GLIBCXX_HAVE_LINK
831 if (::link(to
.c_str(), new_hard_link
.c_str()))
832 ec
.assign(errno
, std::generic_category());
835 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
836 if (CreateHardLinkW(new_hard_link
.c_str(), to
.c_str(), NULL
))
839 ec
.assign((int)GetLastError(), generic_category());
841 ec
= std::make_error_code(std::errc::not_supported
);
846 fs::create_symlink(const path
& to
, const path
& new_symlink
)
849 create_symlink(to
, new_symlink
, ec
);
851 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
852 to
, new_symlink
, ec
));
856 fs::create_symlink(const path
& to
, const path
& new_symlink
,
857 error_code
& ec
) noexcept
859 #ifdef _GLIBCXX_HAVE_SYMLINK
860 if (::symlink(to
.c_str(), new_symlink
.c_str()))
861 ec
.assign(errno
, std::generic_category());
865 ec
= std::make_error_code(std::errc::not_supported
);
874 path p
= current_path(ec
);
876 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
881 fs::current_path(error_code
& ec
)
884 #ifdef _GLIBCXX_HAVE_UNISTD_H
885 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
886 if (char_ptr cwd
= char_ptr
{posix::getcwd(nullptr, 0)})
892 ec
.assign(errno
, std::generic_category());
895 long path_max
= pathconf(".", _PC_PATH_MAX
);
899 else if (path_max
> 10240)
903 #elif defined(PATH_MAX)
904 size_t size
= PATH_MAX
;
908 for (char_ptr buf
; p
.empty(); size
*= 2)
910 using char_type
= fs::path::value_type
;
911 buf
.reset((char_type
*)malloc(size
* sizeof(char_type
)));
914 if (getcwd(buf
.get(), size
))
919 else if (errno
!= ERANGE
)
921 ec
.assign(errno
, std::generic_category());
927 ec
= std::make_error_code(std::errc::not_enough_memory
);
932 #else // _GLIBCXX_HAVE_UNISTD_H
933 ec
= std::make_error_code(std::errc::not_supported
);
939 fs::current_path(const path
& p
)
944 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
948 fs::current_path(const path
& p
, error_code
& ec
) noexcept
950 #ifdef _GLIBCXX_HAVE_UNISTD_H
951 if (posix::chdir(p
.c_str()))
952 ec
.assign(errno
, std::generic_category());
956 ec
= std::make_error_code(std::errc::not_supported
);
961 fs::equivalent(const path
& p1
, const path
& p2
)
964 auto result
= equivalent(p1
, p2
, ec
);
966 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
972 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
974 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
978 if (posix::stat(p1
.c_str(), &st1
) == 0)
979 s1
= make_file_status(st1
);
980 else if (is_not_found_errno(errno
))
981 s1
.type(file_type::not_found
);
985 if (posix::stat(p2
.c_str(), &st2
) == 0)
986 s2
= make_file_status(st2
);
987 else if (is_not_found_errno(errno
))
988 s2
.type(file_type::not_found
);
992 if (exists(s1
) && exists(s2
))
994 if (is_other(s1
) && is_other(s2
))
996 ec
= std::make_error_code(std::errc::not_supported
);
1000 if (is_other(s1
) || is_other(s2
))
1002 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
1004 else if (!exists(s1
) && !exists(s2
))
1005 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
1007 ec
.assign(err
, std::generic_category());
1012 ec
= std::make_error_code(std::errc::not_supported
);
1018 fs::file_size(const path
& p
)
1021 auto sz
= file_size(p
, ec
);
1023 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
1029 template<typename Accessor
, typename T
>
1031 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
1033 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1034 posix::stat_type st
;
1035 if (posix::stat(p
.c_str(), &st
))
1037 ec
.assign(errno
, std::generic_category());
1043 ec
= std::make_error_code(std::errc::not_supported
);
1050 fs::file_size(const path
& p
, error_code
& ec
) noexcept
1054 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
1055 S() : type(file_type::not_found
) { }
1059 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
1060 if (s
.type
== file_type::regular
)
1064 if (s
.type
== file_type::directory
)
1065 ec
= std::make_error_code(std::errc::is_a_directory
);
1067 ec
= std::make_error_code(std::errc::not_supported
);
1073 fs::hard_link_count(const path
& p
)
1076 auto count
= hard_link_count(p
, ec
);
1078 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
1083 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
1085 return do_stat(p
, ec
, std::mem_fn(&stat_type::st_nlink
),
1086 static_cast<uintmax_t>(-1));
1090 fs::is_empty(const path
& p
)
1093 bool e
= is_empty(p
, ec
);
1095 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1101 fs::is_empty(const path
& p
, error_code
& ec
)
1103 auto s
= status(p
, ec
);
1106 bool empty
= fs::is_directory(s
)
1107 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1108 : fs::file_size(p
, ec
) == 0;
1109 return ec
? false : empty
;
1113 fs::last_write_time(const path
& p
)
1116 auto t
= last_write_time(p
, ec
);
1118 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1123 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1125 return do_stat(p
, ec
, [&ec
](const auto& st
) { return file_time(st
, ec
); },
1126 file_time_type::min());
1130 fs::last_write_time(const path
& p
, file_time_type new_time
)
1133 last_write_time(p
, new_time
, ec
);
1135 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1139 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
1140 file_time_type new_time
, error_code
& ec
) noexcept
1142 auto d
= new_time
.time_since_epoch();
1143 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1144 #if _GLIBCXX_USE_UTIMENSAT
1145 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1146 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
1149 ns
+= chrono::seconds(1);
1151 struct ::timespec ts
[2];
1153 ts
[0].tv_nsec
= UTIME_OMIT
;
1154 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1155 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1156 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1157 ec
.assign(errno
, std::generic_category());
1160 #elif _GLIBCXX_HAVE_UTIME_H
1161 posix::utimbuf times
;
1162 times
.modtime
= s
.count();
1163 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1165 if (posix::utime(p
.c_str(), ×
))
1166 ec
.assign(errno
, std::generic_category());
1170 ec
= std::make_error_code(std::errc::not_supported
);
1175 fs::permissions(const path
& p
, perms prms
, perm_options opts
)
1178 permissions(p
, prms
, opts
, ec
);
1180 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1184 fs::permissions(const path
& p
, perms prms
, perm_options opts
,
1185 error_code
& ec
) noexcept
1187 const bool replace
= is_set(opts
, perm_options::replace
);
1188 const bool add
= is_set(opts
, perm_options::add
);
1189 const bool remove
= is_set(opts
, perm_options::remove
);
1190 const bool nofollow
= is_set(opts
, perm_options::nofollow
);
1191 if (((int)replace
+ (int)add
+ (int)remove
) != 1)
1193 ec
= std::make_error_code(std::errc::invalid_argument
);
1197 prms
&= perms::mask
;
1200 if (add
|| remove
|| nofollow
)
1202 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
1205 auto curr
= st
.permissions();
1209 prms
= curr
& ~prms
;
1213 #if _GLIBCXX_USE_FCHMODAT
1214 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
1215 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
1218 if (nofollow
&& is_symlink(st
))
1219 ec
= std::make_error_code(std::errc::operation_not_supported
);
1220 else if (posix::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
1225 ec
.assign(err
, std::generic_category());
1231 fs::proximate(const path
& p
, const path
& base
)
1233 return weakly_canonical(p
).lexically_proximate(weakly_canonical(base
));
1237 fs::proximate(const path
& p
, const path
& base
, error_code
& ec
)
1240 const auto p2
= weakly_canonical(p
, ec
);
1243 const auto base2
= weakly_canonical(base
, ec
);
1245 result
= p2
.lexically_proximate(base2
);
1251 fs::read_symlink(const path
& p
)
1254 path tgt
= read_symlink(p
, ec
);
1256 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1260 fs::path
fs::read_symlink(const path
& p
[[gnu::unused
]], error_code
& ec
)
1263 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1265 if (::lstat(p
.c_str(), &st
))
1267 ec
.assign(errno
, std::generic_category());
1270 std::string
buf(st
.st_size
? st
.st_size
+ 1 : 128, '\0');
1273 ssize_t len
= ::readlink(p
.c_str(), buf
.data(), buf
.size());
1276 ec
.assign(errno
, std::generic_category());
1279 else if (len
== (ssize_t
)buf
.size())
1281 if (buf
.size() > 4096)
1283 ec
.assign(ENAMETOOLONG
, std::generic_category());
1286 buf
.resize(buf
.size() * 2);
1298 ec
= std::make_error_code(std::errc::not_supported
);
1304 fs::relative(const path
& p
, const path
& base
)
1306 return weakly_canonical(p
).lexically_relative(weakly_canonical(base
));
1310 fs::relative(const path
& p
, const path
& base
, error_code
& ec
)
1312 auto result
= weakly_canonical(p
, ec
);
1315 cbase
= weakly_canonical(base
, ec
);
1317 result
= result
.lexically_relative(cbase
);
1324 fs::remove(const path
& p
)
1327 const bool result
= fs::remove(p
, ec
);
1329 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1334 fs::remove(const path
& p
, error_code
& ec
) noexcept
1336 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1337 if (exists(symlink_status(p
, ec
)))
1339 if ((is_directory(p
, ec
) && RemoveDirectoryW(p
.c_str()))
1340 || DeleteFileW(p
.c_str()))
1346 ec
.assign((int)GetLastError(), generic_category());
1349 if (::remove(p
.c_str()) == 0)
1354 else if (errno
== ENOENT
)
1357 ec
.assign(errno
, std::generic_category());
1364 fs::remove_all(const path
& p
)
1367 const auto result
= remove_all(p
, ec
);
1369 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1374 fs::remove_all(const path
& p
, error_code
& ec
)
1376 const auto s
= symlink_status(p
, ec
);
1377 if (!status_known(s
))
1381 if (s
.type() == file_type::not_found
)
1384 uintmax_t count
= 0;
1385 if (s
.type() == file_type::directory
)
1387 for (directory_iterator
d(p
, ec
), end
; !ec
&& d
!= end
; d
.increment(ec
))
1388 count
+= fs::remove_all(d
->path(), ec
);
1389 if (ec
.value() == ENOENT
)
1395 if (fs::remove(p
, ec
))
1397 return ec
? -1 : count
;
1401 fs::rename(const path
& from
, const path
& to
)
1404 rename(from
, to
, ec
);
1406 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1410 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1412 if (posix::rename(from
.c_str(), to
.c_str()))
1413 ec
.assign(errno
, std::generic_category());
1419 fs::resize_file(const path
& p
, uintmax_t size
)
1422 resize_file(p
, size
, ec
);
1424 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1428 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1430 #ifdef _GLIBCXX_HAVE_UNISTD_H
1431 if (size
> static_cast<uintmax_t>(std::numeric_limits
<off_t
>::max()))
1432 ec
.assign(EINVAL
, std::generic_category());
1433 else if (posix::truncate(p
.c_str(), size
))
1434 ec
.assign(errno
, std::generic_category());
1438 ec
= std::make_error_code(std::errc::not_supported
);
1444 fs::space(const path
& p
)
1447 space_info s
= space(p
, ec
);
1449 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1453 #ifdef NEED_DO_SPACE
1455 fs::do_space(const __gnu_posix::char_type
* pathname
,
1456 uintmax_t& capacity
, uintmax_t& free
, uintmax_t& available
,
1457 std::error_code
& ec
)
1459 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1461 if (::statvfs(pathname
, &f
))
1462 ec
.assign(errno
, std::generic_category());
1465 if (f
.f_frsize
!= (unsigned long)-1)
1467 const uintmax_t fragment_size
= f
.f_frsize
;
1468 const fsblkcnt_t unknown
= -1;
1469 if (f
.f_blocks
!= unknown
)
1470 capacity
= f
.f_blocks
* fragment_size
;
1471 if (f
.f_bfree
!= unknown
)
1472 free
= f
.f_bfree
* fragment_size
;
1473 if (f
.f_bavail
!= unknown
)
1474 available
= f
.f_bavail
* fragment_size
;
1478 #elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
1479 ULARGE_INTEGER bytes_avail
= {}, bytes_total
= {}, bytes_free
= {};
1480 if (GetDiskFreeSpaceExW(pathname
, &bytes_avail
, &bytes_total
, &bytes_free
))
1482 if (bytes_total
.QuadPart
!= 0)
1483 capacity
= bytes_total
.QuadPart
;
1484 if (bytes_free
.QuadPart
!= 0)
1485 free
= bytes_free
.QuadPart
;
1486 if (bytes_avail
.QuadPart
!= 0)
1487 available
= bytes_avail
.QuadPart
;
1491 ec
.assign((int)GetLastError(), std::system_category());
1493 ec
= std::make_error_code(std::errc::not_supported
);
1496 #endif // NEED_DO_SPACE
1499 fs::space(const path
& p
, error_code
& ec
) noexcept
1502 static_cast<uintmax_t>(-1),
1503 static_cast<uintmax_t>(-1),
1504 static_cast<uintmax_t>(-1)
1506 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1507 path dir
= absolute(p
);
1508 dir
.remove_filename();
1509 auto str
= dir
.c_str();
1511 auto str
= p
.c_str();
1513 do_space(str
, info
.capacity
, info
.free
, info
.available
, ec
);
1517 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1519 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1523 if (posix::stat(p
.c_str(), &st
))
1526 ec
.assign(err
, std::generic_category());
1527 if (is_not_found_errno(err
))
1528 status
.type(file_type::not_found
);
1530 else if (err
== EOVERFLOW
)
1531 status
.type(file_type::unknown
);
1536 status
= make_file_status(st
);
1543 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1547 if (posix::lstat(p
.c_str(), &st
))
1550 ec
.assign(err
, std::generic_category());
1551 if (is_not_found_errno(err
))
1552 status
.type(file_type::not_found
);
1556 status
= make_file_status(st
);
1564 fs::status(const fs::path
& p
)
1567 auto result
= status(p
, ec
);
1568 if (result
.type() == file_type::none
)
1569 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1574 fs::symlink_status(const fs::path
& p
)
1577 auto result
= symlink_status(p
, ec
);
1578 if (result
.type() == file_type::none
)
1579 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1583 fs::path
fs::temp_directory_path()
1586 path tmp
= temp_directory_path(ec
);
1588 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1592 fs::path
fs::temp_directory_path(error_code
& ec
)
1595 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1596 unsigned len
= 1024;
1601 len
= GetTempPathW(buf
.size(), buf
.data());
1602 } while (len
> buf
.size());
1606 ec
.assign((int)GetLastError(), std::system_category());
1612 const char* tmpdir
= nullptr;
1613 const char* env
[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1614 for (auto e
= env
; tmpdir
== nullptr && *e
!= nullptr; ++e
)
1615 tmpdir
= ::getenv(*e
);
1616 p
= tmpdir
? tmpdir
: "/tmp";
1618 auto st
= status(p
, ec
);
1621 else if (!is_directory(st
))
1624 ec
= std::make_error_code(std::errc::not_a_directory
);
1630 fs::weakly_canonical(const path
& p
)
1633 if (exists(status(p
)))
1634 return canonical(p
);
1637 auto iter
= p
.begin(), end
= p
.end();
1638 // find leading elements of p that exist:
1641 tmp
= result
/ *iter
;
1642 if (exists(status(tmp
)))
1649 if (!result
.empty())
1650 result
= canonical(result
);
1651 // append the non-existing elements:
1655 return result
.lexically_normal();
1659 fs::weakly_canonical(const path
& p
, error_code
& ec
)
1662 file_status st
= status(p
, ec
);
1664 return canonical(p
, ec
);
1665 else if (status_known(st
))
1671 auto iter
= p
.begin(), end
= p
.end();
1672 // find leading elements of p that exist:
1675 tmp
= result
/ *iter
;
1676 st
= status(tmp
, ec
);
1681 if (status_known(st
))
1688 if (!ec
&& !result
.empty())
1689 result
= canonical(result
, ec
);
1694 // append the non-existing elements:
1698 result
= result
.lexically_normal();