xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/src/filesystem/ops.cc (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1a3e9eb18Smrg // Filesystem TS operations -*- C++ -*-
24d5abbe8Smrg 
3b1e83836Smrg // Copyright (C) 2014-2022 Free Software Foundation, Inc.
44d5abbe8Smrg //
54d5abbe8Smrg // This file is part of the GNU ISO C++ Library.  This library is free
64d5abbe8Smrg // software; you can redistribute it and/or modify it under the
74d5abbe8Smrg // terms of the GNU General Public License as published by the
84d5abbe8Smrg // Free Software Foundation; either version 3, or (at your option)
94d5abbe8Smrg // any later version.
104d5abbe8Smrg 
114d5abbe8Smrg // This library is distributed in the hope that it will be useful,
124d5abbe8Smrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
134d5abbe8Smrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
144d5abbe8Smrg // GNU General Public License for more details.
154d5abbe8Smrg 
164d5abbe8Smrg // Under Section 7 of GPL version 3, you are granted additional
174d5abbe8Smrg // permissions described in the GCC Runtime Library Exception, version
184d5abbe8Smrg // 3.1, as published by the Free Software Foundation.
194d5abbe8Smrg 
204d5abbe8Smrg // You should have received a copy of the GNU General Public License and
214d5abbe8Smrg // a copy of the GCC Runtime Library Exception along with this program;
224d5abbe8Smrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
234d5abbe8Smrg // <http://www.gnu.org/licenses/>.
244d5abbe8Smrg 
254d5abbe8Smrg #ifndef _GLIBCXX_USE_CXX11_ABI
264d5abbe8Smrg # define _GLIBCXX_USE_CXX11_ABI 1
27181254a7Smrg # define NEED_DO_COPY_FILE
28181254a7Smrg # define NEED_DO_SPACE
294d5abbe8Smrg #endif
30b1e83836Smrg #ifndef _GNU_SOURCE
31b1e83836Smrg // Cygwin needs this for secure_getenv
32b1e83836Smrg # define _GNU_SOURCE 1
33b1e83836Smrg #endif
344d5abbe8Smrg 
35a3e9eb18Smrg #include <bits/largefile-config.h>
364d5abbe8Smrg #include <experimental/filesystem>
374d5abbe8Smrg #include <functional>
383f4ceed9Smrg #include <ostream>
394d5abbe8Smrg #include <stack>
403f4ceed9Smrg #include <ext/stdio_filebuf.h>
414d5abbe8Smrg #include <stdlib.h>
424d5abbe8Smrg #include <stdio.h>
434d5abbe8Smrg #include <errno.h>
444d5abbe8Smrg #include <limits.h>  // PATH_MAX
458b6133e5Smrg #ifdef _GLIBCXX_HAVE_FCNTL_H
46a3e9eb18Smrg # include <fcntl.h>  // AT_FDCWD, AT_SYMLINK_NOFOLLOW
47a3e9eb18Smrg #endif
48a3e9eb18Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
49a3e9eb18Smrg # include <sys/stat.h>   // stat, utimensat, fchmodat
504d5abbe8Smrg #endif
514d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
52a3e9eb18Smrg # include <sys/statvfs.h> // statvfs
534d5abbe8Smrg #endif
54a3e9eb18Smrg #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
55a3e9eb18Smrg # include <utime.h> // utime
564d5abbe8Smrg #endif
57181254a7Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
58181254a7Smrg # include <windows.h>
59181254a7Smrg #endif
60a3e9eb18Smrg 
61a3e9eb18Smrg #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
62a3e9eb18Smrg   namespace experimental { namespace filesystem {
63a3e9eb18Smrg #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
64a3e9eb18Smrg #include "ops-common.h"
654d5abbe8Smrg 
66b1e83836Smrg #include <filesystem> // std::filesystem::remove_all
67b1e83836Smrg 
684d5abbe8Smrg namespace fs = std::experimental::filesystem;
69181254a7Smrg namespace posix = std::filesystem::__gnu_posix;
704d5abbe8Smrg 
714d5abbe8Smrg fs::path
absolute(const path & p,const path & base)724d5abbe8Smrg fs::absolute(const path& p, const path& base)
734d5abbe8Smrg {
744d5abbe8Smrg   const bool has_root_dir = p.has_root_directory();
754d5abbe8Smrg   const bool has_root_name = p.has_root_name();
764d5abbe8Smrg   path abs;
774d5abbe8Smrg   if (has_root_dir && has_root_name)
784d5abbe8Smrg     abs = p;
794d5abbe8Smrg   else
804d5abbe8Smrg     {
814d5abbe8Smrg       abs = base.is_absolute() ? base : absolute(base);
824d5abbe8Smrg       if (has_root_dir)
834d5abbe8Smrg 	abs = abs.root_name() / p;
844d5abbe8Smrg       else if (has_root_name)
854d5abbe8Smrg 	abs = p.root_name() / abs.root_directory() / abs.relative_path()
864d5abbe8Smrg 	  / p.relative_path();
874d5abbe8Smrg       else
884d5abbe8Smrg 	abs = abs / p;
894d5abbe8Smrg     }
904d5abbe8Smrg   return abs;
914d5abbe8Smrg }
924d5abbe8Smrg 
934d5abbe8Smrg namespace
944d5abbe8Smrg {
954d5abbe8Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
is_dot(wchar_t c)964d5abbe8Smrg   inline bool is_dot(wchar_t c) { return c == L'.'; }
974d5abbe8Smrg #else
984d5abbe8Smrg   inline bool is_dot(char c) { return c == '.'; }
994d5abbe8Smrg #endif
1004d5abbe8Smrg 
is_dot(const fs::path & path)1014d5abbe8Smrg   inline bool is_dot(const fs::path& path)
1024d5abbe8Smrg   {
1034d5abbe8Smrg     const auto& filename = path.native();
1044d5abbe8Smrg     return filename.size() == 1 && is_dot(filename[0]);
1054d5abbe8Smrg   }
1064d5abbe8Smrg 
is_dotdot(const fs::path & path)1074d5abbe8Smrg   inline bool is_dotdot(const fs::path& path)
1084d5abbe8Smrg   {
1094d5abbe8Smrg     const auto& filename = path.native();
1104d5abbe8Smrg     return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
1114d5abbe8Smrg   }
1124d5abbe8Smrg 
1134d5abbe8Smrg   struct free_as_in_malloc
1144d5abbe8Smrg   {
operator ()__anond49a9c9f0111::free_as_in_malloc1154d5abbe8Smrg     void operator()(void* p) const { ::free(p); }
1164d5abbe8Smrg   };
1174d5abbe8Smrg 
118181254a7Smrg   using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
1194d5abbe8Smrg }
1204d5abbe8Smrg 
1214d5abbe8Smrg fs::path
canonical(const path & p,const path & base,error_code & ec)1224d5abbe8Smrg fs::canonical(const path& p, const path& base, error_code& ec)
1234d5abbe8Smrg {
1244d5abbe8Smrg   const path pa = absolute(p, base);
1254d5abbe8Smrg   path result;
1264d5abbe8Smrg 
1274d5abbe8Smrg #ifdef _GLIBCXX_USE_REALPATH
1284d5abbe8Smrg   char_ptr buf{ nullptr };
1294d5abbe8Smrg # if _XOPEN_VERSION < 700
1304d5abbe8Smrg   // Not safe to call realpath(path, NULL)
131181254a7Smrg   using char_type = fs::path::value_type;
132181254a7Smrg   buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
1334d5abbe8Smrg # endif
1344d5abbe8Smrg   if (char* rp = ::realpath(pa.c_str(), buf.get()))
1354d5abbe8Smrg     {
1364d5abbe8Smrg       if (buf == nullptr)
1374d5abbe8Smrg 	buf.reset(rp);
1384d5abbe8Smrg       result.assign(rp);
1394d5abbe8Smrg       ec.clear();
1404d5abbe8Smrg       return result;
1414d5abbe8Smrg     }
1424d5abbe8Smrg   if (errno != ENAMETOOLONG)
1434d5abbe8Smrg     {
1444d5abbe8Smrg       ec.assign(errno, std::generic_category());
1454d5abbe8Smrg       return result;
1464d5abbe8Smrg     }
1474d5abbe8Smrg #endif
1484d5abbe8Smrg 
1494d5abbe8Smrg   if (!exists(pa, ec))
1503f4ceed9Smrg     {
1513f4ceed9Smrg       if (!ec)
1523f4ceed9Smrg 	ec = make_error_code(std::errc::no_such_file_or_directory);
1534d5abbe8Smrg       return result;
1543f4ceed9Smrg     }
1554d5abbe8Smrg   // else: we know there are (currently) no unresolvable symlink loops
1564d5abbe8Smrg 
1574d5abbe8Smrg   result = pa.root_path();
1584d5abbe8Smrg 
1594d5abbe8Smrg   deque<path> cmpts;
1604d5abbe8Smrg   for (auto& f : pa.relative_path())
1614d5abbe8Smrg     cmpts.push_back(f);
1624d5abbe8Smrg 
1634d5abbe8Smrg   int max_allowed_symlinks = 40;
1644d5abbe8Smrg 
1654d5abbe8Smrg   while (!cmpts.empty() && !ec)
1664d5abbe8Smrg     {
1674d5abbe8Smrg       path f = std::move(cmpts.front());
1684d5abbe8Smrg       cmpts.pop_front();
1694d5abbe8Smrg 
1704d5abbe8Smrg       if (is_dot(f))
1714d5abbe8Smrg 	{
1724d5abbe8Smrg 	  if (!is_directory(result, ec) && !ec)
1734d5abbe8Smrg 	    ec.assign(ENOTDIR, std::generic_category());
1744d5abbe8Smrg 	}
1754d5abbe8Smrg       else if (is_dotdot(f))
1764d5abbe8Smrg 	{
1774d5abbe8Smrg 	  auto parent = result.parent_path();
1784d5abbe8Smrg 	  if (parent.empty())
1794d5abbe8Smrg 	    result = pa.root_path();
1804d5abbe8Smrg 	  else
1814d5abbe8Smrg 	    result.swap(parent);
1824d5abbe8Smrg 	}
1834d5abbe8Smrg       else
1844d5abbe8Smrg 	{
1854d5abbe8Smrg 	  result /= f;
1864d5abbe8Smrg 
1874d5abbe8Smrg 	  if (is_symlink(result, ec))
1884d5abbe8Smrg 	    {
1894d5abbe8Smrg 	      path link = read_symlink(result, ec);
1904d5abbe8Smrg 	      if (!ec)
1914d5abbe8Smrg 		{
1924d5abbe8Smrg 		  if (--max_allowed_symlinks == 0)
1934d5abbe8Smrg 		    ec.assign(ELOOP, std::generic_category());
1944d5abbe8Smrg 		  else
1954d5abbe8Smrg 		    {
1964d5abbe8Smrg 		      if (link.is_absolute())
1974d5abbe8Smrg 			{
1984d5abbe8Smrg 			  result = link.root_path();
1994d5abbe8Smrg 			  link = link.relative_path();
2004d5abbe8Smrg 			}
2014d5abbe8Smrg 		      else
2024d5abbe8Smrg 			result.remove_filename();
2034d5abbe8Smrg 
2044d5abbe8Smrg 		      cmpts.insert(cmpts.begin(), link.begin(), link.end());
2054d5abbe8Smrg 		    }
2064d5abbe8Smrg 		}
2074d5abbe8Smrg 	    }
2084d5abbe8Smrg 	}
2094d5abbe8Smrg     }
2104d5abbe8Smrg 
2114d5abbe8Smrg   if (ec || !exists(result, ec))
2124d5abbe8Smrg     result.clear();
2134d5abbe8Smrg 
2144d5abbe8Smrg   return result;
2154d5abbe8Smrg }
2164d5abbe8Smrg 
2174d5abbe8Smrg fs::path
canonical(const path & p,error_code & ec)2184d5abbe8Smrg fs::canonical(const path& p, error_code& ec)
2194d5abbe8Smrg {
2204d5abbe8Smrg   path cur = current_path(ec);
2214d5abbe8Smrg   if (ec.value())
2224d5abbe8Smrg     return {};
2234d5abbe8Smrg   return canonical(p, cur, ec);
2244d5abbe8Smrg }
2254d5abbe8Smrg 
2264d5abbe8Smrg fs::path
canonical(const path & p,const path & base)2274d5abbe8Smrg fs::canonical(const path& p, const path& base)
2284d5abbe8Smrg {
2294d5abbe8Smrg   error_code ec;
2304d5abbe8Smrg   path can = canonical(p, base, ec);
231f30ff588Smrg   if (ec)
232f30ff588Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, base,
233f30ff588Smrg 					     ec));
2344d5abbe8Smrg   return can;
2354d5abbe8Smrg }
2364d5abbe8Smrg 
2374d5abbe8Smrg void
copy(const path & from,const path & to,copy_options options)2384d5abbe8Smrg fs::copy(const path& from, const path& to, copy_options options)
2394d5abbe8Smrg {
2404d5abbe8Smrg   error_code ec;
2414d5abbe8Smrg   copy(from, to, options, ec);
2424d5abbe8Smrg   if (ec.value())
2434d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
2444d5abbe8Smrg }
2454d5abbe8Smrg 
2464d5abbe8Smrg namespace
2474d5abbe8Smrg {
248a3e9eb18Smrg   using std::filesystem::is_set;
2494d5abbe8Smrg 
2504d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
251181254a7Smrg   using posix::stat_type;
2524d5abbe8Smrg 
253a3e9eb18Smrg   using std::filesystem::is_not_found_errno;
254a3e9eb18Smrg   using std::filesystem::file_time;
255a3e9eb18Smrg #endif // _GLIBCXX_HAVE_SYS_STAT_H
256181254a7Smrg 
257a3e9eb18Smrg } // namespace
2584d5abbe8Smrg 
2594d5abbe8Smrg void
copy(const path & from,const path & to,copy_options options,error_code & ec)2604d5abbe8Smrg fs::copy(const path& from, const path& to, copy_options options,
2614d5abbe8Smrg 	 error_code& ec) noexcept
2624d5abbe8Smrg {
263f30ff588Smrg   const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
264f30ff588Smrg   const bool create_symlinks = is_set(options, copy_options::create_symlinks);
265f30ff588Smrg   const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
266f30ff588Smrg   const bool use_lstat = create_symlinks || skip_symlinks;
2674d5abbe8Smrg 
2684d5abbe8Smrg   file_status f, t;
2694d5abbe8Smrg   stat_type from_st, to_st;
2703f4ceed9Smrg   // _GLIBCXX_RESOLVE_LIB_DEFECTS
2713f4ceed9Smrg   // 2681. filesystem::copy() cannot copy symlinks
272f30ff588Smrg   if (use_lstat || copy_symlinks
273181254a7Smrg       ? posix::lstat(from.c_str(), &from_st)
274181254a7Smrg       : posix::stat(from.c_str(), &from_st))
2754d5abbe8Smrg     {
2764d5abbe8Smrg       ec.assign(errno, std::generic_category());
2774d5abbe8Smrg       return;
2784d5abbe8Smrg     }
2794d5abbe8Smrg   if (use_lstat
280181254a7Smrg       ? posix::lstat(to.c_str(), &to_st)
281181254a7Smrg       : posix::stat(to.c_str(), &to_st))
2824d5abbe8Smrg     {
2834d5abbe8Smrg       if (!is_not_found_errno(errno))
2844d5abbe8Smrg 	{
2854d5abbe8Smrg 	  ec.assign(errno, std::generic_category());
2864d5abbe8Smrg 	  return;
2874d5abbe8Smrg 	}
2884d5abbe8Smrg       t = file_status{file_type::not_found};
2894d5abbe8Smrg     }
2904d5abbe8Smrg   else
2914d5abbe8Smrg     t = make_file_status(to_st);
2924d5abbe8Smrg   f = make_file_status(from_st);
2934d5abbe8Smrg 
2944d5abbe8Smrg   if (exists(t) && !is_other(t) && !is_other(f)
2954d5abbe8Smrg       && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
2964d5abbe8Smrg     {
2974d5abbe8Smrg       ec = std::make_error_code(std::errc::file_exists);
2984d5abbe8Smrg       return;
2994d5abbe8Smrg     }
3004d5abbe8Smrg   if (is_other(f) || is_other(t))
3014d5abbe8Smrg     {
302b1e83836Smrg       ec = std::make_error_code(std::errc::invalid_argument);
3034d5abbe8Smrg       return;
3044d5abbe8Smrg     }
3054d5abbe8Smrg   if (is_directory(f) && is_regular_file(t))
3064d5abbe8Smrg     {
3074d5abbe8Smrg       ec = std::make_error_code(std::errc::is_a_directory);
3084d5abbe8Smrg       return;
3094d5abbe8Smrg     }
3104d5abbe8Smrg 
3114d5abbe8Smrg   if (is_symlink(f))
3124d5abbe8Smrg     {
3134d5abbe8Smrg       if (skip_symlinks)
3144d5abbe8Smrg 	ec.clear();
315f30ff588Smrg       else if (!exists(t) && copy_symlinks)
3164d5abbe8Smrg 	copy_symlink(from, to, ec);
3174d5abbe8Smrg       else
3184d5abbe8Smrg 	// Not clear what should be done here.
3194d5abbe8Smrg 	// "Otherwise report an error as specified in Error reporting (7)."
3204d5abbe8Smrg 	ec = std::make_error_code(std::errc::invalid_argument);
3214d5abbe8Smrg     }
3224d5abbe8Smrg   else if (is_regular_file(f))
3234d5abbe8Smrg     {
3244d5abbe8Smrg       if (is_set(options, copy_options::directories_only))
3254d5abbe8Smrg 	ec.clear();
3264d5abbe8Smrg       else if (create_symlinks)
3274d5abbe8Smrg 	create_symlink(from, to, ec);
3284d5abbe8Smrg       else if (is_set(options, copy_options::create_hard_links))
3294d5abbe8Smrg 	create_hard_link(from, to, ec);
3304d5abbe8Smrg       else if (is_directory(t))
331a3e9eb18Smrg 	do_copy_file(from.c_str(), (to / from.filename()).c_str(),
332a3e9eb18Smrg 		     copy_file_options(options), &from_st, nullptr, ec);
3334d5abbe8Smrg       else
3344d5abbe8Smrg 	{
3354d5abbe8Smrg 	  auto ptr = exists(t) ? &to_st : &from_st;
336a3e9eb18Smrg 	  do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
337a3e9eb18Smrg 		       &from_st, ptr,  ec);
3384d5abbe8Smrg 	}
3394d5abbe8Smrg     }
3403f4ceed9Smrg   // _GLIBCXX_RESOLVE_LIB_DEFECTS
3413f4ceed9Smrg   // 2682. filesystem::copy() won't create a symlink to a directory
3423f4ceed9Smrg   else if (is_directory(f) && create_symlinks)
3433f4ceed9Smrg     ec = std::make_error_code(errc::is_a_directory);
3444d5abbe8Smrg   else if (is_directory(f) && (is_set(options, copy_options::recursive)
3454d5abbe8Smrg 			       || options == copy_options::none))
3464d5abbe8Smrg     {
3474d5abbe8Smrg       if (!exists(t))
3484d5abbe8Smrg 	if (!create_directory(to, from, ec))
3494d5abbe8Smrg 	  return;
3504d5abbe8Smrg       // set an unused bit in options to disable further recursion
3514d5abbe8Smrg       if (!is_set(options, copy_options::recursive))
3524d5abbe8Smrg 	options |= static_cast<copy_options>(4096);
353a448f87cSmrg       for (const directory_entry& x : directory_iterator(from, ec))
354a448f87cSmrg 	{
3554d5abbe8Smrg 	  copy(x.path(), to/x.path().filename(), options, ec);
356a448f87cSmrg 	  if (ec)
357a448f87cSmrg 	    return;
358a448f87cSmrg 	}
3594d5abbe8Smrg     }
3603f4ceed9Smrg   // _GLIBCXX_RESOLVE_LIB_DEFECTS
3613f4ceed9Smrg   // 2683. filesystem::copy() says "no effects"
3623f4ceed9Smrg   else
3633f4ceed9Smrg     ec.clear();
3644d5abbe8Smrg }
3654d5abbe8Smrg 
3664d5abbe8Smrg bool
copy_file(const path & from,const path & to,copy_options option)3674d5abbe8Smrg fs::copy_file(const path& from, const path& to, copy_options option)
3684d5abbe8Smrg {
3694d5abbe8Smrg   error_code ec;
3704d5abbe8Smrg   bool result = copy_file(from, to, option, ec);
3714d5abbe8Smrg   if (ec.value())
3724d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
3734d5abbe8Smrg 	  ec));
3744d5abbe8Smrg   return result;
3754d5abbe8Smrg }
3764d5abbe8Smrg 
3774d5abbe8Smrg bool
copy_file(const path & from,const path & to,copy_options options,error_code & ec)378a3e9eb18Smrg fs::copy_file(const path& from, const path& to, copy_options options,
379a448f87cSmrg 	      error_code& ec)
3804d5abbe8Smrg {
3814d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
382a3e9eb18Smrg   return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
383a3e9eb18Smrg 		      nullptr, nullptr, ec);
3844d5abbe8Smrg #else
385b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
3864d5abbe8Smrg   return false;
3874d5abbe8Smrg #endif
3884d5abbe8Smrg }
3894d5abbe8Smrg 
3904d5abbe8Smrg 
3914d5abbe8Smrg void
copy_symlink(const path & existing_symlink,const path & new_symlink)3924d5abbe8Smrg fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
3934d5abbe8Smrg {
3944d5abbe8Smrg   error_code ec;
3954d5abbe8Smrg   copy_symlink(existing_symlink, new_symlink, ec);
3964d5abbe8Smrg   if (ec.value())
3974d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
3984d5abbe8Smrg 	  existing_symlink, new_symlink, ec));
3994d5abbe8Smrg }
4004d5abbe8Smrg 
4014d5abbe8Smrg void
copy_symlink(const path & existing_symlink,const path & new_symlink,error_code & ec)4024d5abbe8Smrg fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
4034d5abbe8Smrg 		 error_code& ec) noexcept
4044d5abbe8Smrg {
4054d5abbe8Smrg   auto p = read_symlink(existing_symlink, ec);
4064d5abbe8Smrg   if (ec.value())
4074d5abbe8Smrg     return;
4084d5abbe8Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
4094d5abbe8Smrg   if (is_directory(p))
4104d5abbe8Smrg     {
4114d5abbe8Smrg       create_directory_symlink(p, new_symlink, ec);
4124d5abbe8Smrg       return;
4134d5abbe8Smrg     }
4144d5abbe8Smrg #endif
4154d5abbe8Smrg   create_symlink(p, new_symlink, ec);
4164d5abbe8Smrg }
4174d5abbe8Smrg 
4184d5abbe8Smrg 
4194d5abbe8Smrg bool
create_directories(const path & p)4204d5abbe8Smrg fs::create_directories(const path& p)
4214d5abbe8Smrg {
4224d5abbe8Smrg   error_code ec;
4234d5abbe8Smrg   bool result = create_directories(p, ec);
4244d5abbe8Smrg   if (ec.value())
4254d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
4264d5abbe8Smrg 	  ec));
4274d5abbe8Smrg   return result;
4284d5abbe8Smrg }
4294d5abbe8Smrg 
4304d5abbe8Smrg bool
create_directories(const path & p,error_code & ec)431a448f87cSmrg fs::create_directories(const path& p, error_code& ec)
4324d5abbe8Smrg {
4334d5abbe8Smrg   if (p.empty())
4344d5abbe8Smrg     {
4354d5abbe8Smrg       ec = std::make_error_code(errc::invalid_argument);
4364d5abbe8Smrg       return false;
4374d5abbe8Smrg     }
438a3e9eb18Smrg 
439a448f87cSmrg   file_status st = status(p, ec);
440a3e9eb18Smrg   if (is_directory(st))
441a3e9eb18Smrg     return false;
442a3e9eb18Smrg   else if (ec && !status_known(st))
443a3e9eb18Smrg     return false;
444a3e9eb18Smrg   else if (exists(st))
445a3e9eb18Smrg     {
446a3e9eb18Smrg       if (!ec)
447a3e9eb18Smrg 	ec = std::make_error_code(std::errc::not_a_directory);
448a3e9eb18Smrg       return false;
449a3e9eb18Smrg     }
450a3e9eb18Smrg 
4514d5abbe8Smrg   std::stack<path> missing;
4524d5abbe8Smrg   path pp = p;
4534d5abbe8Smrg 
4544d5abbe8Smrg   while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
4554d5abbe8Smrg     {
4564d5abbe8Smrg       ec.clear();
4574d5abbe8Smrg       const auto& filename = pp.filename();
4584d5abbe8Smrg       if (!is_dot(filename) && !is_dotdot(filename))
459a3e9eb18Smrg 	{
460a3e9eb18Smrg 	  missing.push(std::move(pp));
461a3e9eb18Smrg 	  pp = missing.top().parent_path();
462a3e9eb18Smrg 	}
463a3e9eb18Smrg       else
464a3e9eb18Smrg 	pp = pp.parent_path();
4654d5abbe8Smrg     }
4664d5abbe8Smrg 
4674d5abbe8Smrg   if (ec || missing.empty())
4684d5abbe8Smrg     return false;
4694d5abbe8Smrg 
470a3e9eb18Smrg   bool created;
4714d5abbe8Smrg   do
4724d5abbe8Smrg     {
4734d5abbe8Smrg       const path& top = missing.top();
474a3e9eb18Smrg       created = create_directory(top, ec);
475a3e9eb18Smrg       if (ec)
476a3e9eb18Smrg 	return false;
4774d5abbe8Smrg       missing.pop();
4784d5abbe8Smrg     }
479a3e9eb18Smrg   while (!missing.empty());
4804d5abbe8Smrg 
481a3e9eb18Smrg   return created;
4824d5abbe8Smrg }
4834d5abbe8Smrg 
4844d5abbe8Smrg namespace
4854d5abbe8Smrg {
4864d5abbe8Smrg   bool
create_dir(const fs::path & p,fs::perms perm,std::error_code & ec)4874d5abbe8Smrg   create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
4884d5abbe8Smrg   {
489f30ff588Smrg     bool created = false;
490*0a307195Smrg #if _GLIBCXX_USE_MKDIR
491181254a7Smrg     posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
492181254a7Smrg     if (posix::mkdir(p.c_str(), mode))
4934d5abbe8Smrg       {
494f30ff588Smrg 	const int err = errno;
495b17d1066Smrg 	if (err != EEXIST || !is_directory(p, ec))
496f30ff588Smrg 	  ec.assign(err, std::generic_category());
4974d5abbe8Smrg       }
4984d5abbe8Smrg     else
4994d5abbe8Smrg       {
5004d5abbe8Smrg 	ec.clear();
501f30ff588Smrg 	created = true;
5024d5abbe8Smrg       }
5034d5abbe8Smrg #else
504b1e83836Smrg     ec = std::make_error_code(std::errc::function_not_supported);
5054d5abbe8Smrg #endif
506f30ff588Smrg     return created;
5074d5abbe8Smrg   }
5084d5abbe8Smrg } // namespace
5094d5abbe8Smrg 
5104d5abbe8Smrg bool
create_directory(const path & p)5114d5abbe8Smrg fs::create_directory(const path& p)
5124d5abbe8Smrg {
5134d5abbe8Smrg   error_code ec;
5144d5abbe8Smrg   bool result = create_directory(p, ec);
5154d5abbe8Smrg   if (ec.value())
5164d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
5174d5abbe8Smrg 	  ec));
5184d5abbe8Smrg   return result;
5194d5abbe8Smrg }
5204d5abbe8Smrg 
5214d5abbe8Smrg bool
create_directory(const path & p,error_code & ec)5224d5abbe8Smrg fs::create_directory(const path& p, error_code& ec) noexcept
5234d5abbe8Smrg {
5244d5abbe8Smrg   return create_dir(p, perms::all, ec);
5254d5abbe8Smrg }
5264d5abbe8Smrg 
5274d5abbe8Smrg 
5284d5abbe8Smrg bool
create_directory(const path & p,const path & attributes)5294d5abbe8Smrg fs::create_directory(const path& p, const path& attributes)
5304d5abbe8Smrg {
5314d5abbe8Smrg   error_code ec;
5324d5abbe8Smrg   bool result = create_directory(p, attributes, ec);
5334d5abbe8Smrg   if (ec.value())
5344d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
5354d5abbe8Smrg 	  ec));
5364d5abbe8Smrg   return result;
5374d5abbe8Smrg }
5384d5abbe8Smrg 
5394d5abbe8Smrg bool
create_directory(const path & p,const path & attributes,error_code & ec)5404d5abbe8Smrg fs::create_directory(const path& p, const path& attributes,
5414d5abbe8Smrg 		     error_code& ec) noexcept
5424d5abbe8Smrg {
5434d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
5444d5abbe8Smrg   stat_type st;
545181254a7Smrg   if (posix::stat(attributes.c_str(), &st))
5464d5abbe8Smrg     {
5474d5abbe8Smrg       ec.assign(errno, std::generic_category());
5484d5abbe8Smrg       return false;
5494d5abbe8Smrg     }
5504d5abbe8Smrg   return create_dir(p, static_cast<perms>(st.st_mode), ec);
5514d5abbe8Smrg #else
552b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
5534d5abbe8Smrg   return false;
5544d5abbe8Smrg #endif
5554d5abbe8Smrg }
5564d5abbe8Smrg 
5574d5abbe8Smrg 
5584d5abbe8Smrg void
create_directory_symlink(const path & to,const path & new_symlink)5594d5abbe8Smrg fs::create_directory_symlink(const path& to, const path& new_symlink)
5604d5abbe8Smrg {
5614d5abbe8Smrg   error_code ec;
5624d5abbe8Smrg   create_directory_symlink(to, new_symlink, ec);
5634d5abbe8Smrg   if (ec.value())
5644d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
5654d5abbe8Smrg 	  to, new_symlink, ec));
5664d5abbe8Smrg }
5674d5abbe8Smrg 
5684d5abbe8Smrg void
create_directory_symlink(const path & to,const path & new_symlink,error_code & ec)5694d5abbe8Smrg fs::create_directory_symlink(const path& to, const path& new_symlink,
5704d5abbe8Smrg 			     error_code& ec) noexcept
5714d5abbe8Smrg {
5724d5abbe8Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
573b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
5744d5abbe8Smrg #else
5754d5abbe8Smrg   create_symlink(to, new_symlink, ec);
5764d5abbe8Smrg #endif
5774d5abbe8Smrg }
5784d5abbe8Smrg 
5794d5abbe8Smrg 
5804d5abbe8Smrg void
create_hard_link(const path & to,const path & new_hard_link)5814d5abbe8Smrg fs::create_hard_link(const path& to, const path& new_hard_link)
5824d5abbe8Smrg {
5834d5abbe8Smrg   error_code ec;
5844d5abbe8Smrg   create_hard_link(to, new_hard_link, ec);
5854d5abbe8Smrg   if (ec.value())
5864d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
5874d5abbe8Smrg 	  to, new_hard_link, ec));
5884d5abbe8Smrg }
5894d5abbe8Smrg 
5904d5abbe8Smrg void
create_hard_link(const path & to,const path & new_hard_link,error_code & ec)5914d5abbe8Smrg fs::create_hard_link(const path& to, const path& new_hard_link,
5924d5abbe8Smrg 		     error_code& ec) noexcept
5934d5abbe8Smrg {
594181254a7Smrg #ifdef _GLIBCXX_HAVE_LINK
5954d5abbe8Smrg   if (::link(to.c_str(), new_hard_link.c_str()))
5964d5abbe8Smrg     ec.assign(errno, std::generic_category());
5974d5abbe8Smrg   else
5984d5abbe8Smrg     ec.clear();
599181254a7Smrg #elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
600181254a7Smrg   if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
601181254a7Smrg     ec.clear();
602181254a7Smrg   else
603b1e83836Smrg     ec = __last_system_error();
6044d5abbe8Smrg #else
605b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
6064d5abbe8Smrg #endif
6074d5abbe8Smrg }
6084d5abbe8Smrg 
6094d5abbe8Smrg void
create_symlink(const path & to,const path & new_symlink)6104d5abbe8Smrg fs::create_symlink(const path& to, const path& new_symlink)
6114d5abbe8Smrg {
6124d5abbe8Smrg   error_code ec;
6134d5abbe8Smrg   create_symlink(to, new_symlink, ec);
6144d5abbe8Smrg   if (ec.value())
6154d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
6164d5abbe8Smrg 	  to, new_symlink, ec));
6174d5abbe8Smrg }
6184d5abbe8Smrg 
6194d5abbe8Smrg void
create_symlink(const path & to,const path & new_symlink,error_code & ec)6204d5abbe8Smrg fs::create_symlink(const path& to, const path& new_symlink,
6214d5abbe8Smrg 		   error_code& ec) noexcept
6224d5abbe8Smrg {
623181254a7Smrg #ifdef _GLIBCXX_HAVE_SYMLINK
6244d5abbe8Smrg   if (::symlink(to.c_str(), new_symlink.c_str()))
6254d5abbe8Smrg     ec.assign(errno, std::generic_category());
6264d5abbe8Smrg   else
6274d5abbe8Smrg     ec.clear();
6284d5abbe8Smrg #else
629b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
6304d5abbe8Smrg #endif
6314d5abbe8Smrg }
6324d5abbe8Smrg 
6334d5abbe8Smrg fs::path
current_path()6344d5abbe8Smrg fs::current_path()
6354d5abbe8Smrg {
6364d5abbe8Smrg   error_code ec;
6374d5abbe8Smrg   path p = current_path(ec);
6384d5abbe8Smrg   if (ec.value())
6394d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
6404d5abbe8Smrg   return p;
6414d5abbe8Smrg }
6424d5abbe8Smrg 
6434d5abbe8Smrg fs::path
current_path(error_code & ec)6444d5abbe8Smrg fs::current_path(error_code& ec)
6454d5abbe8Smrg {
6464d5abbe8Smrg   path p;
647*0a307195Smrg #if _GLIBCXX_USE_GETCWD
648181254a7Smrg #if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
649181254a7Smrg   if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
6504d5abbe8Smrg     {
6514d5abbe8Smrg       p.assign(cwd.get());
6524d5abbe8Smrg       ec.clear();
6534d5abbe8Smrg     }
6544d5abbe8Smrg   else
6554d5abbe8Smrg     ec.assign(errno, std::generic_category());
6564d5abbe8Smrg #else
657181254a7Smrg #ifdef _PC_PATH_MAX
6584d5abbe8Smrg   long path_max = pathconf(".", _PC_PATH_MAX);
6594d5abbe8Smrg   size_t size;
6604d5abbe8Smrg   if (path_max == -1)
6614d5abbe8Smrg       size = 1024;
6624d5abbe8Smrg   else if (path_max > 10240)
6634d5abbe8Smrg       size = 10240;
6644d5abbe8Smrg   else
6654d5abbe8Smrg       size = path_max;
666181254a7Smrg #elif defined(PATH_MAX)
667181254a7Smrg   size_t size = PATH_MAX;
668181254a7Smrg #else
669181254a7Smrg   size_t size = 1024;
670181254a7Smrg #endif
6714d5abbe8Smrg   for (char_ptr buf; p.empty(); size *= 2)
6724d5abbe8Smrg     {
673181254a7Smrg       using char_type = fs::path::value_type;
674181254a7Smrg       buf.reset((char_type*)malloc(size * sizeof(char_type)));
6754d5abbe8Smrg       if (buf)
6764d5abbe8Smrg 	{
6774d5abbe8Smrg 	  if (getcwd(buf.get(), size))
6784d5abbe8Smrg 	    {
6794d5abbe8Smrg 	      p.assign(buf.get());
6804d5abbe8Smrg 	      ec.clear();
6814d5abbe8Smrg 	    }
6824d5abbe8Smrg 	  else if (errno != ERANGE)
6834d5abbe8Smrg 	    {
6844d5abbe8Smrg 	      ec.assign(errno, std::generic_category());
6854d5abbe8Smrg 	      return {};
6864d5abbe8Smrg 	    }
6874d5abbe8Smrg 	}
6884d5abbe8Smrg       else
6894d5abbe8Smrg 	{
6904d5abbe8Smrg 	  ec = std::make_error_code(std::errc::not_enough_memory);
6914d5abbe8Smrg 	  return {};
6924d5abbe8Smrg 	}
6934d5abbe8Smrg     }
6944d5abbe8Smrg #endif  // __GLIBC__
6954d5abbe8Smrg #else   // _GLIBCXX_HAVE_UNISTD_H
696b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
6974d5abbe8Smrg #endif
6984d5abbe8Smrg   return p;
6994d5abbe8Smrg }
7004d5abbe8Smrg 
7014d5abbe8Smrg void
current_path(const path & p)7024d5abbe8Smrg fs::current_path(const path& p)
7034d5abbe8Smrg {
7044d5abbe8Smrg   error_code ec;
7054d5abbe8Smrg   current_path(p, ec);
7064d5abbe8Smrg   if (ec.value())
7074d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
7084d5abbe8Smrg }
7094d5abbe8Smrg 
7104d5abbe8Smrg void
current_path(const path & p,error_code & ec)7114d5abbe8Smrg fs::current_path(const path& p, error_code& ec) noexcept
7124d5abbe8Smrg {
713*0a307195Smrg #if _GLIBCXX_USE_CHDIR
714181254a7Smrg   if (posix::chdir(p.c_str()))
7154d5abbe8Smrg     ec.assign(errno, std::generic_category());
7164d5abbe8Smrg   else
7174d5abbe8Smrg     ec.clear();
7184d5abbe8Smrg #else
719b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
7204d5abbe8Smrg #endif
7214d5abbe8Smrg }
7224d5abbe8Smrg 
7234d5abbe8Smrg bool
equivalent(const path & p1,const path & p2)7244d5abbe8Smrg fs::equivalent(const path& p1, const path& p2)
7254d5abbe8Smrg {
7264d5abbe8Smrg   error_code ec;
7274d5abbe8Smrg   auto result = equivalent(p1, p2, ec);
7283f4ceed9Smrg   if (ec)
7294d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
7304d5abbe8Smrg 	  p1, p2, ec));
7314d5abbe8Smrg   return result;
7324d5abbe8Smrg }
7334d5abbe8Smrg 
7344d5abbe8Smrg bool
equivalent(const path & p1,const path & p2,error_code & ec)7354d5abbe8Smrg fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
7364d5abbe8Smrg {
7374d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
7383f4ceed9Smrg   int err = 0;
7393f4ceed9Smrg   file_status s1, s2;
7404d5abbe8Smrg   stat_type st1, st2;
741181254a7Smrg   if (posix::stat(p1.c_str(), &st1) == 0)
7423f4ceed9Smrg     s1 = make_file_status(st1);
7433f4ceed9Smrg   else if (is_not_found_errno(errno))
7443f4ceed9Smrg     s1.type(file_type::not_found);
7453f4ceed9Smrg   else
7463f4ceed9Smrg     err = errno;
7473f4ceed9Smrg 
748181254a7Smrg   if (posix::stat(p2.c_str(), &st2) == 0)
7493f4ceed9Smrg     s2 = make_file_status(st2);
7503f4ceed9Smrg   else if (is_not_found_errno(errno))
7513f4ceed9Smrg     s2.type(file_type::not_found);
7523f4ceed9Smrg   else
7533f4ceed9Smrg     err = errno;
7543f4ceed9Smrg 
7553f4ceed9Smrg   if (exists(s1) && exists(s2))
7564d5abbe8Smrg     {
7574d5abbe8Smrg       if (is_other(s1) && is_other(s2))
7584d5abbe8Smrg 	{
759b1e83836Smrg 	  ec = std::__unsupported();
7604d5abbe8Smrg 	  return false;
7614d5abbe8Smrg 	}
7624d5abbe8Smrg       ec.clear();
7633f4ceed9Smrg       if (is_other(s1) || is_other(s2))
7643f4ceed9Smrg 	return false;
7654d5abbe8Smrg       return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
7664d5abbe8Smrg     }
767*0a307195Smrg   else if (!exists(s1) || !exists(s2))
7684d5abbe8Smrg     ec = std::make_error_code(std::errc::no_such_file_or_directory);
7693f4ceed9Smrg   else if (err)
7703f4ceed9Smrg     ec.assign(err, std::generic_category());
7713f4ceed9Smrg   else
7723f4ceed9Smrg     ec.clear();
7734d5abbe8Smrg   return false;
7744d5abbe8Smrg #else
775b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
7764d5abbe8Smrg #endif
7774d5abbe8Smrg   return false;
7784d5abbe8Smrg }
7794d5abbe8Smrg 
7804d5abbe8Smrg std::uintmax_t
file_size(const path & p)7814d5abbe8Smrg fs::file_size(const path& p)
7824d5abbe8Smrg {
7834d5abbe8Smrg   error_code ec;
7844d5abbe8Smrg   auto sz = file_size(p, ec);
7854d5abbe8Smrg   if (ec.value())
7864d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
7874d5abbe8Smrg   return sz;
7884d5abbe8Smrg }
7894d5abbe8Smrg 
7904d5abbe8Smrg namespace
7914d5abbe8Smrg {
7924d5abbe8Smrg   template<typename Accessor, typename T>
7934d5abbe8Smrg     inline T
do_stat(const fs::path & p,std::error_code & ec,Accessor f,T deflt)7944d5abbe8Smrg     do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
7954d5abbe8Smrg     {
7964d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
7974d5abbe8Smrg       stat_type st;
798181254a7Smrg       if (posix::stat(p.c_str(), &st))
7994d5abbe8Smrg 	{
8004d5abbe8Smrg 	  ec.assign(errno, std::generic_category());
8014d5abbe8Smrg 	  return deflt;
8024d5abbe8Smrg 	}
8034d5abbe8Smrg       ec.clear();
8044d5abbe8Smrg       return f(st);
8054d5abbe8Smrg #else
806b1e83836Smrg       ec = std::make_error_code(std::errc::function_not_supported);
8074d5abbe8Smrg       return deflt;
8084d5abbe8Smrg #endif
8094d5abbe8Smrg     }
8104d5abbe8Smrg }
8114d5abbe8Smrg 
8124d5abbe8Smrg std::uintmax_t
file_size(const path & p,error_code & ec)8134d5abbe8Smrg fs::file_size(const path& p, error_code& ec) noexcept
8144d5abbe8Smrg {
8154d5abbe8Smrg   struct S
8164d5abbe8Smrg   {
8174d5abbe8Smrg     S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
8184d5abbe8Smrg     S() : type(file_type::not_found) { }
8194d5abbe8Smrg     file_type type;
820a3e9eb18Smrg     uintmax_t size;
8214d5abbe8Smrg   };
8224d5abbe8Smrg   auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
8234d5abbe8Smrg   if (s.type == file_type::regular)
8244d5abbe8Smrg     return s.size;
8254d5abbe8Smrg   if (!ec)
8264d5abbe8Smrg     {
8274d5abbe8Smrg       if (s.type == file_type::directory)
8284d5abbe8Smrg 	ec = std::make_error_code(std::errc::is_a_directory);
8294d5abbe8Smrg       else
830b1e83836Smrg 	ec = std::__unsupported();
8314d5abbe8Smrg     }
8324d5abbe8Smrg   return -1;
8334d5abbe8Smrg }
8344d5abbe8Smrg 
8354d5abbe8Smrg std::uintmax_t
hard_link_count(const path & p)8364d5abbe8Smrg fs::hard_link_count(const path& p)
8374d5abbe8Smrg {
8384d5abbe8Smrg   error_code ec;
8394d5abbe8Smrg   auto count = hard_link_count(p, ec);
8404d5abbe8Smrg   if (ec.value())
8414d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
8424d5abbe8Smrg   return count;
8434d5abbe8Smrg }
8444d5abbe8Smrg 
8454d5abbe8Smrg std::uintmax_t
hard_link_count(const path & p,error_code & ec)8464d5abbe8Smrg fs::hard_link_count(const path& p, error_code& ec) noexcept
8474d5abbe8Smrg {
848181254a7Smrg   return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
8494d5abbe8Smrg 		 static_cast<uintmax_t>(-1));
8504d5abbe8Smrg }
8514d5abbe8Smrg 
8524d5abbe8Smrg bool
is_empty(const path & p)8534d5abbe8Smrg fs::is_empty(const path& p)
8544d5abbe8Smrg {
8553f4ceed9Smrg   error_code ec;
8563f4ceed9Smrg   bool e = is_empty(p, ec);
8573f4ceed9Smrg   if (ec)
8583f4ceed9Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
8593f4ceed9Smrg 					     p, ec));
8603f4ceed9Smrg   return e;
8614d5abbe8Smrg }
8624d5abbe8Smrg 
8634d5abbe8Smrg bool
is_empty(const path & p,error_code & ec)8644d5abbe8Smrg fs::is_empty(const path& p, error_code& ec) noexcept
8654d5abbe8Smrg {
8664d5abbe8Smrg   auto s = status(p, ec);
8673f4ceed9Smrg   if (ec)
8684d5abbe8Smrg     return false;
8693f4ceed9Smrg   bool empty = fs::is_directory(s)
8704d5abbe8Smrg     ? fs::directory_iterator(p, ec) == fs::directory_iterator()
8714d5abbe8Smrg     : fs::file_size(p, ec) == 0;
8723f4ceed9Smrg   return ec ? false : empty;
8734d5abbe8Smrg }
8744d5abbe8Smrg 
8754d5abbe8Smrg fs::file_time_type
last_write_time(const path & p)8764d5abbe8Smrg fs::last_write_time(const path& p)
8774d5abbe8Smrg {
8784d5abbe8Smrg   error_code ec;
8794d5abbe8Smrg   auto t = last_write_time(p, ec);
8804d5abbe8Smrg   if (ec.value())
8814d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
8824d5abbe8Smrg   return t;
8834d5abbe8Smrg }
8844d5abbe8Smrg 
8854d5abbe8Smrg fs::file_time_type
last_write_time(const path & p,error_code & ec)8864d5abbe8Smrg fs::last_write_time(const path& p, error_code& ec) noexcept
8874d5abbe8Smrg {
8883f4ceed9Smrg   return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
8894d5abbe8Smrg 		 file_time_type::min());
8904d5abbe8Smrg }
8914d5abbe8Smrg 
8924d5abbe8Smrg void
last_write_time(const path & p,file_time_type new_time)8934d5abbe8Smrg fs::last_write_time(const path& p, file_time_type new_time)
8944d5abbe8Smrg {
8954d5abbe8Smrg   error_code ec;
8964d5abbe8Smrg   last_write_time(p, new_time, ec);
8974d5abbe8Smrg   if (ec.value())
8984d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
8994d5abbe8Smrg }
9004d5abbe8Smrg 
9014d5abbe8Smrg void
last_write_time(const path & p,file_time_type new_time,error_code & ec)9024d5abbe8Smrg fs::last_write_time(const path& p __attribute__((__unused__)),
9034d5abbe8Smrg 		    file_time_type new_time, error_code& ec) noexcept
9044d5abbe8Smrg {
9054d5abbe8Smrg   auto d = new_time.time_since_epoch();
9064d5abbe8Smrg   auto s = chrono::duration_cast<chrono::seconds>(d);
9074d5abbe8Smrg #if _GLIBCXX_USE_UTIMENSAT
9084d5abbe8Smrg   auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
9093f4ceed9Smrg   if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
9103f4ceed9Smrg     {
9113f4ceed9Smrg       --s;
9123f4ceed9Smrg       ns += chrono::seconds(1);
9133f4ceed9Smrg     }
9144d5abbe8Smrg   struct ::timespec ts[2];
9154d5abbe8Smrg   ts[0].tv_sec = 0;
9164d5abbe8Smrg   ts[0].tv_nsec = UTIME_OMIT;
9174d5abbe8Smrg   ts[1].tv_sec = static_cast<std::time_t>(s.count());
9184d5abbe8Smrg   ts[1].tv_nsec = static_cast<long>(ns.count());
9194d5abbe8Smrg   if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
9204d5abbe8Smrg     ec.assign(errno, std::generic_category());
9214d5abbe8Smrg   else
9224d5abbe8Smrg     ec.clear();
923181254a7Smrg #elif _GLIBCXX_USE_UTIME && _GLIBCXX_HAVE_SYS_STAT_H
924181254a7Smrg   posix::utimbuf times;
9254d5abbe8Smrg   times.modtime = s.count();
9264d5abbe8Smrg   times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
9274d5abbe8Smrg 			 times.modtime);
928181254a7Smrg   if (posix::utime(p.c_str(), &times))
9294d5abbe8Smrg     ec.assign(errno, std::generic_category());
9304d5abbe8Smrg   else
9314d5abbe8Smrg     ec.clear();
9324d5abbe8Smrg #else
933b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
9344d5abbe8Smrg #endif
9354d5abbe8Smrg }
9364d5abbe8Smrg 
9374d5abbe8Smrg void
permissions(const path & p,perms prms)9384d5abbe8Smrg fs::permissions(const path& p, perms prms)
9394d5abbe8Smrg {
9404d5abbe8Smrg   error_code ec;
9414d5abbe8Smrg   permissions(p, prms, ec);
9424d5abbe8Smrg   if (ec.value())
9434d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
9444d5abbe8Smrg }
9454d5abbe8Smrg 
9463f4ceed9Smrg void
permissions(const path & p,perms prms,error_code & ec)9473f4ceed9Smrg fs::permissions(const path& p, perms prms, error_code& ec) noexcept
9484d5abbe8Smrg {
949*0a307195Smrg #if _GLIBCXX_USE_FCHMODAT || _GLIBCXX_USE_CHMOD
9503f4ceed9Smrg   const bool add = is_set(prms, perms::add_perms);
9513f4ceed9Smrg   const bool remove = is_set(prms, perms::remove_perms);
9523f4ceed9Smrg   const bool nofollow = is_set(prms, perms::symlink_nofollow);
9533f4ceed9Smrg   if (add && remove)
9543f4ceed9Smrg     {
9553f4ceed9Smrg       ec = std::make_error_code(std::errc::invalid_argument);
9563f4ceed9Smrg       return;
9573f4ceed9Smrg     }
9583f4ceed9Smrg 
9593f4ceed9Smrg   prms &= perms::mask;
9603f4ceed9Smrg 
9613f4ceed9Smrg   file_status st;
9623f4ceed9Smrg   if (add || remove || nofollow)
9633f4ceed9Smrg     {
9643f4ceed9Smrg       st = nofollow ? symlink_status(p, ec) : status(p, ec);
9653f4ceed9Smrg       if (ec)
9663f4ceed9Smrg 	return;
9673f4ceed9Smrg       auto curr = st.permissions();
9683f4ceed9Smrg       if (add)
9693f4ceed9Smrg 	prms |= curr;
9703f4ceed9Smrg       else if (remove)
9713f4ceed9Smrg 	prms = curr & ~prms;
9723f4ceed9Smrg     }
9733f4ceed9Smrg 
9743f4ceed9Smrg   int err = 0;
9754d5abbe8Smrg #if _GLIBCXX_USE_FCHMODAT
9763f4ceed9Smrg   const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
9773f4ceed9Smrg   if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
9783f4ceed9Smrg     err = errno;
9794d5abbe8Smrg #else
9803f4ceed9Smrg   if (nofollow && is_symlink(st))
981b1e83836Smrg     ec = std::__unsupported();
982181254a7Smrg   else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
9833f4ceed9Smrg     err = errno;
9844d5abbe8Smrg #endif
9853f4ceed9Smrg 
9863f4ceed9Smrg   if (err)
9873f4ceed9Smrg     ec.assign(err, std::generic_category());
9884d5abbe8Smrg   else
9894d5abbe8Smrg     ec.clear();
990*0a307195Smrg #else
991*0a307195Smrg   ec = std::make_error_code(std::errc::function_not_supported);
992*0a307195Smrg #endif
9934d5abbe8Smrg }
9944d5abbe8Smrg 
9954d5abbe8Smrg fs::path
read_symlink(const path & p)9964d5abbe8Smrg fs::read_symlink(const path& p)
9974d5abbe8Smrg {
9984d5abbe8Smrg   error_code ec;
9994d5abbe8Smrg   path tgt = read_symlink(p, ec);
10004d5abbe8Smrg   if (ec.value())
10014d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
10024d5abbe8Smrg   return tgt;
10034d5abbe8Smrg }
10044d5abbe8Smrg 
read_symlink(const path & p,error_code & ec)1005181254a7Smrg fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
10064d5abbe8Smrg {
1007d79abf08Smrg   path result;
1008181254a7Smrg #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
10094d5abbe8Smrg   stat_type st;
1010fb8a8121Smrg   if (posix::lstat(p.c_str(), &st))
10114d5abbe8Smrg     {
10124d5abbe8Smrg       ec.assign(errno, std::generic_category());
1013d79abf08Smrg       return result;
10144d5abbe8Smrg     }
1015fb8a8121Smrg   else if (!fs::is_symlink(make_file_status(st)))
1016fb8a8121Smrg     {
1017fb8a8121Smrg       ec.assign(EINVAL, std::generic_category());
1018fb8a8121Smrg       return result;
1019fb8a8121Smrg     }
1020fb8a8121Smrg 
1021d79abf08Smrg   std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1022d79abf08Smrg   do
1023d79abf08Smrg     {
1024a3e9eb18Smrg       ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
10254d5abbe8Smrg       if (len == -1)
10264d5abbe8Smrg 	{
10274d5abbe8Smrg 	  ec.assign(errno, std::generic_category());
1028d79abf08Smrg 	  return result;
10294d5abbe8Smrg 	}
1030d79abf08Smrg       else if (len == (ssize_t)buf.size())
1031d79abf08Smrg 	{
1032d79abf08Smrg 	  if (buf.size() > 4096)
1033d79abf08Smrg 	    {
1034d79abf08Smrg 	      ec.assign(ENAMETOOLONG, std::generic_category());
1035d79abf08Smrg 	      return result;
1036d79abf08Smrg 	    }
1037d79abf08Smrg 	  buf.resize(buf.size() * 2);
1038d79abf08Smrg 	}
1039d79abf08Smrg       else
1040d79abf08Smrg 	{
1041d79abf08Smrg 	  buf.resize(len);
1042d79abf08Smrg 	  result.assign(buf);
10433f4ceed9Smrg 	  ec.clear();
1044d79abf08Smrg 	  break;
1045d79abf08Smrg 	}
1046d79abf08Smrg     }
1047d79abf08Smrg   while (true);
10484d5abbe8Smrg #else
1049b1e83836Smrg   ec = std::make_error_code(std::errc::function_not_supported);
10504d5abbe8Smrg #endif
1051d79abf08Smrg   return result;
10524d5abbe8Smrg }
10534d5abbe8Smrg 
10544d5abbe8Smrg 
10554d5abbe8Smrg bool
remove(const path & p)10564d5abbe8Smrg fs::remove(const path& p)
10574d5abbe8Smrg {
10584d5abbe8Smrg   error_code ec;
10594d5abbe8Smrg   bool result = fs::remove(p, ec);
1060b17d1066Smrg   if (ec)
10614d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
10624d5abbe8Smrg   return result;
10634d5abbe8Smrg }
10644d5abbe8Smrg 
10654d5abbe8Smrg bool
remove(const path & p,error_code & ec)10664d5abbe8Smrg fs::remove(const path& p, error_code& ec) noexcept
10674d5abbe8Smrg {
1068181254a7Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1069181254a7Smrg   auto st = symlink_status(p, ec);
1070181254a7Smrg   if (exists(st))
1071181254a7Smrg     {
1072181254a7Smrg       if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
1073181254a7Smrg 	  || DeleteFileW(p.c_str()))
1074181254a7Smrg 	{
1075181254a7Smrg 	  ec.clear();
1076181254a7Smrg 	  return true;
1077181254a7Smrg 	}
1078181254a7Smrg       else if (!ec)
1079b1e83836Smrg 	ec = __last_system_error();
1080181254a7Smrg     }
1081181254a7Smrg   else if (status_known(st))
1082181254a7Smrg     ec.clear();
1083181254a7Smrg #else
10844d5abbe8Smrg   if (::remove(p.c_str()) == 0)
10854d5abbe8Smrg     {
10864d5abbe8Smrg       ec.clear();
10874d5abbe8Smrg       return true;
10884d5abbe8Smrg     }
1089d79abf08Smrg   else if (errno == ENOENT)
1090d79abf08Smrg     ec.clear();
10914d5abbe8Smrg   else
10924d5abbe8Smrg     ec.assign(errno, std::generic_category());
1093181254a7Smrg #endif
10944d5abbe8Smrg   return false;
10954d5abbe8Smrg }
10964d5abbe8Smrg 
10974d5abbe8Smrg 
10984d5abbe8Smrg std::uintmax_t
remove_all(const path & p)10994d5abbe8Smrg fs::remove_all(const path& p)
11004d5abbe8Smrg {
11014d5abbe8Smrg   error_code ec;
1102d79abf08Smrg   const auto result = remove_all(p, ec);
1103b17d1066Smrg   if (ec)
11044d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
11054d5abbe8Smrg   return result;
11064d5abbe8Smrg }
11074d5abbe8Smrg 
11084d5abbe8Smrg std::uintmax_t
remove_all(const path & p,error_code & ec)1109a448f87cSmrg fs::remove_all(const path& p, error_code& ec)
11104d5abbe8Smrg {
1111b1e83836Smrg   // Use the C++17 implementation.
1112b1e83836Smrg   return std::filesystem::remove_all(p.native(), ec);
11134d5abbe8Smrg }
11144d5abbe8Smrg 
11154d5abbe8Smrg void
rename(const path & from,const path & to)11164d5abbe8Smrg fs::rename(const path& from, const path& to)
11174d5abbe8Smrg {
11184d5abbe8Smrg   error_code ec;
11194d5abbe8Smrg   rename(from, to, ec);
11204d5abbe8Smrg   if (ec.value())
11214d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
11224d5abbe8Smrg }
11234d5abbe8Smrg 
11244d5abbe8Smrg void
rename(const path & from,const path & to,error_code & ec)11254d5abbe8Smrg fs::rename(const path& from, const path& to, error_code& ec) noexcept
11264d5abbe8Smrg {
1127181254a7Smrg   if (posix::rename(from.c_str(), to.c_str()))
11284d5abbe8Smrg     ec.assign(errno, std::generic_category());
11294d5abbe8Smrg   else
11304d5abbe8Smrg     ec.clear();
11314d5abbe8Smrg }
11324d5abbe8Smrg 
11334d5abbe8Smrg void
resize_file(const path & p,uintmax_t size)11344d5abbe8Smrg fs::resize_file(const path& p, uintmax_t size)
11354d5abbe8Smrg {
11364d5abbe8Smrg   error_code ec;
11374d5abbe8Smrg   resize_file(p, size, ec);
11384d5abbe8Smrg   if (ec.value())
11394d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
11404d5abbe8Smrg }
11414d5abbe8Smrg 
11424d5abbe8Smrg void
resize_file(const path & p,uintmax_t size,error_code & ec)11434d5abbe8Smrg fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
11444d5abbe8Smrg {
1145b1e83836Smrg   if (size > static_cast<uintmax_t>(std::numeric_limits<posix::off_t>::max()))
11464d5abbe8Smrg     ec.assign(EINVAL, std::generic_category());
1147181254a7Smrg   else if (posix::truncate(p.c_str(), size))
11484d5abbe8Smrg     ec.assign(errno, std::generic_category());
11494d5abbe8Smrg   else
11504d5abbe8Smrg     ec.clear();
11514d5abbe8Smrg }
11524d5abbe8Smrg 
11534d5abbe8Smrg 
11544d5abbe8Smrg fs::space_info
space(const path & p)11554d5abbe8Smrg fs::space(const path& p)
11564d5abbe8Smrg {
11574d5abbe8Smrg   error_code ec;
11584d5abbe8Smrg   space_info s = space(p, ec);
11594d5abbe8Smrg   if (ec.value())
11604d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
11614d5abbe8Smrg   return s;
11624d5abbe8Smrg }
11634d5abbe8Smrg 
11644d5abbe8Smrg fs::space_info
space(const path & p,error_code & ec)11654d5abbe8Smrg fs::space(const path& p, error_code& ec) noexcept
11664d5abbe8Smrg {
11674d5abbe8Smrg   space_info info = {
11684d5abbe8Smrg     static_cast<uintmax_t>(-1),
11694d5abbe8Smrg     static_cast<uintmax_t>(-1),
11704d5abbe8Smrg     static_cast<uintmax_t>(-1)
11714d5abbe8Smrg   };
1172181254a7Smrg #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1173181254a7Smrg   path dir = absolute(p);
1174181254a7Smrg   dir.remove_filename();
1175181254a7Smrg   auto str = dir.c_str();
11764d5abbe8Smrg #else
1177181254a7Smrg   auto str = p.c_str();
11784d5abbe8Smrg #endif
1179181254a7Smrg   fs::do_space(str, info.capacity, info.free, info.available, ec);
11804d5abbe8Smrg   return info;
11814d5abbe8Smrg }
11824d5abbe8Smrg 
1183b1e83836Smrg #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
has_trailing_slash(const fs::path & p)1184b1e83836Smrg static bool has_trailing_slash(const fs::path& p)
1185b1e83836Smrg {
1186b1e83836Smrg   wchar_t c = p.native().back();
1187b1e83836Smrg   return c == '/' || c == L'\\';
1188b1e83836Smrg }
1189b1e83836Smrg #endif
1190b1e83836Smrg 
11914d5abbe8Smrg #ifdef _GLIBCXX_HAVE_SYS_STAT_H
11924d5abbe8Smrg fs::file_status
status(const fs::path & p,error_code & ec)11933f4ceed9Smrg fs::status(const fs::path& p, error_code& ec) noexcept
11944d5abbe8Smrg {
11954d5abbe8Smrg   file_status status;
1196b1e83836Smrg 
1197b1e83836Smrg   auto str = p.c_str();
1198b1e83836Smrg 
1199b1e83836Smrg #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1200b1e83836Smrg   // stat() fails if there's a trailing slash (PR 88881)
1201b1e83836Smrg   path p2;
1202b1e83836Smrg   if (p.has_relative_path() && has_trailing_slash(p))
1203b1e83836Smrg     {
1204b1e83836Smrg       __try
1205b1e83836Smrg 	{
1206b1e83836Smrg 	  p2 = p.parent_path();
1207b1e83836Smrg 	  str = p2.c_str();
1208b1e83836Smrg 	}
1209b1e83836Smrg       __catch(const bad_alloc&)
1210b1e83836Smrg 	{
1211b1e83836Smrg 	  ec = std::make_error_code(std::errc::not_enough_memory);
1212b1e83836Smrg 	  return status;
1213b1e83836Smrg 	}
1214b1e83836Smrg       str = p2.c_str();
1215b1e83836Smrg     }
1216b1e83836Smrg #endif
1217b1e83836Smrg 
12184d5abbe8Smrg   stat_type st;
1219b1e83836Smrg   if (posix::stat(str, &st))
12204d5abbe8Smrg     {
12214d5abbe8Smrg       int err = errno;
12224d5abbe8Smrg       ec.assign(err, std::generic_category());
12234d5abbe8Smrg       if (is_not_found_errno(err))
12244d5abbe8Smrg 	status.type(file_type::not_found);
12253f4ceed9Smrg #ifdef EOVERFLOW
12263f4ceed9Smrg       else if (err == EOVERFLOW)
12273f4ceed9Smrg 	status.type(file_type::unknown);
12283f4ceed9Smrg #endif
12294d5abbe8Smrg     }
12304d5abbe8Smrg   else
12314d5abbe8Smrg     {
12324d5abbe8Smrg       status = make_file_status(st);
12334d5abbe8Smrg       ec.clear();
12344d5abbe8Smrg     }
12354d5abbe8Smrg   return status;
12364d5abbe8Smrg }
12374d5abbe8Smrg 
12384d5abbe8Smrg fs::file_status
symlink_status(const fs::path & p,std::error_code & ec)12394d5abbe8Smrg fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
12404d5abbe8Smrg {
12414d5abbe8Smrg   file_status status;
1242b1e83836Smrg 
1243b1e83836Smrg   auto str = p.c_str();
1244b1e83836Smrg 
1245b1e83836Smrg #if _GLIBCXX_FILESYSTEM_IS_WINDOWS
1246b1e83836Smrg   // stat() fails if there's a trailing slash (PR 88881)
1247b1e83836Smrg   path p2;
1248b1e83836Smrg   if (p.has_relative_path() && has_trailing_slash(p))
1249b1e83836Smrg     {
1250b1e83836Smrg       __try
1251b1e83836Smrg 	{
1252b1e83836Smrg 	  p2 = p.parent_path();
1253b1e83836Smrg 	  str = p2.c_str();
1254b1e83836Smrg 	}
1255b1e83836Smrg       __catch(const bad_alloc&)
1256b1e83836Smrg 	{
1257b1e83836Smrg 	  ec = std::make_error_code(std::errc::not_enough_memory);
1258b1e83836Smrg 	  return status;
1259b1e83836Smrg 	}
1260b1e83836Smrg       str = p2.c_str();
1261b1e83836Smrg     }
1262b1e83836Smrg #endif
1263b1e83836Smrg 
12644d5abbe8Smrg   stat_type st;
1265b1e83836Smrg   if (posix::lstat(str, &st))
12664d5abbe8Smrg     {
12674d5abbe8Smrg       int err = errno;
12684d5abbe8Smrg       ec.assign(err, std::generic_category());
12694d5abbe8Smrg       if (is_not_found_errno(err))
12704d5abbe8Smrg 	status.type(file_type::not_found);
12714d5abbe8Smrg     }
12724d5abbe8Smrg   else
12734d5abbe8Smrg     {
12744d5abbe8Smrg       status = make_file_status(st);
12754d5abbe8Smrg       ec.clear();
12764d5abbe8Smrg     }
12774d5abbe8Smrg   return status;
12784d5abbe8Smrg }
12794d5abbe8Smrg #endif
12804d5abbe8Smrg 
12814d5abbe8Smrg fs::file_status
status(const fs::path & p)12824d5abbe8Smrg fs::status(const fs::path& p)
12834d5abbe8Smrg {
12844d5abbe8Smrg   std::error_code ec;
12854d5abbe8Smrg   auto result = status(p, ec);
12864d5abbe8Smrg   if (result.type() == file_type::none)
12874d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
12884d5abbe8Smrg   return result;
12894d5abbe8Smrg }
12904d5abbe8Smrg 
12914d5abbe8Smrg fs::file_status
symlink_status(const fs::path & p)12924d5abbe8Smrg fs::symlink_status(const fs::path& p)
12934d5abbe8Smrg {
12944d5abbe8Smrg   std::error_code ec;
12954d5abbe8Smrg   auto result = symlink_status(p, ec);
12964d5abbe8Smrg   if (result.type() == file_type::none)
12974d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
12984d5abbe8Smrg   return result;
12994d5abbe8Smrg }
13004d5abbe8Smrg 
13014d5abbe8Smrg fs::path
system_complete(const path & p)13024d5abbe8Smrg fs::system_complete(const path& p)
13034d5abbe8Smrg {
13044d5abbe8Smrg   error_code ec;
13054d5abbe8Smrg   path comp = system_complete(p, ec);
13064d5abbe8Smrg   if (ec.value())
13074d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
13084d5abbe8Smrg   return comp;
13094d5abbe8Smrg }
13104d5abbe8Smrg 
13114d5abbe8Smrg fs::path
system_complete(const path & p,error_code & ec)13124d5abbe8Smrg fs::system_complete(const path& p, error_code& ec)
13134d5abbe8Smrg {
13144d5abbe8Smrg   path base = current_path(ec);
13154d5abbe8Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
13164d5abbe8Smrg   if (p.is_absolute() || !p.has_root_name()
13174d5abbe8Smrg       || p.root_name() == base.root_name())
13184d5abbe8Smrg     return absolute(p, base);
13194d5abbe8Smrg   // else TODO
1320b1e83836Smrg   ec = std::__unsupported();
13214d5abbe8Smrg   return {};
13224d5abbe8Smrg #else
13234d5abbe8Smrg   if (ec.value())
13244d5abbe8Smrg     return {};
13254d5abbe8Smrg   return absolute(p, base);
13264d5abbe8Smrg #endif
13274d5abbe8Smrg }
13284d5abbe8Smrg 
1329b1e83836Smrg fs::path
temp_directory_path()1330b1e83836Smrg fs::temp_directory_path()
13314d5abbe8Smrg {
13324d5abbe8Smrg   error_code ec;
13334d5abbe8Smrg   path tmp = temp_directory_path(ec);
13344d5abbe8Smrg   if (ec.value())
13354d5abbe8Smrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
13364d5abbe8Smrg   return tmp;
13374d5abbe8Smrg }
13384d5abbe8Smrg 
1339b1e83836Smrg fs::path
temp_directory_path(error_code & ec)1340b1e83836Smrg fs::temp_directory_path(error_code& ec)
13414d5abbe8Smrg {
1342b1e83836Smrg   path p = fs::get_temp_directory_from_env(ec);
1343b1e83836Smrg   if (ec)
1344181254a7Smrg     return p;
13453f4ceed9Smrg   auto st = status(p, ec);
1346181254a7Smrg   if (ec)
1347181254a7Smrg     p.clear();
1348181254a7Smrg   else if (!is_directory(st))
13493f4ceed9Smrg     {
1350181254a7Smrg       p.clear();
13514d5abbe8Smrg       ec = std::make_error_code(std::errc::not_a_directory);
13523f4ceed9Smrg     }
1353181254a7Smrg   return p;
13544d5abbe8Smrg }
1355