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(), ×))
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