1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2023 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
31 // Cygwin needs this for secure_getenv
32 # define _GNU_SOURCE 1
35 #include <bits/largefile-config.h>
43 #include <limits.h> // PATH_MAX
44 #ifdef _GLIBCXX_HAVE_FCNTL_H
45 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
47 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
48 # include <sys/stat.h> // stat, utimensat, fchmodat
50 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
51 # include <sys/statvfs.h> // statvfs
53 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
54 # include <utime.h> // utime
56 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
57 # define WIN32_LEAN_AND_MEAN
61 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
62 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
63 #include "../filesystem/ops-common.h"
65 #pragma GCC diagnostic ignored "-Wunused-parameter"
67 namespace fs
= std::filesystem
;
68 namespace posix
= std::filesystem::__gnu_posix
;
71 fs::absolute(const path
& p
)
74 path ret
= absolute(p
, ec
);
76 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p
,
82 fs::absolute(const path
& p
, error_code
& ec
)
87 ec
= make_error_code(std::errc::invalid_argument
);
97 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
98 // s must remain null-terminated
99 wstring_view s
= p
.native();
101 if (p
.has_root_directory()) // implies !p.has_root_name()
103 // GetFullPathNameW("//") gives unwanted result (PR 88884).
104 // If there are multiple directory separators at the start,
105 // skip all but the last of them.
106 const auto pos
= s
.find_first_not_of(L
"/\\");
107 __glibcxx_assert(pos
!= 0);
108 s
.remove_prefix(std::min(s
.length(), pos
) - 1);
116 len
= GetFullPathNameW(s
.data(), len
, buf
.data(), nullptr);
118 while (len
> buf
.size());
121 ec
= __last_system_error();
125 ret
= std::move(buf
);
128 ret
= current_path(ec
);
136 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
137 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
139 inline bool is_dot(char c
) { return c
== '.'; }
142 inline bool is_dot(const fs::path
& path
)
144 const auto& filename
= path
.native();
145 return filename
.size() == 1 && is_dot(filename
[0]);
148 inline bool is_dotdot(const fs::path
& path
)
150 const auto& filename
= path
.native();
151 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
154 struct free_as_in_malloc
156 void operator()(void* p
) const { ::free(p
); }
159 using char_ptr
= std::unique_ptr
<fs::path::value_type
[], free_as_in_malloc
>;
163 fs::canonical(const path
& p
, error_code
& ec
)
166 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
167 const path pa
= absolute(p
.lexically_normal(), ec
);
169 const path pa
= absolute(p
, ec
);
174 #ifdef _GLIBCXX_USE_REALPATH
175 char_ptr buf
{ nullptr };
176 # if _XOPEN_VERSION < 700
177 // Not safe to call realpath(path, NULL)
178 using char_type
= fs::path::value_type
;
179 buf
.reset( (char_type
*)::malloc(PATH_MAX
* sizeof(char_type
)) );
181 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
189 if (errno
!= ENAMETOOLONG
)
191 ec
.assign(errno
, std::generic_category());
199 ec
= make_error_code(std::errc::no_such_file_or_directory
);
202 // else: we know there are (currently) no unresolvable symlink loops
204 result
= pa
.root_path();
207 for (auto& f
: pa
.relative_path())
210 int max_allowed_symlinks
= 40;
212 while (!cmpts
.empty() && !ec
)
214 path f
= std::move(cmpts
.front());
219 // ignore empty element
223 if (!is_directory(result
, ec
) && !ec
)
224 ec
.assign(ENOTDIR
, std::generic_category());
226 else if (is_dotdot(f
))
228 auto parent
= result
.parent_path();
230 result
= pa
.root_path();
238 if (is_symlink(result
, ec
))
240 path link
= read_symlink(result
, ec
);
243 if (--max_allowed_symlinks
== 0)
244 ec
.assign(ELOOP
, std::generic_category());
247 if (link
.is_absolute())
249 result
= link
.root_path();
250 link
= link
.relative_path();
253 result
= result
.parent_path();
255 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
262 if (ec
|| !exists(result
, ec
))
269 fs::canonical(const path
& p
)
272 path res
= canonical(p
, ec
);
274 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
280 fs::copy(const path
& from
, const path
& to
, copy_options options
)
283 copy(from
, to
, options
, ec
);
285 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
288 namespace std::filesystem
290 // Need this as there's no 'perm_options::none' enumerator.
291 static inline bool is_set(fs::perm_options obj
, fs::perm_options bits
)
293 return (obj
& bits
) != fs::perm_options
{};
299 struct internal_file_clock
: fs::__file_clock
301 using __file_clock::_S_to_sys
;
302 using __file_clock::_S_from_sys
;
304 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
305 static fs::file_time_type
306 from_stat(const fs::stat_type
& st
, std::error_code
& ec
) noexcept
308 const auto sys_time
= fs::file_time(st
, ec
);
309 if (sys_time
== sys_time
.min())
310 return fs::file_time_type::min();
311 return _S_from_sys(sys_time
);
318 fs::copy(const path
& from
, const path
& to
, copy_options options
,
321 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
322 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
323 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
324 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
325 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
328 stat_type from_st
, to_st
;
329 // _GLIBCXX_RESOLVE_LIB_DEFECTS
330 // 2681. filesystem::copy() cannot copy symlinks
331 if (use_lstat
|| copy_symlinks
332 ? posix::lstat(from
.c_str(), &from_st
)
333 : posix::stat(from
.c_str(), &from_st
))
335 ec
.assign(errno
, std::generic_category());
339 ? posix::lstat(to
.c_str(), &to_st
)
340 : posix::stat(to
.c_str(), &to_st
))
342 if (!is_not_found_errno(errno
))
344 ec
.assign(errno
, std::generic_category());
347 t
= file_status
{file_type::not_found
};
350 t
= make_file_status(to_st
);
351 f
= make_file_status(from_st
);
353 if (exists(t
) && !is_other(t
) && !is_other(f
)
354 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
356 ec
= std::make_error_code(std::errc::file_exists
);
359 if (is_other(f
) || is_other(t
))
361 ec
= std::make_error_code(std::errc::invalid_argument
);
364 if (is_directory(f
) && is_regular_file(t
))
366 ec
= std::make_error_code(std::errc::is_a_directory
);
374 else if (!exists(t
) && copy_symlinks
)
375 copy_symlink(from
, to
, ec
);
377 // Not clear what should be done here.
378 // "Otherwise report an error as specified in Error reporting (7)."
379 ec
= std::make_error_code(std::errc::invalid_argument
);
381 else if (is_regular_file(f
))
383 if (is_set(options
, copy_options::directories_only
))
385 else if (create_symlinks
)
386 create_symlink(from
, to
, ec
);
387 else if (is_set(options
, copy_options::create_hard_links
))
388 create_hard_link(from
, to
, ec
);
389 else if (is_directory(t
))
390 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
391 copy_file_options(options
), &from_st
, nullptr, ec
);
394 auto ptr
= exists(t
) ? &to_st
: &from_st
;
395 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
399 // _GLIBCXX_RESOLVE_LIB_DEFECTS
400 // 2682. filesystem::copy() won't create a symlink to a directory
401 else if (is_directory(f
) && create_symlinks
)
402 ec
= std::make_error_code(errc::is_a_directory
);
403 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
404 || options
== copy_options::none
))
407 if (!create_directory(to
, from
, ec
))
409 // set an unused bit in options to disable further recursion
410 if (!is_set(options
, copy_options::recursive
))
411 options
|= static_cast<copy_options
>(4096);
412 for (const directory_entry
& x
: directory_iterator(from
, ec
))
414 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
419 // _GLIBCXX_RESOLVE_LIB_DEFECTS
420 // 2683. filesystem::copy() says "no effects"
424 ec
= std::make_error_code(std::errc::function_not_supported
);
429 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
432 bool result
= copy_file(from
, to
, option
, ec
);
434 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
440 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
443 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
444 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
445 nullptr, nullptr, ec
);
447 ec
= std::make_error_code(std::errc::function_not_supported
);
454 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
457 copy_symlink(existing_symlink
, new_symlink
, ec
);
459 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
460 existing_symlink
, new_symlink
, ec
));
464 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
465 error_code
& ec
) noexcept
467 auto p
= read_symlink(existing_symlink
, ec
);
470 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
473 create_directory_symlink(p
, new_symlink
, ec
);
477 create_symlink(p
, new_symlink
, ec
);
482 fs::create_directories(const path
& p
)
485 bool result
= create_directories(p
, ec
);
487 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
493 fs::create_directories(const path
& p
, error_code
& ec
)
497 ec
= std::make_error_code(errc::invalid_argument
);
501 file_status st
= status(p
, ec
);
502 if (is_directory(st
))
504 else if (ec
&& !status_known(st
))
509 ec
= std::make_error_code(std::errc::not_a_directory
);
513 __glibcxx_assert(st
.type() == file_type::not_found
);
514 // !exists(p) so there must be at least one non-existent component in p.
516 std::stack
<path
> missing
;
519 // Strip any trailing slash
520 if (pp
.has_relative_path() && !pp
.has_filename())
521 pp
= pp
.parent_path();
525 const auto& filename
= pp
.filename();
526 if (is_dot(filename
) || is_dotdot(filename
))
527 pp
= pp
.parent_path();
530 missing
.push(std::move(pp
));
531 if (missing
.size() > 1000) // sanity check
533 ec
= std::make_error_code(std::errc::filename_too_long
);
536 pp
= missing
.top().parent_path();
547 if (!is_directory(st
))
549 ec
= std::make_error_code(std::errc::not_a_directory
);
554 if (ec
&& exists(st
))
557 while (st
.type() == file_type::not_found
);
559 __glibcxx_assert(!missing
.empty());
564 const path
& top
= missing
.top();
565 created
= create_directory(top
, ec
);
570 while (!missing
.empty());
578 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
580 bool created
= false;
581 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
582 posix::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
583 if (posix::mkdir(p
.c_str(), mode
))
585 const int err
= errno
;
586 if (err
!= EEXIST
|| !is_directory(p
, ec
))
587 ec
.assign(err
, std::generic_category());
595 ec
= std::make_error_code(std::errc::function_not_supported
);
602 fs::create_directory(const path
& p
)
605 bool result
= create_directory(p
, ec
);
607 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
613 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
615 return create_dir(p
, perms::all
, ec
);
620 fs::create_directory(const path
& p
, const path
& attributes
)
623 bool result
= create_directory(p
, attributes
, ec
);
625 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
631 fs::create_directory(const path
& p
, const path
& attributes
,
632 error_code
& ec
) noexcept
634 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
636 if (posix::stat(attributes
.c_str(), &st
))
638 ec
.assign(errno
, std::generic_category());
641 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
643 ec
= std::make_error_code(std::errc::function_not_supported
);
650 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
653 create_directory_symlink(to
, new_symlink
, ec
);
655 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
656 to
, new_symlink
, ec
));
660 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
661 error_code
& ec
) noexcept
663 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
664 ec
= std::make_error_code(std::errc::function_not_supported
);
666 create_symlink(to
, new_symlink
, ec
);
672 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
675 create_hard_link(to
, new_hard_link
, ec
);
677 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
678 to
, new_hard_link
, ec
));
682 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
683 error_code
& ec
) noexcept
685 #ifdef _GLIBCXX_HAVE_LINK
686 if (::link(to
.c_str(), new_hard_link
.c_str()))
687 ec
.assign(errno
, std::generic_category());
690 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
691 if (CreateHardLinkW(new_hard_link
.c_str(), to
.c_str(), NULL
))
694 ec
= __last_system_error();
696 ec
= std::make_error_code(std::errc::function_not_supported
);
701 fs::create_symlink(const path
& to
, const path
& new_symlink
)
704 create_symlink(to
, new_symlink
, ec
);
706 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
707 to
, new_symlink
, ec
));
711 fs::create_symlink(const path
& to
, const path
& new_symlink
,
712 error_code
& ec
) noexcept
714 #ifdef _GLIBCXX_HAVE_SYMLINK
715 if (::symlink(to
.c_str(), new_symlink
.c_str()))
716 ec
.assign(errno
, std::generic_category());
720 ec
= std::make_error_code(std::errc::function_not_supported
);
729 path p
= current_path(ec
);
731 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
736 fs::current_path(error_code
& ec
)
739 #if defined _GLIBCXX_HAVE_UNISTD_H && ! defined __AVR__
740 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
741 if (char_ptr cwd
= char_ptr
{posix::getcwd(nullptr, 0)})
747 ec
.assign(errno
, std::generic_category());
750 long path_max
= pathconf(".", _PC_PATH_MAX
);
754 else if (path_max
> 10240)
758 #elif defined(PATH_MAX)
759 size_t size
= PATH_MAX
;
763 for (char_ptr buf
; p
.empty(); size
*= 2)
765 using char_type
= fs::path::value_type
;
766 buf
.reset((char_type
*)malloc(size
* sizeof(char_type
)));
769 if (getcwd(buf
.get(), size
))
774 else if (errno
!= ERANGE
)
776 ec
.assign(errno
, std::generic_category());
782 ec
= std::make_error_code(std::errc::not_enough_memory
);
787 #else // _GLIBCXX_HAVE_UNISTD_H
788 ec
= std::make_error_code(std::errc::function_not_supported
);
794 fs::current_path(const path
& p
)
799 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
803 fs::current_path(const path
& p
, error_code
& ec
) noexcept
805 #ifdef _GLIBCXX_HAVE_UNISTD_H
806 if (posix::chdir(p
.c_str()))
807 ec
.assign(errno
, std::generic_category());
811 ec
= std::make_error_code(std::errc::function_not_supported
);
816 fs::equivalent(const path
& p1
, const path
& p2
)
819 auto result
= equivalent(p1
, p2
, ec
);
821 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
827 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
829 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
833 if (posix::stat(p1
.c_str(), &st1
) == 0)
834 s1
= make_file_status(st1
);
835 else if (is_not_found_errno(errno
))
836 s1
.type(file_type::not_found
);
840 if (posix::stat(p2
.c_str(), &st2
) == 0)
841 s2
= make_file_status(st2
);
842 else if (is_not_found_errno(errno
))
843 s2
.type(file_type::not_found
);
847 if (exists(s1
) && exists(s2
))
849 if (is_other(s1
) && is_other(s2
))
851 ec
= std::__unsupported();
855 if (is_other(s1
) || is_other(s2
))
857 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
858 // st_ino is not set, so can't be used to distinguish files
859 if (st1
.st_mode
!= st2
.st_mode
|| st1
.st_dev
!= st2
.st_dev
)
863 explicit auto_handle(const path
& p_
)
864 : handle(CreateFileW(p_
.c_str(), 0,
865 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
866 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0))
870 { if (*this) CloseHandle(handle
); }
872 explicit operator bool() const
873 { return handle
!= INVALID_HANDLE_VALUE
; }
876 { return GetFileInformationByHandle(handle
, &info
); }
879 BY_HANDLE_FILE_INFORMATION info
;
886 ec
= __last_system_error();
889 if (!h1
.get_info() || !h2
.get_info())
891 ec
= __last_system_error();
894 return h1
.info
.dwVolumeSerialNumber
== h2
.info
.dwVolumeSerialNumber
895 && h1
.info
.nFileIndexHigh
== h2
.info
.nFileIndexHigh
896 && h1
.info
.nFileIndexLow
== h2
.info
.nFileIndexLow
;
898 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
901 else if (!exists(s1
) && !exists(s2
))
902 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
904 ec
.assign(err
, std::generic_category());
909 ec
= std::make_error_code(std::errc::function_not_supported
);
915 fs::file_size(const path
& p
)
918 auto sz
= file_size(p
, ec
);
920 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
926 template<typename Accessor
, typename T
>
928 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
930 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
932 if (posix::stat(p
.c_str(), &st
))
934 ec
.assign(errno
, std::generic_category());
940 ec
= std::make_error_code(std::errc::function_not_supported
);
947 fs::file_size(const path
& p
, error_code
& ec
) noexcept
949 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
952 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
953 S() : type(file_type::not_found
) { }
957 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
958 if (s
.type
== file_type::regular
)
962 if (s
.type
== file_type::directory
)
963 ec
= std::make_error_code(std::errc::is_a_directory
);
965 ec
= std::__unsupported();
968 ec
= std::make_error_code(std::errc::function_not_supported
);
974 fs::hard_link_count(const path
& p
)
977 auto count
= hard_link_count(p
, ec
);
979 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
984 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
986 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
987 return do_stat(p
, ec
, std::mem_fn(&stat_type::st_nlink
),
988 static_cast<uintmax_t>(-1));
990 ec
= std::make_error_code(std::errc::function_not_supported
);
991 return static_cast<uintmax_t>(-1);
996 fs::is_empty(const path
& p
)
999 bool e
= is_empty(p
, ec
);
1001 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1007 fs::is_empty(const path
& p
, error_code
& ec
)
1009 auto s
= status(p
, ec
);
1012 bool empty
= fs::is_directory(s
)
1013 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1014 : fs::file_size(p
, ec
) == 0;
1015 return ec
? false : empty
;
1019 fs::last_write_time(const path
& p
)
1022 auto t
= last_write_time(p
, ec
);
1024 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1029 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1031 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1032 return do_stat(p
, ec
,
1033 [&ec
](const auto& st
) {
1034 return internal_file_clock::from_stat(st
, ec
);
1036 file_time_type::min());
1038 ec
= std::make_error_code(std::errc::function_not_supported
);
1039 return file_time_type::min();
1044 fs::last_write_time(const path
& p
, file_time_type new_time
)
1047 last_write_time(p
, new_time
, ec
);
1049 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1053 fs::last_write_time(const path
& p
,
1054 file_time_type new_time
, error_code
& ec
) noexcept
1056 auto d
= internal_file_clock::_S_to_sys(new_time
).time_since_epoch();
1057 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1058 #if _GLIBCXX_USE_UTIMENSAT
1059 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1060 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
1063 ns
+= chrono::seconds(1);
1065 struct ::timespec ts
[2];
1067 ts
[0].tv_nsec
= UTIME_OMIT
;
1068 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1069 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1070 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1071 ec
.assign(errno
, std::generic_category());
1074 #elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
1075 posix::utimbuf times
;
1076 times
.modtime
= s
.count();
1077 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1079 if (posix::utime(p
.c_str(), ×
))
1080 ec
.assign(errno
, std::generic_category());
1084 ec
= std::make_error_code(std::errc::function_not_supported
);
1089 fs::permissions(const path
& p
, perms prms
, perm_options opts
)
1092 permissions(p
, prms
, opts
, ec
);
1094 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1098 fs::permissions(const path
& p
, perms prms
, perm_options opts
,
1099 error_code
& ec
) noexcept
1101 const bool replace
= is_set(opts
, perm_options::replace
);
1102 const bool add
= is_set(opts
, perm_options::add
);
1103 const bool remove
= is_set(opts
, perm_options::remove
);
1104 const bool nofollow
= is_set(opts
, perm_options::nofollow
);
1105 if (((int)replace
+ (int)add
+ (int)remove
) != 1)
1107 ec
= std::make_error_code(std::errc::invalid_argument
);
1111 prms
&= perms::mask
;
1114 if (add
|| remove
|| nofollow
)
1116 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
1119 auto curr
= st
.permissions();
1123 prms
= curr
& ~prms
;
1127 #if _GLIBCXX_USE_FCHMODAT
1128 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
1129 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
1132 if (nofollow
&& is_symlink(st
))
1133 ec
= std::__unsupported();
1134 else if (posix::chmod(p
.c_str(), static_cast<posix::mode_t
>(prms
)))
1139 ec
.assign(err
, std::generic_category());
1145 fs::proximate(const path
& p
, const path
& base
)
1147 return weakly_canonical(p
).lexically_proximate(weakly_canonical(base
));
1151 fs::proximate(const path
& p
, const path
& base
, error_code
& ec
)
1154 const auto p2
= weakly_canonical(p
, ec
);
1157 const auto base2
= weakly_canonical(base
, ec
);
1159 result
= p2
.lexically_proximate(base2
);
1165 fs::read_symlink(const path
& p
)
1168 path tgt
= read_symlink(p
, ec
);
1170 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1174 fs::path
fs::read_symlink(const path
& p
, error_code
& ec
)
1177 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1179 if (posix::lstat(p
.c_str(), &st
))
1181 ec
.assign(errno
, std::generic_category());
1184 else if (!fs::is_symlink(make_file_status(st
)))
1186 ec
.assign(EINVAL
, std::generic_category());
1190 std::string
buf(st
.st_size
? st
.st_size
+ 1 : 128, '\0');
1193 ssize_t len
= ::readlink(p
.c_str(), buf
.data(), buf
.size());
1196 ec
.assign(errno
, std::generic_category());
1199 else if (len
== (ssize_t
)buf
.size())
1201 if (buf
.size() > 4096)
1203 ec
.assign(ENAMETOOLONG
, std::generic_category());
1206 buf
.resize(buf
.size() * 2);
1218 ec
= std::make_error_code(std::errc::function_not_supported
);
1224 fs::relative(const path
& p
, const path
& base
)
1226 return weakly_canonical(p
).lexically_relative(weakly_canonical(base
));
1230 fs::relative(const path
& p
, const path
& base
, error_code
& ec
)
1232 auto result
= weakly_canonical(p
, ec
);
1235 cbase
= weakly_canonical(base
, ec
);
1237 result
= result
.lexically_relative(cbase
);
1244 fs::remove(const path
& p
)
1247 const bool result
= fs::remove(p
, ec
);
1249 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1254 fs::remove(const path
& p
, error_code
& ec
) noexcept
1256 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1257 auto st
= symlink_status(p
, ec
);
1260 if ((is_directory(p
, ec
) && RemoveDirectoryW(p
.c_str()))
1261 || DeleteFileW(p
.c_str()))
1267 ec
= __last_system_error();
1269 else if (status_known(st
))
1272 if (::remove(p
.c_str()) == 0)
1277 else if (errno
== ENOENT
)
1280 ec
.assign(errno
, std::generic_category());
1286 fs::remove_all(const path
& p
)
1289 uintmax_t count
= 0;
1290 recursive_directory_iterator
dir(p
, directory_options
{64|128}, ec
);
1291 switch (ec
.value()) // N.B. assumes ec.category() == std::generic_category()
1294 // Iterate over the directory removing everything.
1296 const recursive_directory_iterator end
;
1299 dir
.__erase(); // throws on error
1303 // Directory is empty now, will remove it below.
1307 // Our work here is done.
1311 // Not a directory, will remove below.
1315 // An error occurred.
1316 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1319 // Remove p itself, which is either a non-directory or is now empty.
1320 return count
+ fs::remove(p
);
1324 fs::remove_all(const path
& p
, error_code
& ec
)
1326 uintmax_t count
= 0;
1327 recursive_directory_iterator
dir(p
, directory_options
{64|128}, ec
);
1328 switch (ec
.value()) // N.B. assumes ec.category() == std::generic_category()
1331 // Iterate over the directory removing everything.
1333 const recursive_directory_iterator end
;
1342 // Directory is empty now, will remove it below.
1346 // Our work here is done.
1351 // Not a directory, will remove below.
1355 // An error occurred.
1359 // Remove p itself, which is either a non-directory or is now empty.
1360 if (int last
= fs::remove(p
, ec
); !ec
)
1361 return count
+ last
;
1366 fs::rename(const path
& from
, const path
& to
)
1369 rename(from
, to
, ec
);
1371 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1375 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1377 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1378 const auto to_status
= fs::status(to
, ec
);
1379 if (to_status
.type() == file_type::not_found
)
1384 if (fs::exists(to_status
))
1386 const auto from_status
= fs::status(from
, ec
);
1390 if (fs::is_directory(to_status
))
1392 if (!fs::is_directory(from_status
))
1394 // Cannot rename a non-directory over an existing directory.
1395 ec
= std::make_error_code(std::errc::is_a_directory
);
1399 else if (fs::is_directory(from_status
))
1401 // Cannot rename a directory over an existing non-directory.
1402 ec
= std::make_error_code(std::errc::not_a_directory
);
1407 if (posix::rename(from
.c_str(), to
.c_str()))
1408 ec
.assign(errno
, std::generic_category());
1414 fs::resize_file(const path
& p
, uintmax_t size
)
1417 resize_file(p
, size
, ec
);
1419 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1423 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1425 if (size
> static_cast<uintmax_t>(std::numeric_limits
<posix::off_t
>::max()))
1426 ec
.assign(EINVAL
, std::generic_category());
1427 else if (posix::truncate(p
.c_str(), size
))
1428 ec
.assign(errno
, std::generic_category());
1435 fs::space(const path
& p
)
1438 space_info s
= space(p
, ec
);
1440 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1445 fs::space(const path
& p
, error_code
& ec
) noexcept
1448 static_cast<uintmax_t>(-1),
1449 static_cast<uintmax_t>(-1),
1450 static_cast<uintmax_t>(-1)
1452 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1453 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1454 path dir
= absolute(p
);
1455 dir
.remove_filename();
1456 auto str
= dir
.c_str();
1458 auto str
= p
.c_str();
1461 do_space(str
, info
.capacity
, info
.free
, info
.available
, ec
);
1462 #endif // _GLIBCXX_HAVE_SYS_STAT_H
1467 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1469 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1472 auto str
= p
.c_str();
1474 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1475 // stat() fails if there's a trailing slash (PR 88881)
1477 if (p
.has_relative_path() && !p
.has_filename())
1481 p2
= p
.parent_path();
1484 __catch(const bad_alloc
&)
1486 ec
= std::make_error_code(std::errc::not_enough_memory
);
1494 if (posix::stat(str
, &st
))
1497 ec
.assign(err
, std::generic_category());
1498 if (is_not_found_errno(err
))
1499 status
.type(file_type::not_found
);
1501 else if (err
== EOVERFLOW
)
1502 status
.type(file_type::unknown
);
1507 status
= make_file_status(st
);
1514 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1517 auto str
= p
.c_str();
1519 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1520 // stat() fails if there's a trailing slash (PR 88881)
1522 if (p
.has_relative_path() && !p
.has_filename())
1526 p2
= p
.parent_path();
1529 __catch(const bad_alloc
&)
1531 ec
= std::make_error_code(std::errc::not_enough_memory
);
1539 if (posix::lstat(str
, &st
))
1542 ec
.assign(err
, std::generic_category());
1543 if (is_not_found_errno(err
))
1544 status
.type(file_type::not_found
);
1548 status
= make_file_status(st
);
1556 fs::status(const fs::path
& p
)
1559 auto result
= status(p
, ec
);
1560 if (result
.type() == file_type::none
)
1561 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1566 fs::symlink_status(const fs::path
& p
)
1569 auto result
= symlink_status(p
, ec
);
1570 if (result
.type() == file_type::none
)
1571 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1576 fs::temp_directory_path()
1579 path p
= fs::get_temp_directory_from_env(ec
);
1582 auto st
= status(p
, ec
);
1583 if (!ec
&& !is_directory(st
))
1584 ec
= std::make_error_code(std::errc::not_a_directory
);
1589 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1591 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", p
, ec
));
1597 fs::temp_directory_path(error_code
& ec
)
1599 path p
= fs::get_temp_directory_from_env(ec
);
1602 auto st
= status(p
, ec
);
1605 else if (!is_directory(st
))
1608 ec
= std::make_error_code(std::errc::not_a_directory
);
1615 fs::weakly_canonical(const path
& p
)
1618 if (exists(status(p
)))
1619 return canonical(p
);
1622 auto iter
= p
.begin(), end
= p
.end();
1623 // find leading elements of p that exist:
1626 tmp
= result
/ *iter
;
1627 if (exists(status(tmp
)))
1634 if (!result
.empty())
1635 result
= canonical(result
);
1636 // append the non-existing elements:
1640 return result
.lexically_normal();
1644 fs::weakly_canonical(const path
& p
, error_code
& ec
)
1647 file_status st
= status(p
, ec
);
1649 return canonical(p
, ec
);
1650 else if (status_known(st
))
1656 auto iter
= p
.begin(), end
= p
.end();
1657 // find leading elements of p that exist:
1660 tmp
= result
/ *iter
;
1661 st
= status(tmp
, ec
);
1666 if (status_known(st
))
1673 if (!ec
&& !result
.empty())
1674 result
= canonical(result
, ec
);
1679 // append the non-existing elements:
1683 result
= result
.lexically_normal();