1 // Filesystem TS operations -*- C++ -*-
3 // Copyright (C) 2014-2025 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>
36 #include <experimental/filesystem>
40 #include <ext/stdio_filebuf.h>
44 #include <limits.h> // PATH_MAX
45 #ifdef _GLIBCXX_HAVE_FCNTL_H
46 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
48 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
49 # include <sys/stat.h> // stat, utimensat, fchmodat
51 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
52 # include <sys/statvfs.h> // statvfs
54 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
55 # include <utime.h> // utime
57 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
58 # define WIN32_LEAN_AND_MEAN
62 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
63 namespace experimental { namespace filesystem {
64 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
65 #include "ops-common.h"
67 #include <filesystem> // std::filesystem::remove_all
69 namespace fs
= std::experimental::filesystem
;
70 namespace posix
= std::filesystem::__gnu_posix
;
73 fs::absolute(const path
& p
, const path
& base
)
75 const bool has_root_dir
= p
.has_root_directory();
76 const bool has_root_name
= p
.has_root_name();
78 if (has_root_dir
&& has_root_name
)
82 abs
= base
.is_absolute() ? base
: absolute(base
);
84 abs
= abs
.root_name() / p
;
85 else if (has_root_name
)
86 abs
= p
.root_name() / abs
.root_directory() / abs
.relative_path()
96 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
97 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
99 inline bool is_dot(char c
) { return c
== '.'; }
102 inline bool is_dot(const fs::path
& path
)
104 const auto& filename
= path
.native();
105 return filename
.size() == 1 && is_dot(filename
[0]);
108 inline bool is_dotdot(const fs::path
& path
)
110 const auto& filename
= path
.native();
111 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
114 struct free_as_in_malloc
116 void operator()(void* p
) const { ::free(p
); }
119 using char_ptr
= std::unique_ptr
<fs::path::value_type
[], free_as_in_malloc
>;
123 fs::canonical(const path
& p
, const path
& base
, error_code
& ec
)
125 const path pa
= absolute(p
, base
);
128 #ifdef _GLIBCXX_USE_REALPATH
129 char_ptr buf
{ nullptr };
130 # if _XOPEN_VERSION < 700
131 // Not safe to call realpath(path, NULL)
132 using char_type
= fs::path::value_type
;
133 buf
.reset( (char_type
*)::malloc(PATH_MAX
* sizeof(char_type
)) );
135 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
143 if (errno
!= ENAMETOOLONG
)
145 ec
.assign(errno
, std::generic_category());
153 ec
= make_error_code(std::errc::no_such_file_or_directory
);
156 // else: we know there are (currently) no unresolvable symlink loops
158 result
= pa
.root_path();
161 for (auto& f
: pa
.relative_path())
164 int max_allowed_symlinks
= 40;
166 while (!cmpts
.empty() && !ec
)
168 path f
= std::move(cmpts
.front());
173 if (!is_directory(result
, ec
) && !ec
)
174 ec
.assign(ENOTDIR
, std::generic_category());
176 else if (is_dotdot(f
))
178 auto parent
= result
.parent_path();
180 result
= pa
.root_path();
188 if (is_symlink(result
, ec
))
190 path link
= read_symlink(result
, ec
);
193 if (--max_allowed_symlinks
== 0)
194 ec
.assign(ELOOP
, std::generic_category());
197 if (link
.is_absolute())
199 result
= link
.root_path();
200 link
= link
.relative_path();
203 result
.remove_filename();
205 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
212 if (ec
|| !exists(result
, ec
))
219 fs::canonical(const path
& p
, error_code
& ec
)
221 path cur
= current_path(ec
);
224 return canonical(p
, cur
, ec
);
228 fs::canonical(const path
& p
, const path
& base
)
231 path can
= canonical(p
, base
, ec
);
233 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p
, base
,
239 fs::copy(const path
& from
, const path
& to
, copy_options options
)
242 copy(from
, to
, options
, ec
);
244 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
249 using std::filesystem::is_set
;
251 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
252 using posix::stat_type
;
254 using std::filesystem::is_not_found_errno
;
255 using std::filesystem::file_time
;
256 #endif // _GLIBCXX_HAVE_SYS_STAT_H
260 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
261 #ifdef NEED_DO_COPY_FILE // Only define this once, not in cow-ops.o too
263 fs::equiv_files([[maybe_unused
]] const char_type
* p1
, const stat_type
& st1
,
264 [[maybe_unused
]] const char_type
* p2
, const stat_type
& st2
,
265 [[maybe_unused
]] error_code
& ec
)
267 // For POSIX the device ID and inode number uniquely identify a file.
268 // This doesn't work on Windows (see equiv_files in src/c++17/fs_ops.cc).
269 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
275 fs::copy(const path
& from
, const path
& to
, copy_options options
,
276 error_code
& ec
) noexcept
278 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
279 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
280 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
281 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
284 stat_type from_st
, to_st
;
285 // _GLIBCXX_RESOLVE_LIB_DEFECTS
286 // 2681. filesystem::copy() cannot copy symlinks
287 if (use_lstat
|| copy_symlinks
288 ? posix::lstat(from
.c_str(), &from_st
)
289 : posix::stat(from
.c_str(), &from_st
))
291 ec
.assign(errno
, std::generic_category());
295 ? posix::lstat(to
.c_str(), &to_st
)
296 : posix::stat(to
.c_str(), &to_st
))
298 if (!is_not_found_errno(errno
))
300 ec
.assign(errno
, std::generic_category());
303 t
= file_status
{file_type::not_found
};
306 t
= make_file_status(to_st
);
307 f
= make_file_status(from_st
);
309 if (exists(t
) && !is_other(t
) && !is_other(f
)
310 && fs::equiv_files(from
.c_str(), from_st
, to
.c_str(), to_st
, ec
))
312 ec
= std::make_error_code(std::errc::file_exists
);
315 if (is_other(f
) || is_other(t
))
317 ec
= std::make_error_code(std::errc::invalid_argument
);
320 if (is_directory(f
) && is_regular_file(t
))
322 ec
= std::make_error_code(std::errc::is_a_directory
);
330 else if (!exists(t
) && copy_symlinks
)
331 copy_symlink(from
, to
, ec
);
333 // Not clear what should be done here.
334 // "Otherwise report an error as specified in Error reporting (7)."
335 ec
= std::make_error_code(std::errc::invalid_argument
);
337 else if (is_regular_file(f
))
339 if (is_set(options
, copy_options::directories_only
))
341 else if (create_symlinks
)
342 create_symlink(from
, to
, ec
);
343 else if (is_set(options
, copy_options::create_hard_links
))
344 create_hard_link(from
, to
, ec
);
345 else if (is_directory(t
))
346 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
347 copy_file_options(options
), &from_st
, nullptr, ec
);
350 auto ptr
= exists(t
) ? &to_st
: &from_st
;
351 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
355 // _GLIBCXX_RESOLVE_LIB_DEFECTS
356 // 2682. filesystem::copy() won't create a symlink to a directory
357 else if (is_directory(f
) && create_symlinks
)
358 ec
= std::make_error_code(errc::is_a_directory
);
359 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
360 || options
== copy_options::none
))
363 if (!create_directory(to
, from
, ec
))
365 // set an unused bit in options to disable further recursion
366 if (!is_set(options
, copy_options::recursive
))
367 options
|= static_cast<copy_options
>(4096);
368 for (const directory_entry
& x
: directory_iterator(from
, ec
))
370 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
375 // _GLIBCXX_RESOLVE_LIB_DEFECTS
376 // 2683. filesystem::copy() says "no effects"
382 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
385 bool result
= copy_file(from
, to
, option
, ec
);
387 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
393 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
396 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
397 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
398 nullptr, nullptr, ec
);
400 ec
= std::make_error_code(std::errc::function_not_supported
);
407 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
410 copy_symlink(existing_symlink
, new_symlink
, ec
);
412 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
413 existing_symlink
, new_symlink
, ec
));
417 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
418 error_code
& ec
) noexcept
420 auto p
= read_symlink(existing_symlink
, ec
);
423 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
426 create_directory_symlink(p
, new_symlink
, ec
);
430 create_symlink(p
, new_symlink
, ec
);
435 fs::create_directories(const path
& p
)
438 bool result
= create_directories(p
, ec
);
440 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
446 fs::create_directories(const path
& p
, error_code
& ec
)
450 ec
= std::make_error_code(errc::invalid_argument
);
454 file_status st
= status(p
, ec
);
455 if (is_directory(st
))
457 else if (ec
&& !status_known(st
))
462 ec
= std::make_error_code(std::errc::not_a_directory
);
466 std::stack
<path
> missing
;
469 while (!pp
.empty() && status(pp
, ec
).type() == file_type::not_found
)
472 const auto& filename
= pp
.filename();
473 if (!is_dot(filename
) && !is_dotdot(filename
))
475 missing
.push(std::move(pp
));
476 pp
= missing
.top().parent_path();
479 pp
= pp
.parent_path();
482 if (ec
|| missing
.empty())
488 const path
& top
= missing
.top();
489 created
= create_directory(top
, ec
);
494 while (!missing
.empty());
502 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
504 bool created
= false;
505 #if _GLIBCXX_USE_MKDIR
506 posix::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
507 if (posix::mkdir(p
.c_str(), mode
))
509 const int err
= errno
;
510 if (err
!= EEXIST
|| !is_directory(p
, ec
))
511 ec
.assign(err
, std::generic_category());
519 ec
= std::make_error_code(std::errc::function_not_supported
);
526 fs::create_directory(const path
& p
)
529 bool result
= create_directory(p
, ec
);
531 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
537 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
539 return create_dir(p
, perms::all
, ec
);
544 fs::create_directory(const path
& p
, const path
& attributes
)
547 bool result
= create_directory(p
, attributes
, ec
);
549 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
555 fs::create_directory(const path
& p
, const path
& attributes
,
556 error_code
& ec
) noexcept
558 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
560 if (posix::stat(attributes
.c_str(), &st
))
562 ec
.assign(errno
, std::generic_category());
565 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
567 ec
= std::make_error_code(std::errc::function_not_supported
);
574 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
577 create_directory_symlink(to
, new_symlink
, ec
);
579 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
580 to
, new_symlink
, ec
));
584 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
585 error_code
& ec
) noexcept
587 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
588 ec
= std::make_error_code(std::errc::function_not_supported
);
590 create_symlink(to
, new_symlink
, ec
);
596 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
599 create_hard_link(to
, new_hard_link
, ec
);
601 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
602 to
, new_hard_link
, ec
));
606 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
607 error_code
& ec
) noexcept
609 #ifdef _GLIBCXX_HAVE_LINK
610 if (::link(to
.c_str(), new_hard_link
.c_str()))
611 ec
.assign(errno
, std::generic_category());
614 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
615 if (CreateHardLinkW(new_hard_link
.c_str(), to
.c_str(), NULL
))
618 ec
= __last_system_error();
620 ec
= std::make_error_code(std::errc::function_not_supported
);
625 fs::create_symlink(const path
& to
, const path
& new_symlink
)
628 create_symlink(to
, new_symlink
, ec
);
630 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
631 to
, new_symlink
, ec
));
635 fs::create_symlink(const path
& to
, const path
& new_symlink
,
636 error_code
& ec
) noexcept
638 #ifdef _GLIBCXX_HAVE_SYMLINK
639 if (::symlink(to
.c_str(), new_symlink
.c_str()))
640 ec
.assign(errno
, std::generic_category());
644 ec
= std::make_error_code(std::errc::function_not_supported
);
652 path p
= current_path(ec
);
654 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
659 fs::current_path(error_code
& ec
)
662 #if _GLIBCXX_USE_GETCWD
663 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
664 if (char_ptr cwd
= char_ptr
{posix::getcwd(nullptr, 0)})
670 ec
.assign(errno
, std::generic_category());
673 long path_max
= pathconf(".", _PC_PATH_MAX
);
677 else if (path_max
> 10240)
681 #elif defined(PATH_MAX)
682 size_t size
= PATH_MAX
;
686 for (char_ptr buf
; p
.empty(); size
*= 2)
688 using char_type
= fs::path::value_type
;
689 buf
.reset((char_type
*)malloc(size
* sizeof(char_type
)));
692 if (getcwd(buf
.get(), size
))
697 else if (errno
!= ERANGE
)
699 ec
.assign(errno
, std::generic_category());
705 ec
= std::make_error_code(std::errc::not_enough_memory
);
710 #else // _GLIBCXX_HAVE_UNISTD_H
711 ec
= std::make_error_code(std::errc::function_not_supported
);
717 fs::current_path(const path
& p
)
722 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
726 fs::current_path(const path
& p
, error_code
& ec
) noexcept
728 #if _GLIBCXX_USE_CHDIR
729 if (posix::chdir(p
.c_str()))
730 ec
.assign(errno
, std::generic_category());
734 ec
= std::make_error_code(std::errc::function_not_supported
);
739 fs::equivalent(const path
& p1
, const path
& p2
)
742 auto result
= equivalent(p1
, p2
, ec
);
744 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
750 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
752 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
756 if (posix::stat(p1
.c_str(), &st1
) == 0)
757 s1
= make_file_status(st1
);
758 else if (is_not_found_errno(errno
))
759 s1
.type(file_type::not_found
);
763 if (posix::stat(p2
.c_str(), &st2
) == 0)
764 s2
= make_file_status(st2
);
765 else if (is_not_found_errno(errno
))
766 s2
.type(file_type::not_found
);
770 if (exists(s1
) && exists(s2
))
772 if (is_other(s1
) && is_other(s2
))
774 ec
= std::__unsupported();
778 if (is_other(s1
) || is_other(s2
))
780 return fs::equiv_files(p1
.c_str(), st1
, p2
.c_str(), st2
, ec
);
782 else if (!exists(s1
) || !exists(s2
))
783 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
785 ec
.assign(err
, std::generic_category());
790 ec
= std::make_error_code(std::errc::function_not_supported
);
796 fs::file_size(const path
& p
)
799 auto sz
= file_size(p
, ec
);
801 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
807 template<typename Accessor
, typename T
>
809 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
811 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
813 if (posix::stat(p
.c_str(), &st
))
815 ec
.assign(errno
, std::generic_category());
821 ec
= std::make_error_code(std::errc::function_not_supported
);
828 fs::file_size(const path
& p
, error_code
& ec
) noexcept
832 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
833 S() : type(file_type::not_found
) { }
837 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
838 if (s
.type
== file_type::regular
)
842 if (s
.type
== file_type::directory
)
843 ec
= std::make_error_code(std::errc::is_a_directory
);
845 ec
= std::__unsupported();
851 fs::hard_link_count(const path
& p
)
854 auto count
= hard_link_count(p
, ec
);
856 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
861 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
863 return do_stat(p
, ec
, std::mem_fn(&stat_type::st_nlink
),
864 static_cast<uintmax_t>(-1));
868 fs::is_empty(const path
& p
)
871 bool e
= is_empty(p
, ec
);
873 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
879 fs::is_empty(const path
& p
, error_code
& ec
) noexcept
881 auto s
= status(p
, ec
);
884 bool empty
= fs::is_directory(s
)
885 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
886 : fs::file_size(p
, ec
) == 0;
887 return ec
? false : empty
;
891 fs::last_write_time(const path
& p
)
894 auto t
= last_write_time(p
, ec
);
896 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
901 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
903 return do_stat(p
, ec
, [&ec
](const auto& st
) { return file_time(st
, ec
); },
904 file_time_type::min());
908 fs::last_write_time(const path
& p
, file_time_type new_time
)
911 last_write_time(p
, new_time
, ec
);
913 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
917 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
918 file_time_type new_time
, error_code
& ec
) noexcept
920 auto d
= new_time
.time_since_epoch();
921 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
922 #if _GLIBCXX_USE_UTIMENSAT
923 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
924 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
927 ns
+= chrono::seconds(1);
929 struct ::timespec ts
[2];
931 ts
[0].tv_nsec
= UTIME_OMIT
;
932 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
933 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
934 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
935 ec
.assign(errno
, std::generic_category());
938 #elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
939 posix::utimbuf times
;
940 times
.modtime
= s
.count();
941 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
943 if (posix::utime(p
.c_str(), ×
))
944 ec
.assign(errno
, std::generic_category());
948 ec
= std::make_error_code(std::errc::function_not_supported
);
953 fs::permissions(const path
& p
, perms prms
)
956 permissions(p
, prms
, ec
);
958 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
962 fs::permissions(const path
& p
, perms prms
, error_code
& ec
) noexcept
964 #if _GLIBCXX_USE_FCHMODAT || _GLIBCXX_USE_CHMOD
965 const bool add
= is_set(prms
, perms::add_perms
);
966 const bool remove
= is_set(prms
, perms::remove_perms
);
967 const bool nofollow
= is_set(prms
, perms::symlink_nofollow
);
970 ec
= std::make_error_code(std::errc::invalid_argument
);
977 if (add
|| remove
|| nofollow
)
979 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
982 auto curr
= st
.permissions();
990 #if _GLIBCXX_USE_FCHMODAT
991 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
992 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
995 if (nofollow
&& is_symlink(st
))
996 ec
= std::__unsupported();
997 else if (posix::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
1002 ec
.assign(err
, std::generic_category());
1006 ec
= std::make_error_code(std::errc::function_not_supported
);
1011 fs::read_symlink(const path
& p
)
1014 path tgt
= read_symlink(p
, ec
);
1016 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
1020 fs::path
fs::read_symlink(const path
& p
[[gnu::unused
]], error_code
& ec
)
1023 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
1025 if (posix::lstat(p
.c_str(), &st
))
1027 ec
.assign(errno
, std::generic_category());
1030 else if (!fs::is_symlink(make_file_status(st
)))
1032 ec
.assign(EINVAL
, std::generic_category());
1036 std::string
buf(st
.st_size
? st
.st_size
+ 1 : 128, '\0');
1039 ssize_t len
= ::readlink(p
.c_str(), buf
.data(), buf
.size());
1042 ec
.assign(errno
, std::generic_category());
1045 else if (len
== (ssize_t
)buf
.size())
1047 if (buf
.size() > 4096)
1049 ec
.assign(ENAMETOOLONG
, std::generic_category());
1052 buf
.resize(buf
.size() * 2);
1064 ec
= std::make_error_code(std::errc::function_not_supported
);
1071 fs::remove(const path
& p
)
1074 bool result
= fs::remove(p
, ec
);
1076 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1081 fs::remove(const path
& p
, error_code
& ec
) noexcept
1083 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1084 auto st
= symlink_status(p
, ec
);
1087 if ((is_directory(p
, ec
) && RemoveDirectoryW(p
.c_str()))
1088 || DeleteFileW(p
.c_str()))
1094 ec
= __last_system_error();
1096 else if (status_known(st
))
1099 if (::remove(p
.c_str()) == 0)
1104 else if (errno
== ENOENT
)
1107 ec
.assign(errno
, std::generic_category());
1114 fs::remove_all(const path
& p
)
1117 const auto result
= remove_all(p
, ec
);
1119 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1124 fs::remove_all(const path
& p
, error_code
& ec
)
1126 // Use the C++17 implementation.
1127 return std::filesystem::remove_all(p
.native(), ec
);
1131 fs::rename(const path
& from
, const path
& to
)
1134 rename(from
, to
, ec
);
1136 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1140 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1142 if (posix::rename(from
.c_str(), to
.c_str()))
1143 ec
.assign(errno
, std::generic_category());
1149 fs::resize_file(const path
& p
, uintmax_t size
)
1152 resize_file(p
, size
, ec
);
1154 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1158 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1160 if (size
> static_cast<uintmax_t>(std::numeric_limits
<posix::off_t
>::max()))
1161 ec
.assign(EINVAL
, std::generic_category());
1162 else if (posix::truncate(p
.c_str(), size
))
1163 ec
.assign(errno
, std::generic_category());
1170 fs::space(const path
& p
)
1173 space_info s
= space(p
, ec
);
1175 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1180 fs::space(const path
& p
, error_code
& ec
) noexcept
1183 static_cast<uintmax_t>(-1),
1184 static_cast<uintmax_t>(-1),
1185 static_cast<uintmax_t>(-1)
1187 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1188 path dir
= absolute(p
);
1189 dir
.remove_filename();
1190 auto str
= dir
.c_str();
1192 auto str
= p
.c_str();
1194 fs::do_space(str
, info
.capacity
, info
.free
, info
.available
, ec
);
1198 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1199 static bool has_trailing_slash(const fs::path
& p
)
1201 wchar_t c
= p
.native().back();
1202 return c
== '/' || c
== L
'\\';
1206 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1208 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1212 auto str
= p
.c_str();
1214 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1215 // stat() fails if there's a trailing slash (PR 88881)
1217 if (p
.has_relative_path() && has_trailing_slash(p
))
1221 p2
= p
.parent_path();
1224 __catch(const bad_alloc
&)
1226 ec
= std::make_error_code(std::errc::not_enough_memory
);
1234 if (posix::stat(str
, &st
))
1237 ec
.assign(err
, std::generic_category());
1238 if (is_not_found_errno(err
))
1239 status
.type(file_type::not_found
);
1241 else if (err
== EOVERFLOW
)
1242 status
.type(file_type::unknown
);
1247 status
= make_file_status(st
);
1254 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1258 auto str
= p
.c_str();
1260 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1261 // stat() fails if there's a trailing slash (PR 88881)
1263 if (p
.has_relative_path() && has_trailing_slash(p
))
1267 p2
= p
.parent_path();
1270 __catch(const bad_alloc
&)
1272 ec
= std::make_error_code(std::errc::not_enough_memory
);
1280 if (posix::lstat(str
, &st
))
1283 ec
.assign(err
, std::generic_category());
1284 if (is_not_found_errno(err
))
1285 status
.type(file_type::not_found
);
1289 status
= make_file_status(st
);
1297 fs::status(const fs::path
& p
)
1300 auto result
= status(p
, ec
);
1301 if (result
.type() == file_type::none
)
1302 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1307 fs::symlink_status(const fs::path
& p
)
1310 auto result
= symlink_status(p
, ec
);
1311 if (result
.type() == file_type::none
)
1312 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1317 fs::system_complete(const path
& p
)
1320 path comp
= system_complete(p
, ec
);
1322 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p
, ec
));
1327 fs::system_complete(const path
& p
, error_code
& ec
)
1329 path base
= current_path(ec
);
1330 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1331 if (p
.is_absolute() || !p
.has_root_name()
1332 || p
.root_name() == base
.root_name())
1333 return absolute(p
, base
);
1335 ec
= std::__unsupported();
1340 return absolute(p
, base
);
1345 fs::temp_directory_path()
1348 path p
= fs::get_temp_directory_from_env(ec
);
1351 auto st
= status(p
, ec
);
1352 if (!ec
&& !is_directory(st
))
1353 ec
= std::make_error_code(std::errc::not_a_directory
);
1356 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", p
, ec
));
1361 fs::temp_directory_path(error_code
& ec
)
1363 path p
= fs::get_temp_directory_from_env(ec
);
1366 auto st
= status(p
, ec
);
1369 else if (!is_directory(st
))
1372 ec
= std::make_error_code(std::errc::not_a_directory
);