1 // Filesystem operations -*- C++ -*-
3 // Copyright (C) 2014-2024 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);
115 buf
.__resize_and_overwrite(len
, [&s
, &len
](wchar_t* p
, unsigned n
) {
116 len
= GetFullPathNameW(s
.data(), n
, p
, nullptr);
117 return len
> n
? 0 : len
;
120 while (len
> buf
.size());
123 ec
= __last_system_error();
125 ret
= std::move(buf
);
127 ret
= current_path(ec
);
135 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
136 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
138 inline bool is_dot(char c
) { return c
== '.'; }
141 inline bool is_dot(const fs::path
& path
)
143 const auto& filename
= path
.native();
144 return filename
.size() == 1 && is_dot(filename
[0]);
147 inline bool is_dotdot(const fs::path
& path
)
149 const auto& filename
= path
.native();
150 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
153 struct free_as_in_malloc
155 void operator()(void* p
) const { ::free(p
); }
158 using char_ptr
= std::unique_ptr
<fs::path::value_type
[], free_as_in_malloc
>;
162 fs::canonical(const path
& p
, error_code
& ec
)
165 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
166 const path pa
= absolute(p
.lexically_normal(), ec
);
168 const path pa
= absolute(p
, ec
);
173 #ifdef _GLIBCXX_USE_REALPATH
174 char_ptr buf
{ nullptr };
175 # if _XOPEN_VERSION < 700
176 // Not safe to call realpath(path, NULL)
177 using char_type
= fs::path::value_type
;
178 buf
.reset( (char_type
*)::malloc(PATH_MAX
* sizeof(char_type
)) );
180 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
188 if (errno
!= ENAMETOOLONG
)
190 ec
.assign(errno
, std::generic_category());
198 ec
= make_error_code(std::errc::no_such_file_or_directory
);
201 // else: we know there are (currently) no unresolvable symlink loops
203 result
= pa
.root_path();
206 for (auto& f
: pa
.relative_path())
209 int max_allowed_symlinks
= 40;
211 while (!cmpts
.empty() && !ec
)
213 path f
= std::move(cmpts
.front());
218 // ignore empty element
222 if (!is_directory(result
, ec
) && !ec
)
223 ec
.assign(ENOTDIR
, std::generic_category());
225 else if (is_dotdot(f
))
227 auto parent
= result
.parent_path();
229 result
= pa
.root_path();
237 if (is_symlink(result
, ec
))
239 path link
= read_symlink(result
, ec
);
242 if (--max_allowed_symlinks
== 0)
243 ec
.assign(ELOOP
, std::generic_category());
246 if (link
.is_absolute())
248 result
= link
.root_path();
249 link
= link
.relative_path();
252 result
= result
.parent_path();
254 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
261 if (ec
|| !exists(result
, ec
))
268 fs::canonical(const path
& p
)
271 path res
= canonical(p
, ec
);
273 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
279 fs::copy(const path
& from
, const path
& to
, copy_options options
)
282 copy(from
, to
, options
, ec
);
284 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
287 namespace std::filesystem
289 // Need this as there's no 'perm_options::none' enumerator.
290 static inline bool is_set(fs::perm_options obj
, fs::perm_options bits
)
292 return (obj
& bits
) != fs::perm_options
{};
298 struct internal_file_clock
: fs::__file_clock
300 using __file_clock::_S_to_sys
;
301 using __file_clock::_S_from_sys
;
303 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
304 static fs::file_time_type
305 from_stat(const fs::stat_type
& st
, std::error_code
& ec
) noexcept
307 const auto sys_time
= fs::file_time(st
, ec
);
308 if (sys_time
== sys_time
.min())
309 return fs::file_time_type::min();
310 return _S_from_sys(sys_time
);
317 fs::copy(const path
& from
, const path
& to
, copy_options options
,
320 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
321 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
322 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
323 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
324 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
327 stat_type from_st
, to_st
;
328 // _GLIBCXX_RESOLVE_LIB_DEFECTS
329 // 2681. filesystem::copy() cannot copy symlinks
330 if (use_lstat
|| copy_symlinks
331 ? posix::lstat(from
.c_str(), &from_st
)
332 : posix::stat(from
.c_str(), &from_st
))
334 ec
.assign(errno
, std::generic_category());
338 ? posix::lstat(to
.c_str(), &to_st
)
339 : posix::stat(to
.c_str(), &to_st
))
341 if (!is_not_found_errno(errno
))
343 ec
.assign(errno
, std::generic_category());
346 t
= file_status
{file_type::not_found
};
349 t
= make_file_status(to_st
);
350 f
= make_file_status(from_st
);
352 if (exists(t
) && !is_other(t
) && !is_other(f
)
353 && fs::equiv_files(from
.c_str(), from_st
, to
.c_str(), to_st
, ec
))
355 ec
= std::make_error_code(std::errc::file_exists
);
358 if (is_other(f
) || is_other(t
))
360 ec
= std::make_error_code(std::errc::invalid_argument
);
363 if (is_directory(f
) && is_regular_file(t
))
365 ec
= std::make_error_code(std::errc::is_a_directory
);
373 else if (!exists(t
) && copy_symlinks
)
374 copy_symlink(from
, to
, ec
);
376 // Not clear what should be done here.
377 // "Otherwise report an error as specified in Error reporting (7)."
378 ec
= std::make_error_code(std::errc::invalid_argument
);
380 else if (is_regular_file(f
))
382 if (is_set(options
, copy_options::directories_only
))
384 else if (create_symlinks
)
385 create_symlink(from
, to
, ec
);
386 else if (is_set(options
, copy_options::create_hard_links
))
387 create_hard_link(from
, to
, ec
);
388 else if (is_directory(t
))
389 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
390 copy_file_options(options
), &from_st
, nullptr, ec
);
393 auto ptr
= exists(t
) ? &to_st
: &from_st
;
394 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
398 // _GLIBCXX_RESOLVE_LIB_DEFECTS
399 // 2682. filesystem::copy() won't create a symlink to a directory
400 else if (is_directory(f
) && create_symlinks
)
401 ec
= std::make_error_code(errc::is_a_directory
);
402 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
403 || options
== copy_options::none
))
406 if (!create_directory(to
, from
, ec
))
408 // set an unused bit in options to disable further recursion
409 if (!is_set(options
, copy_options::recursive
))
410 options
|= static_cast<copy_options
>(4096);
411 for (const directory_entry
& x
: directory_iterator(from
, ec
))
413 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
418 // _GLIBCXX_RESOLVE_LIB_DEFECTS
419 // 2683. filesystem::copy() says "no effects"
423 ec
= std::make_error_code(std::errc::function_not_supported
);
428 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
431 bool result
= copy_file(from
, to
, option
, ec
);
433 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
439 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
442 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
443 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
444 nullptr, nullptr, ec
);
446 ec
= std::make_error_code(std::errc::function_not_supported
);
453 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
456 copy_symlink(existing_symlink
, new_symlink
, ec
);
458 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
459 existing_symlink
, new_symlink
, ec
));
463 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
464 error_code
& ec
) noexcept
466 auto p
= read_symlink(existing_symlink
, ec
);
469 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
472 create_directory_symlink(p
, new_symlink
, ec
);
476 create_symlink(p
, new_symlink
, ec
);
481 fs::create_directories(const path
& p
)
484 bool result
= create_directories(p
, ec
);
486 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
492 fs::create_directories(const path
& p
, error_code
& ec
)
496 ec
= std::make_error_code(errc::invalid_argument
);
500 file_status st
= status(p
, ec
);
501 if (is_directory(st
))
503 else if (ec
&& !status_known(st
))
508 ec
= std::make_error_code(std::errc::not_a_directory
);
512 __glibcxx_assert(st
.type() == file_type::not_found
);
513 // !exists(p) so there must be at least one non-existent component in p.
515 std::stack
<path
> missing
;
518 // Strip any trailing slash
519 if (pp
.has_relative_path() && !pp
.has_filename())
520 pp
= pp
.parent_path();
524 const auto& filename
= pp
.filename();
525 if (is_dot(filename
) || is_dotdot(filename
))
526 pp
= pp
.parent_path();
529 missing
.push(std::move(pp
));
530 if (missing
.size() > 1000) // sanity check
532 ec
= std::make_error_code(std::errc::filename_too_long
);
535 pp
= missing
.top().parent_path();
546 if (!is_directory(st
))
548 ec
= std::make_error_code(std::errc::not_a_directory
);
553 if (ec
&& exists(st
))
556 while (st
.type() == file_type::not_found
);
558 __glibcxx_assert(!missing
.empty());
563 const path
& top
= missing
.top();
564 created
= create_directory(top
, ec
);
569 while (!missing
.empty());
577 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
579 bool created
= false;
580 #if _GLIBCXX_USE_MKDIR
581 posix::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
582 if (posix::mkdir(p
.c_str(), mode
))
584 const int err
= errno
;
585 if (err
!= EEXIST
|| !is_directory(p
, ec
))
586 ec
.assign(err
, std::generic_category());
594 ec
= std::make_error_code(std::errc::function_not_supported
);
601 fs::create_directory(const path
& p
)
604 bool result
= create_directory(p
, ec
);
606 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
612 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
614 return create_dir(p
, perms::all
, ec
);
619 fs::create_directory(const path
& p
, const path
& attributes
)
622 bool result
= create_directory(p
, attributes
, ec
);
624 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
630 fs::create_directory(const path
& p
, const path
& attributes
,
631 error_code
& ec
) noexcept
633 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
635 if (posix::stat(attributes
.c_str(), &st
))
637 ec
.assign(errno
, std::generic_category());
640 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
642 ec
= std::make_error_code(std::errc::function_not_supported
);
649 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
652 create_directory_symlink(to
, new_symlink
, ec
);
654 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
655 to
, new_symlink
, ec
));
659 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
660 error_code
& ec
) noexcept
662 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
663 ec
= std::make_error_code(std::errc::function_not_supported
);
665 create_symlink(to
, new_symlink
, ec
);
671 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
674 create_hard_link(to
, new_hard_link
, ec
);
676 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
677 to
, new_hard_link
, ec
));
681 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
682 error_code
& ec
) noexcept
684 #ifdef _GLIBCXX_HAVE_LINK
685 if (::link(to
.c_str(), new_hard_link
.c_str()))
686 ec
.assign(errno
, std::generic_category());
689 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
690 if (CreateHardLinkW(new_hard_link
.c_str(), to
.c_str(), NULL
))
693 ec
= __last_system_error();
695 ec
= std::make_error_code(std::errc::function_not_supported
);
700 fs::create_symlink(const path
& to
, const path
& new_symlink
)
703 create_symlink(to
, new_symlink
, ec
);
705 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
706 to
, new_symlink
, ec
));
710 fs::create_symlink(const path
& to
, const path
& new_symlink
,
711 error_code
& ec
) noexcept
713 #ifdef _GLIBCXX_HAVE_SYMLINK
714 if (::symlink(to
.c_str(), new_symlink
.c_str()))
715 ec
.assign(errno
, std::generic_category());
719 ec
= std::make_error_code(std::errc::function_not_supported
);
728 path p
= current_path(ec
);
730 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
735 fs::current_path(error_code
& ec
)
738 #if _GLIBCXX_USE_GETCWD
739 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
740 if (char_ptr cwd
= char_ptr
{posix::getcwd(nullptr, 0)})
746 ec
.assign(errno
, std::generic_category());
749 long path_max
= pathconf(".", _PC_PATH_MAX
);
753 else if (path_max
> 10240)
757 #elif defined(PATH_MAX)
758 size_t size
= PATH_MAX
;
762 for (char_ptr buf
; p
.empty(); size
*= 2)
764 using char_type
= fs::path::value_type
;
765 buf
.reset((char_type
*)malloc(size
* sizeof(char_type
)));
768 if (getcwd(buf
.get(), size
))
773 else if (errno
!= ERANGE
)
775 ec
.assign(errno
, std::generic_category());
781 ec
= std::make_error_code(std::errc::not_enough_memory
);
786 #else // _GLIBCXX_USE_GETCWD
787 ec
= std::make_error_code(std::errc::function_not_supported
);
793 fs::current_path(const path
& p
)
798 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
802 fs::current_path(const path
& p
, error_code
& ec
) noexcept
804 #if _GLIBCXX_USE_CHDIR
805 if (posix::chdir(p
.c_str()))
806 ec
.assign(errno
, std::generic_category());
810 ec
= std::make_error_code(std::errc::function_not_supported
);
815 fs::equivalent(const path
& p1
, const path
& p2
)
818 auto result
= equivalent(p1
, p2
, ec
);
820 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
825 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
828 // An RAII type that opens a handle for an existing file.
829 struct auto_win_file_handle
832 auto_win_file_handle(const wchar_t* p
, std::error_code
& ec
) noexcept
833 : handle(CreateFileW(p
, 0,
834 FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
,
835 0, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0)),
838 if (handle
== INVALID_HANDLE_VALUE
)
839 ec
= std::__last_system_error();
842 ~auto_win_file_handle()
843 { if (*this) CloseHandle(handle
); }
845 explicit operator bool() const noexcept
846 { return handle
!= INVALID_HANDLE_VALUE
; }
848 bool get_info() noexcept
850 if (GetFileInformationByHandle(handle
, &info
))
852 ec
= std::__last_system_error();
857 BY_HANDLE_FILE_INFORMATION info
;
858 // Like errno, we only set this on error and never clear it.
859 // This propagates an error_code to the caller when something goes wrong,
860 // but the caller should not assume a non-zero ec means an error happened
861 // unless they explicitly cleared it before passing it to our constructor.
867 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
868 #ifdef NEED_DO_COPY_FILE // Only define this once, not in cow-fs_ops.o too
870 fs::equiv_files([[maybe_unused
]] const char_type
* p1
, const stat_type
& st1
,
871 [[maybe_unused
]] const char_type
* p2
, const stat_type
& st2
,
872 [[maybe_unused
]] error_code
& ec
)
874 #if ! _GLIBCXX_FILESYSTEM_IS_WINDOWS
875 // For POSIX the device ID and inode number uniquely identify a file.
876 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
878 // For Windows st_ino is not set, so can't be used to distinguish files.
879 // We can compare modes and device IDs as a cheap initial check:
880 if (st1
.st_mode
!= st2
.st_mode
|| st1
.st_dev
!= st2
.st_dev
)
883 // Use GetFileInformationByHandle to get more info about the files.
884 if (auto_win_file_handle h1
{p1
, ec
})
885 if (auto_win_file_handle h2
{p2
, ec
})
886 if (h1
.get_info() && h2
.get_info())
887 return h1
.info
.dwVolumeSerialNumber
== h2
.info
.dwVolumeSerialNumber
888 && h1
.info
.nFileIndexHigh
== h2
.info
.nFileIndexHigh
889 && h1
.info
.nFileIndexLow
== h2
.info
.nFileIndexLow
;
891 #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
893 #endif // NEED_DO_COPY_FILE
894 #endif // _GLIBCXX_HAVE_SYS_STAT_H
897 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
899 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
903 if (posix::stat(p1
.c_str(), &st1
) == 0)
904 s1
= make_file_status(st1
);
905 else if (is_not_found_errno(errno
))
906 s1
.type(file_type::not_found
);
910 if (posix::stat(p2
.c_str(), &st2
) == 0)
911 s2
= make_file_status(st2
);
912 else if (is_not_found_errno(errno
))
913 s2
.type(file_type::not_found
);
917 if (exists(s1
) && exists(s2
))
919 if (is_other(s1
) && is_other(s2
))
921 ec
= std::__unsupported();
925 if (is_other(s1
) || is_other(s2
))
927 return fs::equiv_files(p1
.c_str(), st1
, p2
.c_str(), st2
, ec
);
929 else if (!exists(s1
) || !exists(s2
))
930 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
932 ec
.assign(err
, std::generic_category());
937 ec
= std::make_error_code(std::errc::function_not_supported
);
943 fs::file_size(const path
& p
)
946 auto sz
= file_size(p
, ec
);
948 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
954 template<typename Accessor
, typename T
>
956 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
958 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
960 if (posix::stat(p
.c_str(), &st
))
962 ec
.assign(errno
, std::generic_category());
968 ec
= std::make_error_code(std::errc::function_not_supported
);
975 fs::file_size(const path
& p
, error_code
& ec
) noexcept
977 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
980 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
981 S() : type(file_type::not_found
) { }
985 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
986 if (s
.type
== file_type::regular
)
990 if (s
.type
== file_type::directory
)
991 ec
= std::make_error_code(std::errc::is_a_directory
);
993 ec
= std::__unsupported();
996 ec
= std::make_error_code(std::errc::function_not_supported
);
1002 fs::hard_link_count(const path
& p
)
1005 auto count
= hard_link_count(p
, ec
);
1007 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
1012 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
1014 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1015 auto_win_file_handle
h(p
.c_str(), ec
);
1016 if (h
&& h
.get_info())
1019 return static_cast<uintmax_t>(h
.info
.nNumberOfLinks
);
1021 return static_cast<uintmax_t>(-1);
1022 #elif defined _GLIBCXX_HAVE_SYS_STAT_H
1023 return do_stat(p
, ec
, std::mem_fn(&stat_type::st_nlink
),
1024 static_cast<uintmax_t>(-1));
1026 ec
= std::make_error_code(std::errc::function_not_supported
);
1027 return static_cast<uintmax_t>(-1);
1032 fs::is_empty(const path
& p
)
1035 bool e
= is_empty(p
, ec
);
1037 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1043 fs::is_empty(const path
& p
, error_code
& ec
)
1045 auto s
= status(p
, ec
);
1048 bool empty
= fs::is_directory(s
)
1049 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
1050 : fs::file_size(p
, ec
) == 0;
1051 return ec
? false : empty
;
1055 fs::last_write_time(const path
& p
)
1058 auto t
= last_write_time(p
, ec
);
1060 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
1065 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
1067 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1068 return do_stat(p
, ec
,
1069 [&ec
](const auto& st
) {
1070 return internal_file_clock::from_stat(st
, ec
);
1072 file_time_type::min());
1074 ec
= std::make_error_code(std::errc::function_not_supported
);
1075 return file_time_type::min();
1080 fs::last_write_time(const path
& p
, file_time_type new_time
)
1083 last_write_time(p
, new_time
, ec
);
1085 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
1089 fs::last_write_time(const path
& p
,
1090 file_time_type new_time
, error_code
& ec
) noexcept
1092 auto d
= internal_file_clock::_S_to_sys(new_time
).time_since_epoch();
1093 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
1094 #if _GLIBCXX_USE_UTIMENSAT
1095 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
1096 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
1099 ns
+= chrono::seconds(1);
1101 struct ::timespec ts
[2];
1103 ts
[0].tv_nsec
= UTIME_OMIT
;
1104 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
1105 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
1106 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
1107 ec
.assign(errno
, std::generic_category());
1110 #elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
1111 posix::utimbuf times
;
1112 times
.modtime
= s
.count();
1113 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
1115 if (posix::utime(p
.c_str(), ×
))
1116 ec
.assign(errno
, std::generic_category());
1120 ec
= std::make_error_code(std::errc::function_not_supported
);
1125 fs::permissions(const path
& p
, perms prms
, perm_options opts
)
1128 permissions(p
, prms
, opts
, ec
);
1130 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
1134 fs::permissions(const path
& p
, perms prms
, perm_options opts
,
1135 error_code
& ec
) noexcept
1137 #if _GLIBCXX_USE_FCHMODAT || _GLIBCXX_USE_CHMOD
1138 const bool replace
= is_set(opts
, perm_options::replace
);
1139 const bool add
= is_set(opts
, perm_options::add
);
1140 const bool remove
= is_set(opts
, perm_options::remove
);
1141 const bool nofollow
= is_set(opts
, perm_options::nofollow
);
1142 if (((int)replace
+ (int)add
+ (int)remove
) != 1)
1144 ec
= std::make_error_code(std::errc::invalid_argument
);
1148 prms
&= perms::mask
;
1151 if (add
|| remove
|| nofollow
)
1153 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
1156 auto curr
= st
.permissions();
1160 prms
= curr
& ~prms
;
1164 #if _GLIBCXX_USE_FCHMODAT
1165 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
1166 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
1169 if (nofollow
&& is_symlink(st
))
1170 ec
= std::__unsupported();
1171 else if (posix::chmod(p
.c_str(), static_cast<posix::mode_t
>(prms
)))
1176 ec
.assign(err
, std::generic_category());
1180 ec
= std::make_error_code(std::errc::function_not_supported
);
1185 fs::proximate(const path
& p
, const path
& base
)
1187 return weakly_canonical(p
).lexically_proximate(weakly_canonical(base
));
1191 fs::proximate(const path
& p
, const path
& base
, error_code
& ec
)
1194 const auto p2
= weakly_canonical(p
, ec
);
1197 const auto base2
= weakly_canonical(base
, ec
);
1199 result
= p2
.lexically_proximate(base2
);
1205 fs::read_symlink(const path
& p
)
1208 path tgt
= read_symlink(p
, ec
);
1210 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1214 fs::path
fs::read_symlink(const path
& p
, error_code
& ec
)
1217 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1219 if (posix::lstat(p
.c_str(), &st
))
1221 ec
.assign(errno
, std::generic_category());
1224 else if (!fs::is_symlink(make_file_status(st
)))
1226 ec
.assign(EINVAL
, std::generic_category());
1231 size_t bufsz
= st
.st_size
? st
.st_size
+ 1 : 128;
1235 buf
.__resize_and_overwrite(bufsz
, [&p
, &len
](char* ptr
, size_t n
) {
1236 len
= ::readlink(p
.c_str(), ptr
, n
);
1237 return size_t(len
) < n
? len
: 0;
1241 result
.assign(std::move(buf
));
1247 ec
.assign(errno
, std::generic_category());
1250 else if (bufsz
> 4096)
1252 ec
.assign(ENAMETOOLONG
, std::generic_category());
1260 ec
= std::make_error_code(std::errc::function_not_supported
);
1266 fs::relative(const path
& p
, const path
& base
)
1268 return weakly_canonical(p
).lexically_relative(weakly_canonical(base
));
1272 fs::relative(const path
& p
, const path
& base
, error_code
& ec
)
1274 auto result
= weakly_canonical(p
, ec
);
1277 cbase
= weakly_canonical(base
, ec
);
1279 result
= result
.lexically_relative(cbase
);
1286 fs::remove(const path
& p
)
1289 const bool result
= fs::remove(p
, ec
);
1291 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1296 fs::remove(const path
& p
, error_code
& ec
) noexcept
1298 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1299 auto st
= symlink_status(p
, ec
);
1302 if ((is_directory(p
, ec
) && RemoveDirectoryW(p
.c_str()))
1303 || DeleteFileW(p
.c_str()))
1309 ec
= __last_system_error();
1311 else if (status_known(st
))
1314 if (::remove(p
.c_str()) == 0)
1319 else if (errno
== ENOENT
)
1322 ec
.assign(errno
, std::generic_category());
1328 fs::remove_all(const path
& p
)
1331 uintmax_t count
= 0;
1332 recursive_directory_iterator
dir(p
, directory_options
{64|128}, ec
);
1333 switch (ec
.value()) // N.B. assumes ec.category() == std::generic_category()
1336 // Iterate over the directory removing everything.
1338 const recursive_directory_iterator end
;
1341 dir
.__erase(); // throws on error
1345 // Directory is empty now, will remove it below.
1349 // Our work here is done.
1352 case ELOOP
: // POSIX says openat with O_NOFOLLOW sets ELOOP for a symlink.
1353 #if defined __FreeBSD__ || defined __DragonFly__
1354 case EMLINK
: // Used instead of ELOOP
1356 #if defined __NetBSD__ && defined EFTYPE
1357 case EFTYPE
: // Used instead of ELOOP
1359 // Not a directory, will remove below.
1363 // An error occurred.
1364 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1367 // Remove p itself, which is either a non-directory or is now empty.
1368 return count
+ fs::remove(p
);
1372 fs::remove_all(const path
& p
, error_code
& ec
)
1374 uintmax_t count
= 0;
1375 recursive_directory_iterator
dir(p
, directory_options
{64|128}, ec
);
1376 switch (ec
.value()) // N.B. assumes ec.category() == std::generic_category()
1379 // Iterate over the directory removing everything.
1381 const recursive_directory_iterator end
;
1390 // Directory is empty now, will remove it below.
1394 // Our work here is done.
1398 case ELOOP
: // POSIX says openat with O_NOFOLLOW sets ELOOP for a symlink.
1399 #if defined __FreeBSD__ || defined __DragonFly__
1400 case EMLINK
: // Used instead of ELOOP
1402 #if defined __NetBSD__ && defined EFTYPE
1403 case EFTYPE
: // Used instead of ELOOP
1405 // Not a directory, will remove below.
1409 // An error occurred.
1413 // Remove p itself, which is either a non-directory or is now empty.
1414 if (int last
= fs::remove(p
, ec
); !ec
)
1415 return count
+ last
;
1420 fs::rename(const path
& from
, const path
& to
)
1423 rename(from
, to
, ec
);
1425 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1429 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1431 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1432 const auto to_status
= fs::status(to
, ec
);
1433 if (to_status
.type() == file_type::not_found
)
1438 if (fs::exists(to_status
))
1440 const auto from_status
= fs::status(from
, ec
);
1444 if (fs::is_directory(to_status
))
1446 if (!fs::is_directory(from_status
))
1448 // Cannot rename a non-directory over an existing directory.
1449 ec
= std::make_error_code(std::errc::is_a_directory
);
1453 else if (fs::is_directory(from_status
))
1455 // Cannot rename a directory over an existing non-directory.
1456 ec
= std::make_error_code(std::errc::not_a_directory
);
1461 if (posix::rename(from
.c_str(), to
.c_str()))
1462 ec
.assign(errno
, std::generic_category());
1468 fs::resize_file(const path
& p
, uintmax_t size
)
1471 resize_file(p
, size
, ec
);
1473 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1477 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1479 if (size
> static_cast<uintmax_t>(std::numeric_limits
<posix::off_t
>::max()))
1480 ec
.assign(EINVAL
, std::generic_category());
1481 else if (posix::truncate(p
.c_str(), size
))
1482 ec
.assign(errno
, std::generic_category());
1489 fs::space(const path
& p
)
1492 space_info s
= space(p
, ec
);
1494 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
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 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1507 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1508 path dir
= absolute(p
);
1509 dir
.remove_filename();
1510 auto str
= dir
.c_str();
1512 auto str
= p
.c_str();
1515 do_space(str
, info
.capacity
, info
.free
, info
.available
, ec
);
1516 #endif // _GLIBCXX_HAVE_SYS_STAT_H
1521 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1523 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1526 auto str
= p
.c_str();
1528 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1529 // stat() fails if there's a trailing slash (PR 88881)
1531 if (p
.has_relative_path() && !p
.has_filename())
1535 p2
= p
.parent_path();
1538 __catch(const bad_alloc
&)
1540 ec
= std::make_error_code(std::errc::not_enough_memory
);
1548 if (posix::stat(str
, &st
))
1551 ec
.assign(err
, std::generic_category());
1552 if (is_not_found_errno(err
))
1553 status
.type(file_type::not_found
);
1555 else if (err
== EOVERFLOW
)
1556 status
.type(file_type::unknown
);
1561 status
= make_file_status(st
);
1568 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1571 auto str
= p
.c_str();
1573 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1574 // stat() fails if there's a trailing slash (PR 88881)
1576 if (p
.has_relative_path() && !p
.has_filename())
1580 p2
= p
.parent_path();
1583 __catch(const bad_alloc
&)
1585 ec
= std::make_error_code(std::errc::not_enough_memory
);
1593 if (posix::lstat(str
, &st
))
1596 ec
.assign(err
, std::generic_category());
1597 if (is_not_found_errno(err
))
1598 status
.type(file_type::not_found
);
1602 status
= make_file_status(st
);
1610 fs::status(const fs::path
& p
)
1613 auto result
= status(p
, ec
);
1614 if (result
.type() == file_type::none
)
1615 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1620 fs::symlink_status(const fs::path
& p
)
1623 auto result
= symlink_status(p
, ec
);
1624 if (result
.type() == file_type::none
)
1625 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1630 fs::temp_directory_path()
1633 path p
= fs::get_temp_directory_from_env(ec
);
1636 auto st
= status(p
, ec
);
1637 if (!ec
&& !is_directory(st
))
1638 ec
= std::make_error_code(std::errc::not_a_directory
);
1643 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1645 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", p
, ec
));
1651 fs::temp_directory_path(error_code
& ec
)
1653 path p
= fs::get_temp_directory_from_env(ec
);
1656 auto st
= status(p
, ec
);
1659 else if (!is_directory(st
))
1662 ec
= std::make_error_code(std::errc::not_a_directory
);
1669 fs::weakly_canonical(const path
& p
)
1672 if (exists(status(p
)))
1673 return canonical(p
);
1676 auto iter
= p
.begin(), end
= p
.end();
1677 // find leading elements of p that exist:
1680 tmp
= result
/ *iter
;
1681 if (exists(status(tmp
)))
1688 if (!result
.empty())
1689 result
= canonical(result
);
1690 // append the non-existing elements:
1694 return result
.lexically_normal();
1698 fs::weakly_canonical(const path
& p
, error_code
& ec
)
1701 file_status st
= status(p
, ec
);
1703 return canonical(p
, ec
);
1704 else if (status_known(st
))
1710 auto iter
= p
.begin(), end
= p
.end();
1711 // find leading elements of p that exist:
1714 tmp
= result
/ *iter
;
1715 st
= status(tmp
, ec
);
1720 if (status_known(st
))
1727 if (!ec
&& !result
.empty())
1728 result
= canonical(result
, ec
);
1733 // append the non-existing elements:
1737 result
= result
.lexically_normal();