1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2017 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
29 #include <experimental/filesystem>
33 #include <ext/stdio_filebuf.h>
37 #include <limits.h> // PATH_MAX
38 #ifdef _GLIBCXX_HAVE_UNISTD_H
40 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
41 # include <sys/types.h>
42 # include <sys/stat.h>
45 #ifdef _GLIBCXX_HAVE_FCNTL_H
48 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
49 # include <sys/statvfs.h>
51 #ifdef _GLIBCXX_USE_SENDFILE
52 # include <sys/sendfile.h>
54 #if _GLIBCXX_HAVE_UTIME_H
58 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
60 # define utime _wutime
62 # define chmod _wchmod
65 namespace fs
= std::experimental::filesystem
;
68 fs::absolute(const path
& p
, const path
& base
)
70 const bool has_root_dir
= p
.has_root_directory();
71 const bool has_root_name
= p
.has_root_name();
73 if (has_root_dir
&& has_root_name
)
77 abs
= base
.is_absolute() ? base
: absolute(base
);
79 abs
= abs
.root_name() / p
;
80 else if (has_root_name
)
81 abs
= p
.root_name() / abs
.root_directory() / abs
.relative_path()
91 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
92 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
94 inline bool is_dot(char c
) { return c
== '.'; }
97 inline bool is_dot(const fs::path
& path
)
99 const auto& filename
= path
.native();
100 return filename
.size() == 1 && is_dot(filename
[0]);
103 inline bool is_dotdot(const fs::path
& path
)
105 const auto& filename
= path
.native();
106 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
109 struct free_as_in_malloc
111 void operator()(void* p
) const { ::free(p
); }
114 using char_ptr
= std::unique_ptr
<char[], free_as_in_malloc
>;
118 fs::canonical(const path
& p
, const path
& base
, error_code
& ec
)
120 const path pa
= absolute(p
, base
);
123 #ifdef _GLIBCXX_USE_REALPATH
124 char_ptr buf
{ nullptr };
125 # if _XOPEN_VERSION < 700
126 // Not safe to call realpath(path, NULL)
127 buf
.reset( (char*)::malloc(PATH_MAX
) );
129 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
137 if (errno
!= ENAMETOOLONG
)
139 ec
.assign(errno
, std::generic_category());
147 ec
= make_error_code(std::errc::no_such_file_or_directory
);
150 // else: we know there are (currently) no unresolvable symlink loops
152 result
= pa
.root_path();
155 for (auto& f
: pa
.relative_path())
158 int max_allowed_symlinks
= 40;
160 while (!cmpts
.empty() && !ec
)
162 path f
= std::move(cmpts
.front());
167 if (!is_directory(result
, ec
) && !ec
)
168 ec
.assign(ENOTDIR
, std::generic_category());
170 else if (is_dotdot(f
))
172 auto parent
= result
.parent_path();
174 result
= pa
.root_path();
182 if (is_symlink(result
, ec
))
184 path link
= read_symlink(result
, ec
);
187 if (--max_allowed_symlinks
== 0)
188 ec
.assign(ELOOP
, std::generic_category());
191 if (link
.is_absolute())
193 result
= link
.root_path();
194 link
= link
.relative_path();
197 result
.remove_filename();
199 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
206 if (ec
|| !exists(result
, ec
))
213 fs::canonical(const path
& p
, error_code
& ec
)
215 path cur
= current_path(ec
);
218 return canonical(p
, cur
, ec
);
222 fs::canonical(const path
& p
, const path
& base
)
225 path can
= canonical(p
, base
, ec
);
227 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p
, base
,
233 fs::copy(const path
& from
, const path
& to
, copy_options options
)
236 copy(from
, to
, options
, ec
);
238 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
243 template<typename Bitmask
>
244 inline bool is_set(Bitmask obj
, Bitmask bits
)
246 return (obj
& bits
) != Bitmask::none
;
250 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
253 typedef struct ::stat stat_type
;
256 make_file_type(const stat_type
& st
) noexcept
259 #ifdef _GLIBCXX_HAVE_S_ISREG
260 if (S_ISREG(st
.st_mode
))
261 return file_type::regular
;
262 else if (S_ISDIR(st
.st_mode
))
263 return file_type::directory
;
264 else if (S_ISCHR(st
.st_mode
))
265 return file_type::character
;
266 else if (S_ISBLK(st
.st_mode
))
267 return file_type::block
;
268 else if (S_ISFIFO(st
.st_mode
))
269 return file_type::fifo
;
270 else if (S_ISLNK(st
.st_mode
))
271 return file_type::symlink
;
272 else if (S_ISSOCK(st
.st_mode
))
273 return file_type::socket
;
275 return file_type::unknown
;
279 inline fs::file_status
280 make_file_status(const stat_type
& st
) noexcept
282 return fs::file_status
{
284 static_cast<fs::perms
>(st
.st_mode
) & fs::perms::mask
289 is_not_found_errno(int err
) noexcept
291 return err
== ENOENT
|| err
== ENOTDIR
;
294 inline fs::file_time_type
295 file_time(const stat_type
& st
, std::error_code
& ec
) noexcept
297 using namespace std::chrono
;
298 #ifdef _GLIBCXX_USE_ST_MTIM
299 time_t s
= st
.st_mtim
.tv_sec
;
300 nanoseconds ns
{st
.st_mtim
.tv_nsec
};
302 time_t s
= st
.st_mtime
;
306 if (s
>= (nanoseconds::max().count() / 1e9
))
308 ec
= std::make_error_code(std::errc::value_too_large
); // EOVERFLOW
309 return fs::file_time_type::min();
312 return fs::file_time_type
{seconds
{s
} + ns
};
316 do_copy_file(const fs::path
& from
, const fs::path
& to
,
317 fs::copy_options option
,
318 stat_type
* from_st
, stat_type
* to_st
,
319 std::error_code
& ec
) noexcept
322 fs::file_status t
, f
;
324 if (to_st
== nullptr)
326 if (::stat(to
.c_str(), &st1
))
329 if (!is_not_found_errno(err
))
331 ec
.assign(err
, std::generic_category());
338 else if (to_st
== from_st
)
341 if (to_st
== nullptr)
342 t
= fs::file_status
{fs::file_type::not_found
};
344 t
= make_file_status(*to_st
);
346 if (from_st
== nullptr)
348 if (::stat(from
.c_str(), &st2
))
350 ec
.assign(errno
, std::generic_category());
356 f
= make_file_status(*from_st
);
357 // _GLIBCXX_RESOLVE_LIB_DEFECTS
358 // 2712. copy_file() has a number of unspecified error conditions
359 if (!is_regular_file(f
))
361 ec
= std::make_error_code(std::errc::not_supported
);
365 using opts
= fs::copy_options
;
369 if (!is_regular_file(t
))
371 ec
= std::make_error_code(std::errc::not_supported
);
375 if (to_st
->st_dev
== from_st
->st_dev
376 && to_st
->st_ino
== from_st
->st_ino
)
378 ec
= std::make_error_code(std::errc::file_exists
);
382 if (is_set(option
, opts::skip_existing
))
387 else if (is_set(option
, opts::update_existing
))
389 const auto from_mtime
= file_time(*from_st
, ec
);
392 if ((from_mtime
<= file_time(*to_st
, ec
)) || ec
)
395 else if (!is_set(option
, opts::overwrite_existing
))
397 ec
= std::make_error_code(std::errc::file_exists
);
400 else if (!is_regular_file(t
))
402 ec
= std::make_error_code(std::errc::not_supported
);
408 ~CloseFD() { if (fd
!= -1) ::close(fd
); }
409 bool close() { return ::close(std::exchange(fd
, -1)) == 0; }
413 CloseFD in
= { ::open(from
.c_str(), O_RDONLY
) };
416 ec
.assign(errno
, std::generic_category());
419 int oflag
= O_WRONLY
|O_CREAT
;
420 if (is_set(option
, opts::overwrite_existing
|opts::update_existing
))
424 CloseFD out
= { ::open(to
.c_str(), oflag
, S_IWUSR
) };
427 if (errno
== EEXIST
&& is_set(option
, opts::skip_existing
))
430 ec
.assign(errno
, std::generic_category());
434 #ifdef _GLIBCXX_USE_FCHMOD
435 if (::fchmod(out
.fd
, from_st
->st_mode
))
436 #elif defined _GLIBCXX_USE_FCHMODAT
437 if (::fchmodat(AT_FDCWD
, to
.c_str(), from_st
->st_mode
, 0))
439 if (::chmod(to
.c_str(), from_st
->st_mode
))
442 ec
.assign(errno
, std::generic_category());
446 #ifdef _GLIBCXX_USE_SENDFILE
448 const auto n
= ::sendfile(out
.fd
, in
.fd
, &offset
, from_st
->st_size
);
449 if (n
< 0 && (errno
== ENOSYS
|| errno
== EINVAL
))
452 __gnu_cxx::stdio_filebuf
<char> sbin(in
.fd
, std::ios::in
);
453 __gnu_cxx::stdio_filebuf
<char> sbout(out
.fd
, std::ios::out
);
458 if (from_st
->st_size
&& !(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());
472 #ifdef _GLIBCXX_USE_SENDFILE
474 if (n
!= from_st
->st_size
)
476 ec
.assign(errno
, std::generic_category());
479 if (!out
.close() || !in
.close())
481 ec
.assign(errno
, std::generic_category());
493 fs::copy(const path
& from
, const path
& to
, copy_options options
,
494 error_code
& ec
) noexcept
496 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
497 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
498 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
499 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
502 stat_type from_st
, to_st
;
503 // _GLIBCXX_RESOLVE_LIB_DEFECTS
504 // 2681. filesystem::copy() cannot copy symlinks
505 if (use_lstat
|| copy_symlinks
506 ? ::lstat(from
.c_str(), &from_st
)
507 : ::stat(from
.c_str(), &from_st
))
509 ec
.assign(errno
, std::generic_category());
513 ? ::lstat(to
.c_str(), &to_st
)
514 : ::stat(to
.c_str(), &to_st
))
516 if (!is_not_found_errno(errno
))
518 ec
.assign(errno
, std::generic_category());
521 t
= file_status
{file_type::not_found
};
524 t
= make_file_status(to_st
);
525 f
= make_file_status(from_st
);
527 if (exists(t
) && !is_other(t
) && !is_other(f
)
528 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
530 ec
= std::make_error_code(std::errc::file_exists
);
533 if (is_other(f
) || is_other(t
))
535 ec
= std::make_error_code(std::errc::not_supported
);
538 if (is_directory(f
) && is_regular_file(t
))
540 ec
= std::make_error_code(std::errc::is_a_directory
);
548 else if (!exists(t
) && copy_symlinks
)
549 copy_symlink(from
, to
, ec
);
551 // Not clear what should be done here.
552 // "Otherwise report an error as specified in Error reporting (7)."
553 ec
= std::make_error_code(std::errc::invalid_argument
);
555 else if (is_regular_file(f
))
557 if (is_set(options
, copy_options::directories_only
))
559 else if (create_symlinks
)
560 create_symlink(from
, to
, ec
);
561 else if (is_set(options
, copy_options::create_hard_links
))
562 create_hard_link(from
, to
, ec
);
563 else if (is_directory(t
))
564 do_copy_file(from
, to
/ from
.filename(), options
, &from_st
, 0, ec
);
567 auto ptr
= exists(t
) ? &to_st
: &from_st
;
568 do_copy_file(from
, to
, options
, &from_st
, ptr
, ec
);
571 // _GLIBCXX_RESOLVE_LIB_DEFECTS
572 // 2682. filesystem::copy() won't create a symlink to a directory
573 else if (is_directory(f
) && create_symlinks
)
574 ec
= std::make_error_code(errc::is_a_directory
);
575 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
576 || options
== copy_options::none
))
579 if (!create_directory(to
, from
, ec
))
581 // set an unused bit in options to disable further recursion
582 if (!is_set(options
, copy_options::recursive
))
583 options
|= static_cast<copy_options
>(4096);
584 for (const directory_entry
& x
: directory_iterator(from
))
585 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
587 // _GLIBCXX_RESOLVE_LIB_DEFECTS
588 // 2683. filesystem::copy() says "no effects"
594 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
597 bool result
= copy_file(from
, to
, option
, ec
);
599 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
605 fs::copy_file(const path
& from
, const path
& to
, copy_options option
,
606 error_code
& ec
) noexcept
608 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
609 return do_copy_file(from
, to
, option
, nullptr, nullptr, ec
);
611 ec
= std::make_error_code(std::errc::not_supported
);
618 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
621 copy_symlink(existing_symlink
, new_symlink
, ec
);
623 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
624 existing_symlink
, new_symlink
, ec
));
628 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
629 error_code
& ec
) noexcept
631 auto p
= read_symlink(existing_symlink
, ec
);
634 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
637 create_directory_symlink(p
, new_symlink
, ec
);
641 create_symlink(p
, new_symlink
, ec
);
646 fs::create_directories(const path
& p
)
649 bool result
= create_directories(p
, ec
);
651 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
657 fs::create_directories(const path
& p
, error_code
& ec
) noexcept
661 ec
= std::make_error_code(errc::invalid_argument
);
664 std::stack
<path
> missing
;
667 while (!pp
.empty() && status(pp
, ec
).type() == file_type::not_found
)
670 const auto& filename
= pp
.filename();
671 if (!is_dot(filename
) && !is_dotdot(filename
))
673 pp
.remove_filename();
676 if (ec
|| missing
.empty())
681 const path
& top
= missing
.top();
682 create_directory(top
, ec
);
683 if (ec
&& is_directory(top
))
687 while (!missing
.empty() && !ec
);
689 return missing
.empty();
695 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
697 bool created
= false;
698 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
699 ::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
700 if (::mkdir(p
.c_str(), mode
))
702 const int err
= errno
;
703 if (err
!= EEXIST
|| !is_directory(p
))
704 ec
.assign(err
, std::generic_category());
714 ec
= std::make_error_code(std::errc::not_supported
);
721 fs::create_directory(const path
& p
)
724 bool result
= create_directory(p
, ec
);
726 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
732 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
734 return create_dir(p
, perms::all
, ec
);
739 fs::create_directory(const path
& p
, const path
& attributes
)
742 bool result
= create_directory(p
, attributes
, ec
);
744 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
750 fs::create_directory(const path
& p
, const path
& attributes
,
751 error_code
& ec
) noexcept
753 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
755 if (::stat(attributes
.c_str(), &st
))
757 ec
.assign(errno
, std::generic_category());
760 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
762 ec
= std::make_error_code(std::errc::not_supported
);
769 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
772 create_directory_symlink(to
, new_symlink
, ec
);
774 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
775 to
, new_symlink
, ec
));
779 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
780 error_code
& ec
) noexcept
782 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
783 ec
= std::make_error_code(std::errc::not_supported
);
785 create_symlink(to
, new_symlink
, ec
);
791 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
794 create_hard_link(to
, new_hard_link
, ec
);
796 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
797 to
, new_hard_link
, ec
));
801 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
802 error_code
& ec
) noexcept
804 #ifdef _GLIBCXX_HAVE_UNISTD_H
805 if (::link(to
.c_str(), new_hard_link
.c_str()))
806 ec
.assign(errno
, std::generic_category());
810 ec
= std::make_error_code(std::errc::not_supported
);
815 fs::create_symlink(const path
& to
, const path
& new_symlink
)
818 create_symlink(to
, new_symlink
, ec
);
820 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
821 to
, new_symlink
, ec
));
825 fs::create_symlink(const path
& to
, const path
& new_symlink
,
826 error_code
& ec
) noexcept
828 #ifdef _GLIBCXX_HAVE_UNISTD_H
829 if (::symlink(to
.c_str(), new_symlink
.c_str()))
830 ec
.assign(errno
, std::generic_category());
834 ec
= std::make_error_code(std::errc::not_supported
);
843 path p
= current_path(ec
);
845 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
850 fs::current_path(error_code
& ec
)
853 #ifdef _GLIBCXX_HAVE_UNISTD_H
855 if (char_ptr cwd
= char_ptr
{::getcwd(nullptr, 0)})
861 ec
.assign(errno
, std::generic_category());
863 long path_max
= pathconf(".", _PC_PATH_MAX
);
867 else if (path_max
> 10240)
871 for (char_ptr buf
; p
.empty(); size
*= 2)
873 buf
.reset((char*)malloc(size
));
876 if (getcwd(buf
.get(), size
))
881 else if (errno
!= ERANGE
)
883 ec
.assign(errno
, std::generic_category());
889 ec
= std::make_error_code(std::errc::not_enough_memory
);
894 #else // _GLIBCXX_HAVE_UNISTD_H
895 ec
= std::make_error_code(std::errc::not_supported
);
901 fs::current_path(const path
& p
)
906 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
910 fs::current_path(const path
& p
, error_code
& ec
) noexcept
912 #ifdef _GLIBCXX_HAVE_UNISTD_H
913 if (::chdir(p
.c_str()))
914 ec
.assign(errno
, std::generic_category());
918 ec
= std::make_error_code(std::errc::not_supported
);
923 fs::equivalent(const path
& p1
, const path
& p2
)
926 auto result
= equivalent(p1
, p2
, ec
);
928 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
934 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
936 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
940 if (::stat(p1
.c_str(), &st1
) == 0)
941 s1
= make_file_status(st1
);
942 else if (is_not_found_errno(errno
))
943 s1
.type(file_type::not_found
);
947 if (::stat(p2
.c_str(), &st2
) == 0)
948 s2
= make_file_status(st2
);
949 else if (is_not_found_errno(errno
))
950 s2
.type(file_type::not_found
);
954 if (exists(s1
) && exists(s2
))
956 if (is_other(s1
) && is_other(s2
))
958 ec
= std::make_error_code(std::errc::not_supported
);
962 if (is_other(s1
) || is_other(s2
))
964 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
966 else if (!exists(s1
) && !exists(s2
))
967 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
969 ec
.assign(err
, std::generic_category());
974 ec
= std::make_error_code(std::errc::not_supported
);
980 fs::file_size(const path
& p
)
983 auto sz
= file_size(p
, ec
);
985 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
991 template<typename Accessor
, typename T
>
993 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
995 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
997 if (::stat(p
.c_str(), &st
))
999 ec
.assign(errno
, std::generic_category());
1005 ec
= std::make_error_code(std::errc::not_supported
);
1012 fs::file_size(const path
& p
, error_code
& ec
) noexcept
1016 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
1017 S() : type(file_type::not_found
) { }
1021 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
1022 if (s
.type
== file_type::regular
)
1026 if (s
.type
== file_type::directory
)
1027 ec
= std::make_error_code(std::errc::is_a_directory
);
1029 ec
= std::make_error_code(std::errc::not_supported
);
1035 fs::hard_link_count(const path
& p
)
1038 auto count
= hard_link_count(p
, ec
);
1040 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
1045 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
1047 return do_stat(p
, ec
, std::mem_fn(&stat::st_nlink
),
1048 static_cast<uintmax_t>(-1));
1052 fs::is_empty(const path
& p
)
1055 bool e
= is_empty(p
, ec
);
1057 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1063 fs::is_empty(const path
& p
, error_code
& ec
) noexcept
1065 auto s
= status(p
, ec
);
1068 bool empty
= fs::is_directory(s
)
1069 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1070 : fs::file_size(p
, ec
) == 0;
1071 return ec
? false : empty
;
1075 fs::last_write_time(const path
& p
)
1078 auto t
= last_write_time(p
, ec
);
1080 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1085 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1087 return do_stat(p
, ec
, [&ec
](const auto& st
) { return file_time(st
, ec
); },
1088 file_time_type::min());
1092 fs::last_write_time(const path
& p
, file_time_type new_time
)
1095 last_write_time(p
, new_time
, ec
);
1097 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1101 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
1102 file_time_type new_time
, error_code
& ec
) noexcept
1104 auto d
= new_time
.time_since_epoch();
1105 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1106 #if _GLIBCXX_USE_UTIMENSAT
1107 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1108 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
1111 ns
+= chrono::seconds(1);
1113 struct ::timespec ts
[2];
1115 ts
[0].tv_nsec
= UTIME_OMIT
;
1116 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1117 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1118 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1119 ec
.assign(errno
, std::generic_category());
1122 #elif _GLIBCXX_HAVE_UTIME_H
1124 times
.modtime
= s
.count();
1125 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1127 if (::utime(p
.c_str(), ×
))
1128 ec
.assign(errno
, std::generic_category());
1132 ec
= std::make_error_code(std::errc::not_supported
);
1137 fs::permissions(const path
& p
, perms prms
)
1140 permissions(p
, prms
, ec
);
1142 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1146 fs::permissions(const path
& p
, perms prms
, error_code
& ec
) noexcept
1148 const bool add
= is_set(prms
, perms::add_perms
);
1149 const bool remove
= is_set(prms
, perms::remove_perms
);
1150 const bool nofollow
= is_set(prms
, perms::symlink_nofollow
);
1153 ec
= std::make_error_code(std::errc::invalid_argument
);
1157 prms
&= perms::mask
;
1160 if (add
|| remove
|| nofollow
)
1162 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
1165 auto curr
= st
.permissions();
1169 prms
= curr
& ~prms
;
1173 #if _GLIBCXX_USE_FCHMODAT
1174 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
1175 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
1178 if (nofollow
&& is_symlink(st
))
1179 ec
= std::make_error_code(std::errc::operation_not_supported
);
1180 else if (::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
1185 ec
.assign(err
, std::generic_category());
1191 fs::read_symlink(const path
& p
)
1194 path tgt
= read_symlink(p
, ec
);
1196 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1200 fs::path
fs::read_symlink(const path
& p
, error_code
& ec
)
1202 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1204 if (::lstat(p
.c_str(), &st
))
1206 ec
.assign(errno
, std::generic_category());
1209 std::string
buf(st
.st_size
, '\0');
1210 ssize_t len
= ::readlink(p
.c_str(), &buf
.front(), buf
.size());
1213 ec
.assign(errno
, std::generic_category());
1217 return path
{buf
.data(), buf
.data()+len
};
1219 ec
= std::make_error_code(std::errc::not_supported
);
1226 fs::remove(const path
& p
)
1229 bool result
= fs::remove(p
, ec
);
1231 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1236 fs::remove(const path
& p
, error_code
& ec
) noexcept
1238 if (exists(symlink_status(p
, ec
)))
1240 if (::remove(p
.c_str()) == 0)
1246 ec
.assign(errno
, std::generic_category());
1253 fs::remove_all(const path
& p
)
1256 bool result
= remove_all(p
, ec
);
1258 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1263 fs::remove_all(const path
& p
, error_code
& ec
) noexcept
1265 auto fs
= symlink_status(p
, ec
);
1266 uintmax_t count
= 0;
1267 if (ec
.value() == 0 && fs
.type() == file_type::directory
)
1268 for (directory_iterator
d(p
, ec
), end
; ec
.value() == 0 && d
!= end
; ++d
)
1269 count
+= fs::remove_all(d
->path(), ec
);
1272 return fs::remove(p
, ec
) ? ++count
: -1; // fs:remove() calls ec.clear()
1276 fs::rename(const path
& from
, const path
& to
)
1279 rename(from
, to
, ec
);
1281 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1285 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1287 if (::rename(from
.c_str(), to
.c_str()))
1288 ec
.assign(errno
, std::generic_category());
1294 fs::resize_file(const path
& p
, uintmax_t size
)
1297 resize_file(p
, size
, ec
);
1299 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1303 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1305 #ifdef _GLIBCXX_HAVE_UNISTD_H
1306 if (size
> static_cast<uintmax_t>(std::numeric_limits
<off_t
>::max()))
1307 ec
.assign(EINVAL
, std::generic_category());
1308 else if (::truncate(p
.c_str(), size
))
1309 ec
.assign(errno
, std::generic_category());
1313 ec
= std::make_error_code(std::errc::not_supported
);
1319 fs::space(const path
& p
)
1322 space_info s
= space(p
, ec
);
1324 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1329 fs::space(const path
& p
, error_code
& ec
) noexcept
1332 static_cast<uintmax_t>(-1),
1333 static_cast<uintmax_t>(-1),
1334 static_cast<uintmax_t>(-1)
1336 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1338 if (::statvfs(p
.c_str(), &f
))
1339 ec
.assign(errno
, std::generic_category());
1343 f
.f_blocks
* f
.f_frsize
,
1344 f
.f_bfree
* f
.f_frsize
,
1345 f
.f_bavail
* f
.f_frsize
1350 ec
= std::make_error_code(std::errc::not_supported
);
1355 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1357 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1361 if (::stat(p
.c_str(), &st
))
1364 ec
.assign(err
, std::generic_category());
1365 if (is_not_found_errno(err
))
1366 status
.type(file_type::not_found
);
1368 else if (err
== EOVERFLOW
)
1369 status
.type(file_type::unknown
);
1374 status
= make_file_status(st
);
1381 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1385 if (::lstat(p
.c_str(), &st
))
1388 ec
.assign(err
, std::generic_category());
1389 if (is_not_found_errno(err
))
1390 status
.type(file_type::not_found
);
1394 status
= make_file_status(st
);
1402 fs::status(const fs::path
& p
)
1405 auto result
= status(p
, ec
);
1406 if (result
.type() == file_type::none
)
1407 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1412 fs::symlink_status(const fs::path
& p
)
1415 auto result
= symlink_status(p
, ec
);
1416 if (result
.type() == file_type::none
)
1417 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1422 fs::system_complete(const path
& p
)
1425 path comp
= system_complete(p
, ec
);
1427 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p
, ec
));
1432 fs::system_complete(const path
& p
, error_code
& ec
)
1434 path base
= current_path(ec
);
1435 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1436 if (p
.is_absolute() || !p
.has_root_name()
1437 || p
.root_name() == base
.root_name())
1438 return absolute(p
, base
);
1440 ec
= std::make_error_code(std::errc::not_supported
);
1445 return absolute(p
, base
);
1449 fs::path
fs::temp_directory_path()
1452 path tmp
= temp_directory_path(ec
);
1454 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1458 fs::path
fs::temp_directory_path(error_code
& ec
)
1460 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1461 ec
= std::make_error_code(std::errc::not_supported
);
1464 const char* tmpdir
= nullptr;
1465 const char* env
[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1466 for (auto e
= env
; tmpdir
== nullptr && *e
!= nullptr; ++e
)
1467 tmpdir
= ::getenv(*e
);
1468 path p
= tmpdir
? tmpdir
: "/tmp";
1469 auto st
= status(p
, ec
);
1472 if (is_directory(st
))
1478 ec
= std::make_error_code(std::errc::not_a_directory
);