1 // Filesystem TS operations -*- C++ -*-
3 // Copyright (C) 2014-2018 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 #ifndef _GLIBCXX_USE_CXX11_ABI
26 # define _GLIBCXX_USE_CXX11_ABI 1
29 #include <experimental/filesystem>
33 #include <ext/stdio_filebuf.h>
37 #include <limits.h> // PATH_MAX
38 #ifdef _GLIBCXX_HAVE_FCNTL_H
39 # include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
41 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
42 # include <sys/stat.h> // stat, utimensat, fchmodat
44 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
45 # include <sys/statvfs.h> // statvfs
47 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
48 # include <utime.h> // utime
50 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
54 #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
55 namespace experimental { namespace filesystem {
56 #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
57 #include "ops-common.h"
59 namespace fs
= std::experimental::filesystem
;
60 namespace posix
= std::filesystem::__gnu_posix
;
63 fs::absolute(const path
& p
, const path
& base
)
65 const bool has_root_dir
= p
.has_root_directory();
66 const bool has_root_name
= p
.has_root_name();
68 if (has_root_dir
&& has_root_name
)
72 abs
= base
.is_absolute() ? base
: absolute(base
);
74 abs
= abs
.root_name() / p
;
75 else if (has_root_name
)
76 abs
= p
.root_name() / abs
.root_directory() / abs
.relative_path()
86 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
87 inline bool is_dot(wchar_t c
) { return c
== L
'.'; }
89 inline bool is_dot(char c
) { return c
== '.'; }
92 inline bool is_dot(const fs::path
& path
)
94 const auto& filename
= path
.native();
95 return filename
.size() == 1 && is_dot(filename
[0]);
98 inline bool is_dotdot(const fs::path
& path
)
100 const auto& filename
= path
.native();
101 return filename
.size() == 2 && is_dot(filename
[0]) && is_dot(filename
[1]);
104 struct free_as_in_malloc
106 void operator()(void* p
) const { ::free(p
); }
109 using char_ptr
= std::unique_ptr
<fs::path::value_type
[], free_as_in_malloc
>;
113 fs::canonical(const path
& p
, const path
& base
, error_code
& ec
)
115 const path pa
= absolute(p
, base
);
118 #ifdef _GLIBCXX_USE_REALPATH
119 char_ptr buf
{ nullptr };
120 # if _XOPEN_VERSION < 700
121 // Not safe to call realpath(path, NULL)
122 using char_type
= fs::path::value_type
;
123 buf
.reset( (char_type
*)::malloc(PATH_MAX
* sizeof(char_type
)) );
125 if (char* rp
= ::realpath(pa
.c_str(), buf
.get()))
133 if (errno
!= ENAMETOOLONG
)
135 ec
.assign(errno
, std::generic_category());
143 ec
= make_error_code(std::errc::no_such_file_or_directory
);
146 // else: we know there are (currently) no unresolvable symlink loops
148 result
= pa
.root_path();
151 for (auto& f
: pa
.relative_path())
154 int max_allowed_symlinks
= 40;
156 while (!cmpts
.empty() && !ec
)
158 path f
= std::move(cmpts
.front());
163 if (!is_directory(result
, ec
) && !ec
)
164 ec
.assign(ENOTDIR
, std::generic_category());
166 else if (is_dotdot(f
))
168 auto parent
= result
.parent_path();
170 result
= pa
.root_path();
178 if (is_symlink(result
, ec
))
180 path link
= read_symlink(result
, ec
);
183 if (--max_allowed_symlinks
== 0)
184 ec
.assign(ELOOP
, std::generic_category());
187 if (link
.is_absolute())
189 result
= link
.root_path();
190 link
= link
.relative_path();
193 result
.remove_filename();
195 cmpts
.insert(cmpts
.begin(), link
.begin(), link
.end());
202 if (ec
|| !exists(result
, ec
))
209 fs::canonical(const path
& p
, error_code
& ec
)
211 path cur
= current_path(ec
);
214 return canonical(p
, cur
, ec
);
218 fs::canonical(const path
& p
, const path
& base
)
221 path can
= canonical(p
, base
, ec
);
223 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p
, base
,
229 fs::copy(const path
& from
, const path
& to
, copy_options options
)
232 copy(from
, to
, options
, ec
);
234 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from
, to
, ec
));
239 using std::filesystem::is_set
;
241 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
242 using posix::stat_type
;
244 using std::filesystem::is_not_found_errno
;
245 using std::filesystem::file_time
;
246 using std::filesystem::do_copy_file
;
247 #endif // _GLIBCXX_HAVE_SYS_STAT_H
252 fs::copy(const path
& from
, const path
& to
, copy_options options
,
253 error_code
& ec
) noexcept
255 const bool skip_symlinks
= is_set(options
, copy_options::skip_symlinks
);
256 const bool create_symlinks
= is_set(options
, copy_options::create_symlinks
);
257 const bool copy_symlinks
= is_set(options
, copy_options::copy_symlinks
);
258 const bool use_lstat
= create_symlinks
|| skip_symlinks
;
261 stat_type from_st
, to_st
;
262 // _GLIBCXX_RESOLVE_LIB_DEFECTS
263 // 2681. filesystem::copy() cannot copy symlinks
264 if (use_lstat
|| copy_symlinks
265 ? posix::lstat(from
.c_str(), &from_st
)
266 : posix::stat(from
.c_str(), &from_st
))
268 ec
.assign(errno
, std::generic_category());
272 ? posix::lstat(to
.c_str(), &to_st
)
273 : posix::stat(to
.c_str(), &to_st
))
275 if (!is_not_found_errno(errno
))
277 ec
.assign(errno
, std::generic_category());
280 t
= file_status
{file_type::not_found
};
283 t
= make_file_status(to_st
);
284 f
= make_file_status(from_st
);
286 if (exists(t
) && !is_other(t
) && !is_other(f
)
287 && to_st
.st_dev
== from_st
.st_dev
&& to_st
.st_ino
== from_st
.st_ino
)
289 ec
= std::make_error_code(std::errc::file_exists
);
292 if (is_other(f
) || is_other(t
))
294 ec
= std::make_error_code(std::errc::not_supported
);
297 if (is_directory(f
) && is_regular_file(t
))
299 ec
= std::make_error_code(std::errc::is_a_directory
);
307 else if (!exists(t
) && copy_symlinks
)
308 copy_symlink(from
, to
, ec
);
310 // Not clear what should be done here.
311 // "Otherwise report an error as specified in Error reporting (7)."
312 ec
= std::make_error_code(std::errc::invalid_argument
);
314 else if (is_regular_file(f
))
316 if (is_set(options
, copy_options::directories_only
))
318 else if (create_symlinks
)
319 create_symlink(from
, to
, ec
);
320 else if (is_set(options
, copy_options::create_hard_links
))
321 create_hard_link(from
, to
, ec
);
322 else if (is_directory(t
))
323 do_copy_file(from
.c_str(), (to
/ from
.filename()).c_str(),
324 copy_file_options(options
), &from_st
, nullptr, ec
);
327 auto ptr
= exists(t
) ? &to_st
: &from_st
;
328 do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
332 // _GLIBCXX_RESOLVE_LIB_DEFECTS
333 // 2682. filesystem::copy() won't create a symlink to a directory
334 else if (is_directory(f
) && create_symlinks
)
335 ec
= std::make_error_code(errc::is_a_directory
);
336 else if (is_directory(f
) && (is_set(options
, copy_options::recursive
)
337 || options
== copy_options::none
))
340 if (!create_directory(to
, from
, ec
))
342 // set an unused bit in options to disable further recursion
343 if (!is_set(options
, copy_options::recursive
))
344 options
|= static_cast<copy_options
>(4096);
345 for (const directory_entry
& x
: directory_iterator(from
))
346 copy(x
.path(), to
/x
.path().filename(), options
, ec
);
348 // _GLIBCXX_RESOLVE_LIB_DEFECTS
349 // 2683. filesystem::copy() says "no effects"
355 fs::copy_file(const path
& from
, const path
& to
, copy_options option
)
358 bool result
= copy_file(from
, to
, option
, ec
);
360 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from
, to
,
366 fs::copy_file(const path
& from
, const path
& to
, copy_options options
,
367 error_code
& ec
) noexcept
369 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
370 return do_copy_file(from
.c_str(), to
.c_str(), copy_file_options(options
),
371 nullptr, nullptr, ec
);
373 ec
= std::make_error_code(std::errc::not_supported
);
380 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
)
383 copy_symlink(existing_symlink
, new_symlink
, ec
);
385 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
386 existing_symlink
, new_symlink
, ec
));
390 fs::copy_symlink(const path
& existing_symlink
, const path
& new_symlink
,
391 error_code
& ec
) noexcept
393 auto p
= read_symlink(existing_symlink
, ec
);
396 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
399 create_directory_symlink(p
, new_symlink
, ec
);
403 create_symlink(p
, new_symlink
, ec
);
408 fs::create_directories(const path
& p
)
411 bool result
= create_directories(p
, ec
);
413 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p
,
419 fs::create_directories(const path
& p
, error_code
& ec
) noexcept
423 ec
= std::make_error_code(errc::invalid_argument
);
426 std::stack
<path
> missing
;
429 while (!pp
.empty() && status(pp
, ec
).type() == file_type::not_found
)
432 const auto& filename
= pp
.filename();
433 if (!is_dot(filename
) && !is_dotdot(filename
))
435 pp
.remove_filename();
438 if (ec
|| missing
.empty())
443 const path
& top
= missing
.top();
444 create_directory(top
, ec
);
445 if (ec
&& is_directory(top
))
449 while (!missing
.empty() && !ec
);
451 return missing
.empty();
457 create_dir(const fs::path
& p
, fs::perms perm
, std::error_code
& ec
)
459 bool created
= false;
460 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
461 posix::mode_t mode
= static_cast<std::underlying_type_t
<fs::perms
>>(perm
);
462 if (posix::mkdir(p
.c_str(), mode
))
464 const int err
= errno
;
465 if (err
!= EEXIST
|| !is_directory(p
, ec
))
466 ec
.assign(err
, std::generic_category());
474 ec
= std::make_error_code(std::errc::not_supported
);
481 fs::create_directory(const path
& p
)
484 bool result
= create_directory(p
, ec
);
486 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
492 fs::create_directory(const path
& p
, error_code
& ec
) noexcept
494 return create_dir(p
, perms::all
, ec
);
499 fs::create_directory(const path
& p
, const path
& attributes
)
502 bool result
= create_directory(p
, attributes
, ec
);
504 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p
,
510 fs::create_directory(const path
& p
, const path
& attributes
,
511 error_code
& ec
) noexcept
513 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
515 if (posix::stat(attributes
.c_str(), &st
))
517 ec
.assign(errno
, std::generic_category());
520 return create_dir(p
, static_cast<perms
>(st
.st_mode
), ec
);
522 ec
= std::make_error_code(std::errc::not_supported
);
529 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
)
532 create_directory_symlink(to
, new_symlink
, ec
);
534 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
535 to
, new_symlink
, ec
));
539 fs::create_directory_symlink(const path
& to
, const path
& new_symlink
,
540 error_code
& ec
) noexcept
542 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
543 ec
= std::make_error_code(std::errc::not_supported
);
545 create_symlink(to
, new_symlink
, ec
);
551 fs::create_hard_link(const path
& to
, const path
& new_hard_link
)
554 create_hard_link(to
, new_hard_link
, ec
);
556 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
557 to
, new_hard_link
, ec
));
561 fs::create_hard_link(const path
& to
, const path
& new_hard_link
,
562 error_code
& ec
) noexcept
564 #ifdef _GLIBCXX_HAVE_LINK
565 if (::link(to
.c_str(), new_hard_link
.c_str()))
566 ec
.assign(errno
, std::generic_category());
569 #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
570 if (CreateHardLinkW(new_hard_link
.c_str(), to
.c_str(), NULL
))
573 ec
.assign((int)GetLastError(), generic_category());
575 ec
= std::make_error_code(std::errc::not_supported
);
580 fs::create_symlink(const path
& to
, const path
& new_symlink
)
583 create_symlink(to
, new_symlink
, ec
);
585 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
586 to
, new_symlink
, ec
));
590 fs::create_symlink(const path
& to
, const path
& new_symlink
,
591 error_code
& ec
) noexcept
593 #ifdef _GLIBCXX_HAVE_SYMLINK
594 if (::symlink(to
.c_str(), new_symlink
.c_str()))
595 ec
.assign(errno
, std::generic_category());
599 ec
= std::make_error_code(std::errc::not_supported
);
607 path p
= current_path(ec
);
609 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec
));
614 fs::current_path(error_code
& ec
)
617 #ifdef _GLIBCXX_HAVE_UNISTD_H
618 #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
619 if (char_ptr cwd
= char_ptr
{posix::getcwd(nullptr, 0)})
625 ec
.assign(errno
, std::generic_category());
628 long path_max
= pathconf(".", _PC_PATH_MAX
);
632 else if (path_max
> 10240)
636 #elif defined(PATH_MAX)
637 size_t size
= PATH_MAX
;
641 for (char_ptr buf
; p
.empty(); size
*= 2)
643 using char_type
= fs::path::value_type
;
644 buf
.reset((char_type
*)malloc(size
* sizeof(char_type
)));
647 if (getcwd(buf
.get(), size
))
652 else if (errno
!= ERANGE
)
654 ec
.assign(errno
, std::generic_category());
660 ec
= std::make_error_code(std::errc::not_enough_memory
);
665 #else // _GLIBCXX_HAVE_UNISTD_H
666 ec
= std::make_error_code(std::errc::not_supported
);
672 fs::current_path(const path
& p
)
677 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec
));
681 fs::current_path(const path
& p
, error_code
& ec
) noexcept
683 #ifdef _GLIBCXX_HAVE_UNISTD_H
684 if (posix::chdir(p
.c_str()))
685 ec
.assign(errno
, std::generic_category());
689 ec
= std::make_error_code(std::errc::not_supported
);
694 fs::equivalent(const path
& p1
, const path
& p2
)
697 auto result
= equivalent(p1
, p2
, ec
);
699 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
705 fs::equivalent(const path
& p1
, const path
& p2
, error_code
& ec
) noexcept
707 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
711 if (posix::stat(p1
.c_str(), &st1
) == 0)
712 s1
= make_file_status(st1
);
713 else if (is_not_found_errno(errno
))
714 s1
.type(file_type::not_found
);
718 if (posix::stat(p2
.c_str(), &st2
) == 0)
719 s2
= make_file_status(st2
);
720 else if (is_not_found_errno(errno
))
721 s2
.type(file_type::not_found
);
725 if (exists(s1
) && exists(s2
))
727 if (is_other(s1
) && is_other(s2
))
729 ec
= std::make_error_code(std::errc::not_supported
);
733 if (is_other(s1
) || is_other(s2
))
735 return st1
.st_dev
== st2
.st_dev
&& st1
.st_ino
== st2
.st_ino
;
737 else if (!exists(s1
) && !exists(s2
))
738 ec
= std::make_error_code(std::errc::no_such_file_or_directory
);
740 ec
.assign(err
, std::generic_category());
745 ec
= std::make_error_code(std::errc::not_supported
);
751 fs::file_size(const path
& p
)
754 auto sz
= file_size(p
, ec
);
756 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p
, ec
));
762 template<typename Accessor
, typename T
>
764 do_stat(const fs::path
& p
, std::error_code
& ec
, Accessor f
, T deflt
)
766 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
768 if (posix::stat(p
.c_str(), &st
))
770 ec
.assign(errno
, std::generic_category());
776 ec
= std::make_error_code(std::errc::not_supported
);
783 fs::file_size(const path
& p
, error_code
& ec
) noexcept
787 S(const stat_type
& st
) : type(make_file_type(st
)), size(st
.st_size
) { }
788 S() : type(file_type::not_found
) { }
792 auto s
= do_stat(p
, ec
, [](const auto& st
) { return S
{st
}; }, S
{});
793 if (s
.type
== file_type::regular
)
797 if (s
.type
== file_type::directory
)
798 ec
= std::make_error_code(std::errc::is_a_directory
);
800 ec
= std::make_error_code(std::errc::not_supported
);
806 fs::hard_link_count(const path
& p
)
809 auto count
= hard_link_count(p
, ec
);
811 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p
, ec
));
816 fs::hard_link_count(const path
& p
, error_code
& ec
) noexcept
818 return do_stat(p
, ec
, std::mem_fn(&stat_type::st_nlink
),
819 static_cast<uintmax_t>(-1));
823 fs::is_empty(const path
& p
)
826 bool e
= is_empty(p
, ec
);
828 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
834 fs::is_empty(const path
& p
, error_code
& ec
) noexcept
836 auto s
= status(p
, ec
);
839 bool empty
= fs::is_directory(s
)
840 ? fs::directory_iterator(p
, ec
) == fs::directory_iterator()
841 : fs::file_size(p
, ec
) == 0;
842 return ec
? false : empty
;
846 fs::last_write_time(const path
& p
)
849 auto t
= last_write_time(p
, ec
);
851 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p
, ec
));
856 fs::last_write_time(const path
& p
, error_code
& ec
) noexcept
858 return do_stat(p
, ec
, [&ec
](const auto& st
) { return file_time(st
, ec
); },
859 file_time_type::min());
863 fs::last_write_time(const path
& p
, file_time_type new_time
)
866 last_write_time(p
, new_time
, ec
);
868 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p
, ec
));
872 fs::last_write_time(const path
& p
__attribute__((__unused__
)),
873 file_time_type new_time
, error_code
& ec
) noexcept
875 auto d
= new_time
.time_since_epoch();
876 auto s
= chrono::duration_cast
<chrono::seconds
>(d
);
877 #if _GLIBCXX_USE_UTIMENSAT
878 auto ns
= chrono::duration_cast
<chrono::nanoseconds
>(d
- s
);
879 if (ns
< ns
.zero()) // tv_nsec must be non-negative and less than 10e9.
882 ns
+= chrono::seconds(1);
884 struct ::timespec ts
[2];
886 ts
[0].tv_nsec
= UTIME_OMIT
;
887 ts
[1].tv_sec
= static_cast<std::time_t>(s
.count());
888 ts
[1].tv_nsec
= static_cast<long>(ns
.count());
889 if (::utimensat(AT_FDCWD
, p
.c_str(), ts
, 0))
890 ec
.assign(errno
, std::generic_category());
893 #elif _GLIBCXX_HAVE_UTIME_H
894 posix::utimbuf times
;
895 times
.modtime
= s
.count();
896 times
.actime
= do_stat(p
, ec
, [](const auto& st
) { return st
.st_atime
; },
898 if (posix::utime(p
.c_str(), ×
))
899 ec
.assign(errno
, std::generic_category());
903 ec
= std::make_error_code(std::errc::not_supported
);
908 fs::permissions(const path
& p
, perms prms
)
911 permissions(p
, prms
, ec
);
913 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p
, ec
));
917 fs::permissions(const path
& p
, perms prms
, error_code
& ec
) noexcept
919 const bool add
= is_set(prms
, perms::add_perms
);
920 const bool remove
= is_set(prms
, perms::remove_perms
);
921 const bool nofollow
= is_set(prms
, perms::symlink_nofollow
);
924 ec
= std::make_error_code(std::errc::invalid_argument
);
931 if (add
|| remove
|| nofollow
)
933 st
= nofollow
? symlink_status(p
, ec
) : status(p
, ec
);
936 auto curr
= st
.permissions();
944 #if _GLIBCXX_USE_FCHMODAT
945 const int flag
= (nofollow
&& is_symlink(st
)) ? AT_SYMLINK_NOFOLLOW
: 0;
946 if (::fchmodat(AT_FDCWD
, p
.c_str(), static_cast<mode_t
>(prms
), flag
))
949 if (nofollow
&& is_symlink(st
))
950 ec
= std::make_error_code(std::errc::operation_not_supported
);
951 else if (posix::chmod(p
.c_str(), static_cast<mode_t
>(prms
)))
956 ec
.assign(err
, std::generic_category());
962 fs::read_symlink(const path
& p
)
965 path tgt
= read_symlink(p
, ec
);
967 _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p
, ec
));
971 fs::path
fs::read_symlink(const path
& p
[[gnu::unused
]], error_code
& ec
)
974 #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
976 if (::lstat(p
.c_str(), &st
))
978 ec
.assign(errno
, std::generic_category());
981 std::string
buf(st
.st_size
? st
.st_size
+ 1 : 128, '\0');
984 ssize_t len
= ::readlink(p
.c_str(), buf
.data(), buf
.size());
987 ec
.assign(errno
, std::generic_category());
990 else if (len
== (ssize_t
)buf
.size())
992 if (buf
.size() > 4096)
994 ec
.assign(ENAMETOOLONG
, std::generic_category());
997 buf
.resize(buf
.size() * 2);
1009 ec
= std::make_error_code(std::errc::not_supported
);
1016 fs::remove(const path
& p
)
1019 bool result
= fs::remove(p
, ec
);
1021 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p
, ec
));
1026 fs::remove(const path
& p
, error_code
& ec
) noexcept
1028 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1029 if (exists(symlink_status(p
, ec
)))
1031 if ((is_directory(p
, ec
) && RemoveDirectoryW(p
.c_str()))
1032 || DeleteFileW(p
.c_str()))
1038 ec
.assign((int)GetLastError(), generic_category());
1041 if (::remove(p
.c_str()) == 0)
1046 else if (errno
== ENOENT
)
1049 ec
.assign(errno
, std::generic_category());
1056 fs::remove_all(const path
& p
)
1059 const auto result
= remove_all(p
, ec
);
1061 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p
, ec
));
1066 fs::remove_all(const path
& p
, error_code
& ec
) noexcept
1068 const auto s
= symlink_status(p
, ec
);
1069 if (!status_known(s
))
1073 if (s
.type() == file_type::not_found
)
1076 uintmax_t count
= 0;
1077 if (s
.type() == file_type::directory
)
1079 for (directory_iterator
d(p
, ec
), end
; !ec
&& d
!= end
; d
.increment(ec
))
1080 count
+= fs::remove_all(d
->path(), ec
);
1081 if (ec
.value() == ENOENT
)
1087 if (fs::remove(p
, ec
))
1089 return ec
? -1 : count
;
1093 fs::rename(const path
& from
, const path
& to
)
1096 rename(from
, to
, ec
);
1098 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from
, to
, ec
));
1102 fs::rename(const path
& from
, const path
& to
, error_code
& ec
) noexcept
1104 if (posix::rename(from
.c_str(), to
.c_str()))
1105 ec
.assign(errno
, std::generic_category());
1111 fs::resize_file(const path
& p
, uintmax_t size
)
1114 resize_file(p
, size
, ec
);
1116 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p
, ec
));
1120 fs::resize_file(const path
& p
, uintmax_t size
, error_code
& ec
) noexcept
1122 #ifdef _GLIBCXX_HAVE_UNISTD_H
1123 if (size
> static_cast<uintmax_t>(std::numeric_limits
<off_t
>::max()))
1124 ec
.assign(EINVAL
, std::generic_category());
1125 else if (posix::truncate(p
.c_str(), size
))
1126 ec
.assign(errno
, std::generic_category());
1130 ec
= std::make_error_code(std::errc::not_supported
);
1136 fs::space(const path
& p
)
1139 space_info s
= space(p
, ec
);
1141 _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p
, ec
));
1146 fs::space(const path
& p
, error_code
& ec
) noexcept
1149 static_cast<uintmax_t>(-1),
1150 static_cast<uintmax_t>(-1),
1151 static_cast<uintmax_t>(-1)
1153 #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1154 path dir
= absolute(p
);
1155 dir
.remove_filename();
1156 auto str
= dir
.c_str();
1158 auto str
= p
.c_str();
1160 std::filesystem::do_space(str
, info
.capacity
, info
.free
, info
.available
, ec
);
1164 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
1166 fs::status(const fs::path
& p
, error_code
& ec
) noexcept
1170 if (posix::stat(p
.c_str(), &st
))
1173 ec
.assign(err
, std::generic_category());
1174 if (is_not_found_errno(err
))
1175 status
.type(file_type::not_found
);
1177 else if (err
== EOVERFLOW
)
1178 status
.type(file_type::unknown
);
1183 status
= make_file_status(st
);
1190 fs::symlink_status(const fs::path
& p
, std::error_code
& ec
) noexcept
1194 if (posix::lstat(p
.c_str(), &st
))
1197 ec
.assign(err
, std::generic_category());
1198 if (is_not_found_errno(err
))
1199 status
.type(file_type::not_found
);
1203 status
= make_file_status(st
);
1211 fs::status(const fs::path
& p
)
1214 auto result
= status(p
, ec
);
1215 if (result
.type() == file_type::none
)
1216 _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p
, ec
));
1221 fs::symlink_status(const fs::path
& p
)
1224 auto result
= symlink_status(p
, ec
);
1225 if (result
.type() == file_type::none
)
1226 _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p
, ec
));
1231 fs::system_complete(const path
& p
)
1234 path comp
= system_complete(p
, ec
);
1236 _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p
, ec
));
1241 fs::system_complete(const path
& p
, error_code
& ec
)
1243 path base
= current_path(ec
);
1244 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1245 if (p
.is_absolute() || !p
.has_root_name()
1246 || p
.root_name() == base
.root_name())
1247 return absolute(p
, base
);
1249 ec
= std::make_error_code(std::errc::not_supported
);
1254 return absolute(p
, base
);
1258 fs::path
fs::temp_directory_path()
1261 path tmp
= temp_directory_path(ec
);
1263 _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec
));
1267 fs::path
fs::temp_directory_path(error_code
& ec
)
1270 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1271 unsigned len
= 1024;
1276 len
= GetTempPathW(buf
.size(), buf
.data());
1277 } while (len
> buf
.size());
1281 ec
.assign((int)GetLastError(), std::system_category());
1287 const char* tmpdir
= nullptr;
1288 const char* env
[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1289 for (auto e
= env
; tmpdir
== nullptr && *e
!= nullptr; ++e
)
1290 tmpdir
= ::getenv(*e
);
1291 p
= tmpdir
? tmpdir
: "/tmp";
1292 auto st
= status(p
, ec
);
1295 else if (!is_directory(st
))
1298 ec
= std::make_error_code(std::errc::not_a_directory
);