1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2016 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>
35 #include <limits.h> // PATH_MAX
36 #ifdef _GLIBCXX_HAVE_UNISTD_H
38 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
39 # include <sys/types.h>
40 # include <sys/stat.h>
43 #ifdef _GLIBCXX_HAVE_FCNTL_H
46 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
47 # include <sys/statvfs.h>
49 #ifdef _GLIBCXX_USE_SENDFILE
50 # include <sys/sendfile.h>
52 # include <ext/stdio_filebuf.h>
55 #if _GLIBCXX_HAVE_UTIME_H
59 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
61 # define utime _wutime
63 # define chmod _wchmod
66 namespace fs
= std::experimental::filesystem
;
69 fs::absolute(const path
& p
, const path
& base
)
71 const bool has_root_dir
= p
.has_root_directory();
72 const bool has_root_name
= p
.has_root_name();
74 if (has_root_dir
&& has_root_name
)
78 abs
= base
.is_absolute() ? base
: absolute(base
);
80 abs
= abs
.root_name() / p
;
81 else if (has_root_name
)
82 abs
= p
.root_name() / abs
.root_directory() / abs
.relative_path()
92 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
93 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
95 inline bool is_dot(char c
) { return c
== '.'; }
98 inline bool is_dot(const fs::path
& path
)
100 const auto& filename
= path
.native();
101 return filename
.size() == 1 && is_dot(filename
[0]);
104 inline bool is_dotdot(const fs::path
& path
)
106 const auto& filename
= path
.native();
107 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
110 struct free_as_in_malloc
112 void operator()(void* p
) const { ::free(p
); }
115 using char_ptr
= std::unique_ptr
<char[], free_as_in_malloc
>;
119 fs::canonical(const path
& p
, const path
& base
, error_code
& ec
)
121 const path pa
= absolute(p
, base
);
124 #ifdef _GLIBCXX_USE_REALPATH
125 char_ptr buf
{ nullptr };
126 # if _XOPEN_VERSION < 700
127 // Not safe to call realpath(path, NULL)
128 buf
.reset( (char*)::malloc(PATH_MAX
) );
130 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
138 if (errno
!= ENAMETOOLONG
)
140 ec
.assign(errno
, std::generic_category());
147 // else: we know there are (currently) no unresolvable symlink loops
149 result
= pa
.root_path();
152 for (auto& f
: pa
.relative_path())
155 int max_allowed_symlinks
= 40;
157 while (!cmpts
.empty() && !ec
)
159 path f
= std::move(cmpts
.front());
164 if (!is_directory(result
, ec
) && !ec
)
165 ec
.assign(ENOTDIR
, std::generic_category());
167 else if (is_dotdot(f
))
169 auto parent
= result
.parent_path();
171 result
= pa
.root_path();
179 if (is_symlink(result
, ec
))
181 path link
= read_symlink(result
, ec
);
184 if (--max_allowed_symlinks
== 0)
185 ec
.assign(ELOOP
, std::generic_category());
188 if (link
.is_absolute())
190 result
= link
.root_path();
191 link
= link
.relative_path();
194 result
.remove_filename();
196 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
203 if (ec
|| !exists(result
, ec
))
210 fs::canonical(const path
& p
, error_code
& ec
)
212 path cur
= current_path(ec
);
215 return canonical(p
, cur
, ec
);
219 fs::canonical(const path
& p
, const path
& base
)
222 path can
= canonical(p
, base
, ec
);
224 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p
, base
,
230 fs::copy(const path
& from
, const path
& to
, copy_options options
)
233 copy(from
, to
, options
, ec
);
235 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
240 template<typename Bitmask
>
241 inline bool is_set(Bitmask obj
, Bitmask bits
)
243 return (obj
& bits
) != Bitmask::none
;
247 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
250 typedef struct ::stat stat_type
;
253 make_file_type(const stat_type
& st
) noexcept
256 #ifdef _GLIBCXX_HAVE_S_ISREG
257 if (S_ISREG(st
.st_mode
))
258 return file_type::regular
;
259 else if (S_ISDIR(st
.st_mode
))
260 return file_type::directory
;
261 else if (S_ISCHR(st
.st_mode
))
262 return file_type::character
;
263 else if (S_ISBLK(st
.st_mode
))
264 return file_type::block
;
265 else if (S_ISFIFO(st
.st_mode
))
266 return file_type::fifo
;
267 else if (S_ISLNK(st
.st_mode
))
268 return file_type::symlink
;
269 else if (S_ISSOCK(st
.st_mode
))
270 return file_type::socket
;
272 return file_type::unknown
;
276 inline fs::file_status
277 make_file_status(const stat_type
& st
) noexcept
279 return fs::file_status
{
281 static_cast<fs::perms
>(st
.st_mode
) & fs::perms::mask
286 is_not_found_errno(int err
) noexcept
288 return err
== ENOENT
|| err
== ENOTDIR
;
291 inline fs::file_time_type
292 file_time(const stat_type
& st
) noexcept
294 using namespace std::chrono
;
295 return fs::file_time_type
{
296 #ifdef _GLIBCXX_USE_ST_MTIM
297 seconds
{st
.st_mtim
.tv_sec
} + nanoseconds
{st
.st_mtim
.tv_nsec
}
304 // Returns true if the file descriptor was successfully closed,
305 // otherwise returns false and the reason will be in errno.
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
);
358 using opts
= fs::copy_options
;
362 if (!is_other(t
) && !is_other(f
)
363 && to_st
->st_dev
== from_st
->st_dev
364 && to_st
->st_ino
== from_st
->st_ino
)
366 ec
= std::make_error_code(std::errc::file_exists
);
370 if (is_set(option
, opts::skip_existing
))
375 else if (is_set(option
, opts::update_existing
))
377 if (file_time(*from_st
) <= file_time(*to_st
))
383 else if (!is_set(option
, opts::overwrite_existing
))
385 ec
= std::make_error_code(std::errc::file_exists
);
391 ~CloseFD() { if (fd
!= -1) close_fd(fd
); }
392 bool close() { return close_fd(std::exchange(fd
, -1)); }
396 CloseFD in
= { ::open(from
.c_str(), O_RDONLY
) };
399 ec
.assign(errno
, std::generic_category());
402 int oflag
= O_WRONLY
|O_CREAT
;
403 if (is_set(option
, opts::overwrite_existing
|opts::update_existing
))
407 CloseFD out
= { ::open(to
.c_str(), oflag
, S_IWUSR
) };
410 if (errno
== EEXIST
&& is_set(option
, opts::skip_existing
))
413 ec
.assign(errno
, std::generic_category());
417 #ifdef _GLIBCXX_USE_FCHMOD
418 if (::fchmod(out
.fd
, from_st
->st_mode
))
419 #elif _GLIBCXX_USE_FCHMODAT
420 if (::fchmodat(AT_FDCWD
, to
.c_str(), from_st
->st_mode
, 0))
422 if (::chmod(to
.c_str(), from_st
->st_mode
))
425 ec
.assign(errno
, std::generic_category());
429 #ifdef _GLIBCXX_USE_SENDFILE
430 const auto n
= ::sendfile(out
.fd
, in
.fd
, nullptr, from_st
->st_size
);
431 if (n
!= from_st
->st_size
)
433 ec
.assign(errno
, std::generic_category());
436 if (!out
.close() || !in
.close())
438 ec
.assign(errno
, std::generic_category());
442 __gnu_cxx::stdio_filebuf
<char> sbin(in
.fd
, std::ios::in
);
443 __gnu_cxx::stdio_filebuf
<char> sbout(out
.fd
, std::ios::out
);
448 if (from_st
->st_size
&& !(std::ostream(&sbout
) << &sbin
))
450 ec
= std::make_error_code(std::errc::io_error
);
453 if (sbout
.close() || sbin
.close())
455 ec
.assign(errno
, std::generic_category());
467 fs::copy(const path
& from
, const path
& to
, copy_options options
,
468 error_code
& ec
) noexcept
470 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
471 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
472 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
473 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
476 stat_type from_st
, to_st
;
477 // N4099 doesn't check copy_symlinks here, but I think that's a defect.
478 if (use_lstat
|| copy_symlinks
479 ? ::lstat(from
.c_str(), &from_st
)
480 : ::stat(from
.c_str(), &from_st
))
482 ec
.assign(errno
, std::generic_category());
486 ? ::lstat(to
.c_str(), &to_st
)
487 : ::stat(to
.c_str(), &to_st
))
489 if (!is_not_found_errno(errno
))
491 ec
.assign(errno
, std::generic_category());
494 t
= file_status
{file_type::not_found
};
497 t
= make_file_status(to_st
);
498 f
= make_file_status(from_st
);
500 if (exists(t
) && !is_other(t
) && !is_other(f
)
501 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
503 ec
= std::make_error_code(std::errc::file_exists
);
506 if (is_other(f
) || is_other(t
))
508 ec
= std::make_error_code(std::errc::not_supported
);
511 if (is_directory(f
) && is_regular_file(t
))
513 ec
= std::make_error_code(std::errc::is_a_directory
);
521 else if (!exists(t
) && copy_symlinks
)
522 copy_symlink(from
, to
, ec
);
524 // Not clear what should be done here.
525 // "Otherwise report an error as specified in Error reporting (7)."
526 ec
= std::make_error_code(std::errc::invalid_argument
);
528 else if (is_regular_file(f
))
530 if (is_set(options
, copy_options::directories_only
))
532 else if (create_symlinks
)
533 create_symlink(from
, to
, ec
);
534 else if (is_set(options
, copy_options::create_hard_links
))
535 create_hard_link(from
, to
, ec
);
536 else if (is_directory(t
))
537 do_copy_file(from
, to
/ from
.filename(), options
, &from_st
, 0, ec
);
540 auto ptr
= exists(t
) ? &to_st
: &from_st
;
541 do_copy_file(from
, to
, options
, &from_st
, ptr
, ec
);
544 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
545 || options
== copy_options::none
))
548 if (!create_directory(to
, from
, ec
))
550 // set an unused bit in options to disable further recursion
551 if (!is_set(options
, copy_options::recursive
))
552 options
|= static_cast<copy_options
>(4096);
553 for (const directory_entry
& x
: directory_iterator(from
))
554 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
556 // "Otherwise no effects." (should ec.clear() be called?)
560 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
563 bool result
= copy_file(from
, to
, option
, ec
);
565 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
571 fs::copy_file(const path
& from
, const path
& to
, copy_options option
,
572 error_code
& ec
) noexcept
574 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
575 return do_copy_file(from
, to
, option
, nullptr, nullptr, ec
);
577 ec
= std::make_error_code(std::errc::not_supported
);
584 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
587 copy_symlink(existing_symlink
, new_symlink
, ec
);
589 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
590 existing_symlink
, new_symlink
, ec
));
594 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
595 error_code
& ec
) noexcept
597 auto p
= read_symlink(existing_symlink
, ec
);
600 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
603 create_directory_symlink(p
, new_symlink
, ec
);
607 create_symlink(p
, new_symlink
, ec
);
612 fs::create_directories(const path
& p
)
615 bool result
= create_directories(p
, ec
);
617 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
623 fs::create_directories(const path
& p
, error_code
& ec
) noexcept
627 ec
= std::make_error_code(errc::invalid_argument
);
630 std::stack
<path
> missing
;
633 while (!pp
.empty() && status(pp
, ec
).type() == file_type::not_found
)
636 const auto& filename
= pp
.filename();
637 if (!is_dot(filename
) && !is_dotdot(filename
))
639 pp
.remove_filename();
642 if (ec
|| missing
.empty())
647 const path
& top
= missing
.top();
648 create_directory(top
, ec
);
649 if (ec
&& is_directory(top
))
653 while (!missing
.empty() && !ec
);
655 return missing
.empty();
661 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
663 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
664 ::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
665 if (::mkdir(p
.c_str(), mode
))
667 ec
.assign(errno
, std::generic_category());
676 ec
= std::make_error_code(std::errc::not_supported
);
683 fs::create_directory(const path
& p
)
686 bool result
= create_directory(p
, ec
);
688 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
694 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
696 return create_dir(p
, perms::all
, ec
);
701 fs::create_directory(const path
& p
, const path
& attributes
)
704 bool result
= create_directory(p
, attributes
, ec
);
706 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
712 fs::create_directory(const path
& p
, const path
& attributes
,
713 error_code
& ec
) noexcept
715 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
717 if (::stat(attributes
.c_str(), &st
))
719 ec
.assign(errno
, std::generic_category());
722 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
724 ec
= std::make_error_code(std::errc::not_supported
);
731 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
734 create_directory_symlink(to
, new_symlink
, ec
);
736 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
737 to
, new_symlink
, ec
));
741 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
742 error_code
& ec
) noexcept
744 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
745 ec
= std::make_error_code(std::errc::not_supported
);
747 create_symlink(to
, new_symlink
, ec
);
753 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
756 create_hard_link(to
, new_hard_link
, ec
);
758 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
759 to
, new_hard_link
, ec
));
763 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
764 error_code
& ec
) noexcept
766 #ifdef _GLIBCXX_HAVE_UNISTD_H
767 if (::link(to
.c_str(), new_hard_link
.c_str()))
768 ec
.assign(errno
, std::generic_category());
772 ec
= std::make_error_code(std::errc::not_supported
);
777 fs::create_symlink(const path
& to
, const path
& new_symlink
)
780 create_symlink(to
, new_symlink
, ec
);
782 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
783 to
, new_symlink
, ec
));
787 fs::create_symlink(const path
& to
, const path
& new_symlink
,
788 error_code
& ec
) noexcept
790 #ifdef _GLIBCXX_HAVE_UNISTD_H
791 if (::symlink(to
.c_str(), new_symlink
.c_str()))
792 ec
.assign(errno
, std::generic_category());
796 ec
= std::make_error_code(std::errc::not_supported
);
805 path p
= current_path(ec
);
807 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
812 fs::current_path(error_code
& ec
)
815 #ifdef _GLIBCXX_HAVE_UNISTD_H
817 if (char_ptr cwd
= char_ptr
{::getcwd(nullptr, 0)})
823 ec
.assign(errno
, std::generic_category());
825 long path_max
= pathconf(".", _PC_PATH_MAX
);
829 else if (path_max
> 10240)
833 for (char_ptr buf
; p
.empty(); size
*= 2)
835 buf
.reset((char*)malloc(size
));
838 if (getcwd(buf
.get(), size
))
843 else if (errno
!= ERANGE
)
845 ec
.assign(errno
, std::generic_category());
851 ec
= std::make_error_code(std::errc::not_enough_memory
);
856 #else // _GLIBCXX_HAVE_UNISTD_H
857 ec
= std::make_error_code(std::errc::not_supported
);
863 fs::current_path(const path
& p
)
868 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
872 fs::current_path(const path
& p
, error_code
& ec
) noexcept
874 #ifdef _GLIBCXX_HAVE_UNISTD_H
875 if (::chdir(p
.c_str()))
876 ec
.assign(errno
, std::generic_category());
880 ec
= std::make_error_code(std::errc::not_supported
);
885 fs::equivalent(const path
& p1
, const path
& p2
)
888 auto result
= equivalent(p1
, p2
, ec
);
890 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
896 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
898 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
900 if (::stat(p1
.c_str(), &st1
) == 0 && ::stat(p2
.c_str(), &st2
) == 0)
902 file_status s1
= make_file_status(st1
);
903 file_status s2
= make_file_status(st2
);
904 if (is_other(s1
) && is_other(s2
))
906 ec
= std::make_error_code(std::errc::not_supported
);
910 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
912 else if (is_not_found_errno(errno
))
914 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
917 ec
.assign(errno
, std::generic_category());
919 ec
= std::make_error_code(std::errc::not_supported
);
925 fs::file_size(const path
& p
)
928 auto sz
= file_size(p
, ec
);
930 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
936 template<typename Accessor
, typename T
>
938 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
940 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
942 if (::stat(p
.c_str(), &st
))
944 ec
.assign(errno
, std::generic_category());
950 ec
= std::make_error_code(std::errc::not_supported
);
957 fs::file_size(const path
& p
, error_code
& ec
) noexcept
961 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
962 S() : type(file_type::not_found
) { }
966 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
967 if (s
.type
== file_type::regular
)
971 if (s
.type
== file_type::directory
)
972 ec
= std::make_error_code(std::errc::is_a_directory
);
974 ec
= std::make_error_code(std::errc::not_supported
);
980 fs::hard_link_count(const path
& p
)
983 auto count
= hard_link_count(p
, ec
);
985 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
990 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
992 return do_stat(p
, ec
, std::mem_fn(&stat::st_nlink
),
993 static_cast<uintmax_t>(-1));
997 fs::is_empty(const path
& p
)
999 return fs::is_directory(status(p
))
1000 ? fs::directory_iterator(p
) == fs::directory_iterator()
1001 : fs::file_size(p
) == 0;
1005 fs::is_empty(const path
& p
, error_code
& ec
) noexcept
1007 auto s
= status(p
, ec
);
1010 return fs::is_directory(s
)
1011 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1012 : fs::file_size(p
, ec
) == 0;
1016 fs::last_write_time(const path
& p
)
1019 auto t
= last_write_time(p
, ec
);
1021 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1026 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1028 return do_stat(p
, ec
, [](const auto& st
) { return file_time(st
); },
1029 file_time_type::min());
1033 fs::last_write_time(const path
& p
, file_time_type new_time
)
1036 last_write_time(p
, new_time
, ec
);
1038 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1042 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
1043 file_time_type new_time
, error_code
& ec
) noexcept
1045 auto d
= new_time
.time_since_epoch();
1046 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1047 #if _GLIBCXX_USE_UTIMENSAT
1048 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1049 struct ::timespec ts
[2];
1051 ts
[0].tv_nsec
= UTIME_OMIT
;
1052 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1053 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1054 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1055 ec
.assign(errno
, std::generic_category());
1058 #elif _GLIBCXX_HAVE_UTIME_H
1060 times
.modtime
= s
.count();
1061 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1063 if (::utime(p
.c_str(), ×
))
1064 ec
.assign(errno
, std::generic_category());
1068 ec
= std::make_error_code(std::errc::not_supported
);
1073 fs::permissions(const path
& p
, perms prms
)
1076 permissions(p
, prms
, ec
);
1078 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1081 void fs::permissions(const path
& p
, perms prms
, error_code
& ec
) noexcept
1083 #if _GLIBCXX_USE_FCHMODAT
1084 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), 0))
1086 if (::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
1088 ec
.assign(errno
, std::generic_category());
1094 fs::read_symlink(const path
& p
)
1097 path tgt
= read_symlink(p
, ec
);
1099 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1103 fs::path
fs::read_symlink(const path
& p
, error_code
& ec
)
1105 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1107 if (::lstat(p
.c_str(), &st
))
1109 ec
.assign(errno
, std::generic_category());
1112 std::string
buf(st
.st_size
, '\0');
1113 ssize_t len
= ::readlink(p
.c_str(), &buf
.front(), buf
.size());
1116 ec
.assign(errno
, std::generic_category());
1119 return path
{buf
.data(), buf
.data()+len
};
1121 ec
= std::make_error_code(std::errc::not_supported
);
1128 fs::remove(const path
& p
)
1131 bool result
= fs::remove(p
, ec
);
1133 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1138 fs::remove(const path
& p
, error_code
& ec
) noexcept
1140 if (exists(symlink_status(p
, ec
)))
1142 if (::remove(p
.c_str()) == 0)
1148 ec
.assign(errno
, std::generic_category());
1155 fs::remove_all(const path
& p
)
1158 bool result
= remove_all(p
, ec
);
1160 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1165 fs::remove_all(const path
& p
, error_code
& ec
) noexcept
1167 auto fs
= symlink_status(p
, ec
);
1168 uintmax_t count
= 0;
1169 if (ec
.value() == 0 && fs
.type() == file_type::directory
)
1170 for (directory_iterator
d(p
, ec
), end
; ec
.value() == 0 && d
!= end
; ++d
)
1171 count
+= fs::remove(d
->path(), ec
);
1174 return fs::remove(p
, ec
) ? ++count
: -1; // fs:remove() calls ec.clear()
1178 fs::rename(const path
& from
, const path
& to
)
1181 rename(from
, to
, ec
);
1183 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1187 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1189 if (::rename(from
.c_str(), to
.c_str()))
1190 ec
.assign(errno
, std::generic_category());
1196 fs::resize_file(const path
& p
, uintmax_t size
)
1199 resize_file(p
, size
, ec
);
1201 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1205 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1207 #ifdef _GLIBCXX_HAVE_UNISTD_H
1208 if (size
> static_cast<uintmax_t>(std::numeric_limits
<off_t
>::max()))
1209 ec
.assign(EINVAL
, std::generic_category());
1210 else if (::truncate(p
.c_str(), size
))
1211 ec
.assign(errno
, std::generic_category());
1215 ec
= std::make_error_code(std::errc::not_supported
);
1221 fs::space(const path
& p
)
1224 space_info s
= space(p
, ec
);
1226 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1231 fs::space(const path
& p
, error_code
& ec
) noexcept
1234 static_cast<uintmax_t>(-1),
1235 static_cast<uintmax_t>(-1),
1236 static_cast<uintmax_t>(-1)
1238 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1240 if (::statvfs(p
.c_str(), &f
))
1241 ec
.assign(errno
, std::generic_category());
1245 f
.f_blocks
* f
.f_frsize
,
1246 f
.f_bfree
* f
.f_frsize
,
1247 f
.f_bavail
* f
.f_frsize
1252 ec
= std::make_error_code(std::errc::not_supported
);
1257 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1259 fs::status(const fs::path
& p
, std::error_code
& ec
) noexcept
1263 if (::stat(p
.c_str(), &st
))
1266 ec
.assign(err
, std::generic_category());
1267 if (is_not_found_errno(err
))
1268 status
.type(file_type::not_found
);
1272 status
= make_file_status(st
);
1279 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1283 if (::lstat(p
.c_str(), &st
))
1286 ec
.assign(err
, std::generic_category());
1287 if (is_not_found_errno(err
))
1288 status
.type(file_type::not_found
);
1292 status
= make_file_status(st
);
1300 fs::status(const fs::path
& p
)
1303 auto result
= status(p
, ec
);
1304 if (result
.type() == file_type::none
)
1305 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1310 fs::symlink_status(const fs::path
& p
)
1313 auto result
= symlink_status(p
, ec
);
1314 if (result
.type() == file_type::none
)
1315 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1320 fs::system_complete(const path
& p
)
1323 path comp
= system_complete(p
, ec
);
1325 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p
, ec
));
1330 fs::system_complete(const path
& p
, error_code
& ec
)
1332 path base
= current_path(ec
);
1333 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1334 if (p
.is_absolute() || !p
.has_root_name()
1335 || p
.root_name() == base
.root_name())
1336 return absolute(p
, base
);
1338 ec
= std::make_error_code(std::errc::not_supported
);
1343 return absolute(p
, base
);
1347 fs::path
fs::temp_directory_path()
1350 path tmp
= temp_directory_path(ec
);
1352 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1356 fs::path
fs::temp_directory_path(error_code
& ec
)
1358 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1359 ec
= std::make_error_code(std::errc::not_supported
);
1362 const char* tmpdir
= nullptr;
1363 const char* env
[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1364 for (auto e
= env
; tmpdir
== nullptr && *e
!= nullptr; ++e
)
1365 tmpdir
= ::getenv(*e
);
1366 path p
= tmpdir
? tmpdir
: "/tmp";
1367 if (exists(p
) && is_directory(p
))
1372 ec
= std::make_error_code(std::errc::not_a_directory
);