Home | History | Annotate | Download | only in filesystem
      1 //===--------------------- filesystem/ops.cpp -----------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "experimental/filesystem"
     11 #include "iterator"
     12 #include "fstream"
     13 #include "type_traits"
     14 #include "random"  /* for unique_path */
     15 #include "cstdlib"
     16 #include "climits"
     17 
     18 #include <unistd.h>
     19 #include <sys/stat.h>
     20 #include <sys/statvfs.h>
     21 #include <fcntl.h>  /* values for fchmodat */
     22 #if !defined(UTIME_OMIT)
     23 #include <sys/time.h> // for ::utimes as used in __last_write_time
     24 #endif
     25 
     26 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM
     27 
     28 filesystem_error::~filesystem_error() {}
     29 
     30 
     31 //                       POSIX HELPERS
     32 
     33 namespace detail { namespace  {
     34 
     35 using value_type = path::value_type;
     36 using string_type = path::string_type;
     37 
     38 inline std::error_code capture_errno() {
     39   _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
     40   return std::error_code(errno, std::generic_category());
     41 }
     42 
     43 void set_or_throw(std::error_code const& m_ec, std::error_code* ec,
     44                   const char* msg, path const& p = {}, path const& p2 = {})
     45 {
     46     if (ec) {
     47         *ec = m_ec;
     48     } else {
     49         string msg_s("std::experimental::filesystem::");
     50         msg_s += msg;
     51         __throw_filesystem_error(msg_s, p, p2, m_ec);
     52     }
     53 }
     54 
     55 void set_or_throw(std::error_code* ec, const char* msg,
     56                   path const& p = {}, path const& p2 = {})
     57 {
     58     return set_or_throw(capture_errno(), ec, msg, p, p2);
     59 }
     60 
     61 perms posix_get_perms(const struct ::stat & st) noexcept {
     62     return static_cast<perms>(st.st_mode) & perms::mask;
     63 }
     64 
     65 ::mode_t posix_convert_perms(perms prms) {
     66     return static_cast< ::mode_t>(prms & perms::mask);
     67 }
     68 
     69 file_status create_file_status(std::error_code& m_ec, path const& p,
     70                                struct ::stat& path_stat,
     71                                std::error_code* ec)
     72 {
     73     if (ec) *ec = m_ec;
     74     if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
     75         return file_status(file_type::not_found);
     76     }
     77     else if (m_ec) {
     78         set_or_throw(m_ec, ec, "posix_stat", p);
     79         return file_status(file_type::none);
     80     }
     81     // else
     82 
     83     file_status fs_tmp;
     84     auto const mode = path_stat.st_mode;
     85     if      (S_ISLNK(mode))  fs_tmp.type(file_type::symlink);
     86     else if (S_ISREG(mode))  fs_tmp.type(file_type::regular);
     87     else if (S_ISDIR(mode))  fs_tmp.type(file_type::directory);
     88     else if (S_ISBLK(mode))  fs_tmp.type(file_type::block);
     89     else if (S_ISCHR(mode))  fs_tmp.type(file_type::character);
     90     else if (S_ISFIFO(mode)) fs_tmp.type(file_type::fifo);
     91     else if (S_ISSOCK(mode)) fs_tmp.type(file_type::socket);
     92     else                     fs_tmp.type(file_type::unknown);
     93 
     94     fs_tmp.permissions(detail::posix_get_perms(path_stat));
     95     return fs_tmp;
     96 }
     97 
     98 file_status posix_stat(path const & p, struct ::stat& path_stat,
     99                        std::error_code* ec)
    100 {
    101     std::error_code m_ec;
    102     if (::stat(p.c_str(), &path_stat) == -1)
    103         m_ec = detail::capture_errno();
    104     return create_file_status(m_ec, p, path_stat, ec);
    105 }
    106 
    107 file_status posix_stat(path const & p, std::error_code* ec) {
    108     struct ::stat path_stat;
    109     return posix_stat(p, path_stat, ec);
    110 }
    111 
    112 file_status posix_lstat(path const & p, struct ::stat & path_stat,
    113                         std::error_code* ec)
    114 {
    115     std::error_code m_ec;
    116     if (::lstat(p.c_str(), &path_stat) == -1)
    117         m_ec = detail::capture_errno();
    118     return create_file_status(m_ec, p, path_stat, ec);
    119 }
    120 
    121 file_status posix_lstat(path const & p, std::error_code* ec) {
    122     struct ::stat path_stat;
    123     return posix_lstat(p, path_stat, ec);
    124 }
    125 
    126 bool stat_equivalent(struct ::stat& st1, struct ::stat& st2) {
    127     return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
    128 }
    129 
    130 //                           DETAIL::MISC
    131 
    132 
    133 bool copy_file_impl(const path& from, const path& to, perms from_perms,
    134                     std::error_code *ec)
    135 {
    136     std::ifstream in(from.c_str(), std::ios::binary);
    137     std::ofstream out(to.c_str(),  std::ios::binary);
    138 
    139     if (in.good() && out.good()) {
    140         using InIt = std::istreambuf_iterator<char>;
    141         using OutIt = std::ostreambuf_iterator<char>;
    142         InIt bin(in);
    143         InIt ein;
    144         OutIt bout(out);
    145         std::copy(bin, ein, bout);
    146     }
    147     if (out.fail() || in.fail()) {
    148         set_or_throw(make_error_code(errc::operation_not_permitted),
    149                      ec, "copy_file", from, to);
    150         return false;
    151     }
    152     __permissions(to, from_perms, ec);
    153     // TODO what if permissions fails?
    154     return true;
    155 }
    156 
    157 }} // end namespace detail
    158 
    159 using detail::set_or_throw;
    160 
    161 path __canonical(path const & orig_p, const path& base, std::error_code *ec)
    162 {
    163     path p = absolute(orig_p, base);
    164     char buff[PATH_MAX + 1];
    165     char *ret;
    166     if ((ret = ::realpath(p.c_str(), buff)) == nullptr) {
    167         set_or_throw(ec, "canonical", orig_p, base);
    168         return {};
    169     }
    170     if (ec) ec->clear();
    171     return {ret};
    172 }
    173 
    174 void __copy(const path& from, const path& to, copy_options options,
    175             std::error_code *ec)
    176 {
    177     const bool sym_status = bool(options &
    178         (copy_options::create_symlinks | copy_options::skip_symlinks));
    179 
    180     const bool sym_status2 = bool(options &
    181         copy_options::copy_symlinks);
    182 
    183     std::error_code m_ec;
    184     struct ::stat f_st = {};
    185     const file_status f = sym_status || sym_status2
    186                                      ? detail::posix_lstat(from, f_st, &m_ec)
    187                                      : detail::posix_stat(from,  f_st, &m_ec);
    188     if (m_ec)
    189         return set_or_throw(m_ec, ec, "copy", from, to);
    190 
    191     struct ::stat t_st = {};
    192     const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec)
    193                                      : detail::posix_stat(to, t_st, &m_ec);
    194 
    195     if (not status_known(t))
    196         return set_or_throw(m_ec, ec, "copy", from, to);
    197 
    198     if (!exists(f) || is_other(f) || is_other(t)
    199         || (is_directory(f) && is_regular_file(t))
    200         || detail::stat_equivalent(f_st, t_st))
    201     {
    202         return set_or_throw(make_error_code(errc::function_not_supported),
    203                             ec, "copy", from, to);
    204     }
    205 
    206     if (ec) ec->clear();
    207 
    208     if (is_symlink(f)) {
    209         if (bool(copy_options::skip_symlinks & options)) {
    210             // do nothing
    211         } else if (not exists(t)) {
    212             __copy_symlink(from, to, ec);
    213         } else {
    214             set_or_throw(make_error_code(errc::file_exists),
    215                          ec, "copy", from, to);
    216         }
    217         return;
    218     }
    219     else if (is_regular_file(f)) {
    220         if (bool(copy_options::directories_only & options)) {
    221             // do nothing
    222         }
    223         else if (bool(copy_options::create_symlinks & options)) {
    224             __create_symlink(from, to, ec);
    225         }
    226         else if (bool(copy_options::create_hard_links & options)) {
    227             __create_hard_link(from, to, ec);
    228         }
    229         else if (is_directory(t)) {
    230             __copy_file(from, to / from.filename(), options, ec);
    231         } else {
    232             __copy_file(from, to, options, ec);
    233         }
    234         return;
    235     }
    236     else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
    237         return set_or_throw(make_error_code(errc::is_a_directory), ec, "copy");
    238     }
    239     else if (is_directory(f) && (bool(copy_options::recursive & options) ||
    240              copy_options::none == options)) {
    241 
    242         if (!exists(t)) {
    243             // create directory to with attributes from 'from'.
    244             __create_directory(to, from, ec);
    245             if (ec && *ec) { return; }
    246         }
    247         directory_iterator it = ec ? directory_iterator(from, *ec)
    248                                    : directory_iterator(from);
    249         if (ec && *ec) { return; }
    250         std::error_code m_ec;
    251         for (; it != directory_iterator(); it.increment(m_ec)) {
    252             if (m_ec) return set_or_throw(m_ec, ec, "copy", from, to);
    253             __copy(it->path(), to / it->path().filename(),
    254                    options | copy_options::__in_recursive_copy, ec);
    255             if (ec && *ec) { return; }
    256         }
    257     }
    258 }
    259 
    260 
    261 bool __copy_file(const path& from, const path& to, copy_options options,
    262                  std::error_code *ec)
    263 {
    264     if (ec) ec->clear();
    265 
    266     std::error_code m_ec;
    267     auto from_st = detail::posix_stat(from, &m_ec);
    268     if (not is_regular_file(from_st)) {
    269         if (not m_ec)
    270             m_ec = make_error_code(errc::not_supported);
    271         set_or_throw(m_ec, ec, "copy_file", from, to);
    272         return false;
    273     }
    274 
    275     auto to_st = detail::posix_stat(to, &m_ec);
    276     if (!status_known(to_st)) {
    277         set_or_throw(m_ec, ec, "copy_file", from, to);
    278         return false;
    279     }
    280 
    281     const bool to_exists = exists(to_st);
    282     if (to_exists && !is_regular_file(to_st)) {
    283         set_or_throw(make_error_code(errc::not_supported), ec, "copy_file", from, to);
    284         return false;
    285     }
    286     if (to_exists && bool(copy_options::skip_existing & options)) {
    287         return false;
    288     }
    289     else if (to_exists && bool(copy_options::update_existing & options)) {
    290         auto from_time = __last_write_time(from, ec);
    291         if (ec && *ec) { return false; }
    292         auto to_time = __last_write_time(to, ec);
    293         if (ec && *ec) { return false; }
    294         if (from_time <= to_time) {
    295             return false;
    296         }
    297         return detail::copy_file_impl(from, to, from_st.permissions(), ec);
    298     }
    299     else if (!to_exists || bool(copy_options::overwrite_existing & options)) {
    300         return detail::copy_file_impl(from, to, from_st.permissions(), ec);
    301     }
    302     else {
    303         set_or_throw(make_error_code(errc::file_exists), ec, "copy", from, to);
    304         return false;
    305     }
    306 
    307     _LIBCPP_UNREACHABLE();
    308 }
    309 
    310 void __copy_symlink(const path& existing_symlink, const path& new_symlink,
    311                     std::error_code *ec)
    312 {
    313     const path real_path(__read_symlink(existing_symlink, ec));
    314     if (ec && *ec) { return; }
    315     // NOTE: proposal says you should detect if you should call
    316     // create_symlink or create_directory_symlink. I don't think this
    317     // is needed with POSIX
    318     __create_symlink(real_path, new_symlink, ec);
    319 }
    320 
    321 
    322 bool __create_directories(const path& p, std::error_code *ec)
    323 {
    324     std::error_code m_ec;
    325     auto const st = detail::posix_stat(p, &m_ec);
    326     if (!status_known(st)) {
    327         set_or_throw(m_ec, ec, "create_directories", p);
    328         return false;
    329     }
    330     else if (is_directory(st)) {
    331         if (ec) ec->clear();
    332         return false;
    333     }
    334     else if (exists(st)) {
    335         set_or_throw(make_error_code(errc::file_exists),
    336                      ec, "create_directories", p);
    337         return false;
    338     }
    339 
    340     const path parent = p.parent_path();
    341     if (!parent.empty()) {
    342         const file_status parent_st = status(parent, m_ec);
    343         if (not status_known(parent_st)) {
    344             set_or_throw(m_ec, ec, "create_directories", p);
    345             return false;
    346         }
    347         if (not exists(parent_st)) {
    348             __create_directories(parent, ec);
    349             if (ec && *ec) { return false; }
    350         }
    351     }
    352     return __create_directory(p, ec);
    353 }
    354 
    355 bool __create_directory(const path& p, std::error_code *ec)
    356 {
    357     if (ec) ec->clear();
    358     if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
    359         return true;
    360     if (errno != EEXIST || !is_directory(p))
    361         set_or_throw(ec, "create_directory", p);
    362     return false;
    363 }
    364 
    365 bool __create_directory(path const & p, path const & attributes,
    366                         std::error_code *ec)
    367 {
    368     struct ::stat attr_stat;
    369     std::error_code mec;
    370     auto st = detail::posix_stat(attributes, attr_stat, &mec);
    371     if (!status_known(st)) {
    372         set_or_throw(mec, ec, "create_directory", p, attributes);
    373         return false;
    374     }
    375     if (ec) ec->clear();
    376     if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
    377         return true;
    378     if (errno != EEXIST || !is_directory(p))
    379         set_or_throw(ec, "create_directory", p, attributes);
    380     return false;
    381 }
    382 
    383 void __create_directory_symlink(path const & from, path const & to,
    384                                 std::error_code *ec){
    385     if (::symlink(from.c_str(), to.c_str()) != 0)
    386         set_or_throw(ec, "create_directory_symlink", from, to);
    387     else if (ec)
    388         ec->clear();
    389 }
    390 
    391 void __create_hard_link(const path& from, const path& to, std::error_code *ec){
    392     if (::link(from.c_str(), to.c_str()) == -1)
    393         set_or_throw(ec, "create_hard_link", from, to);
    394     else if (ec)
    395         ec->clear();
    396 }
    397 
    398 void __create_symlink(path const & from, path const & to, std::error_code *ec) {
    399 
    400     if (::symlink(from.c_str(), to.c_str()) == -1)
    401         set_or_throw(ec, "create_symlink", from, to);
    402     else if (ec)
    403         ec->clear();
    404 }
    405 
    406 path __current_path(std::error_code *ec) {
    407     auto size = ::pathconf(".", _PC_PATH_MAX);
    408     _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
    409 
    410     auto buff = std::unique_ptr<char[]>(new char[size + 1]);
    411     char* ret;
    412     if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr) {
    413         set_or_throw(ec, "current_path");
    414         return {};
    415     }
    416     if (ec) ec->clear();
    417     return {buff.get()};
    418 }
    419 
    420 void __current_path(const path& p, std::error_code *ec) {
    421     if (::chdir(p.c_str()) == -1)
    422         set_or_throw(ec, "current_path", p);
    423     else if (ec)
    424         ec->clear();
    425 }
    426 
    427 bool __equivalent(const path& p1, const path& p2, std::error_code *ec)
    428 {
    429     std::error_code ec1, ec2;
    430     struct ::stat st1 = {};
    431     struct ::stat st2 = {};
    432     auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
    433     auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
    434 
    435     if ((!exists(s1) && !exists(s2)) || (is_other(s1) && is_other(s2))) {
    436         set_or_throw(make_error_code(errc::not_supported), ec,
    437                      "equivalent", p1, p2);
    438         return false;
    439     }
    440     if (ec) ec->clear();
    441     return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
    442 }
    443 
    444 
    445 std::uintmax_t __file_size(const path& p, std::error_code *ec)
    446 {
    447     std::error_code m_ec;
    448     struct ::stat st;
    449     file_status fst = detail::posix_stat(p, st, &m_ec);
    450     if (!exists(fst) || !is_regular_file(fst)) {
    451         if (!m_ec)
    452             m_ec = make_error_code(errc::not_supported);
    453         set_or_throw(m_ec, ec, "file_size", p);
    454         return static_cast<uintmax_t>(-1);
    455     }
    456     // is_regular_file(p) == true
    457     if (ec) ec->clear();
    458     return static_cast<std::uintmax_t>(st.st_size);
    459 }
    460 
    461 std::uintmax_t __hard_link_count(const path& p, std::error_code *ec)
    462 {
    463     std::error_code m_ec;
    464     struct ::stat st;
    465     detail::posix_stat(p, st, &m_ec);
    466     if (m_ec) {
    467         set_or_throw(m_ec, ec, "hard_link_count", p);
    468         return static_cast<std::uintmax_t>(-1);
    469     }
    470     if (ec) ec->clear();
    471     return static_cast<std::uintmax_t>(st.st_nlink);
    472 }
    473 
    474 
    475 bool __fs_is_empty(const path& p, std::error_code *ec)
    476 {
    477     if (ec) ec->clear();
    478     std::error_code m_ec;
    479     struct ::stat pst;
    480     auto st = detail::posix_stat(p, pst, &m_ec);
    481     if (m_ec) {
    482         set_or_throw(m_ec, ec, "is_empty", p);
    483         return false;
    484     }
    485     else if (!is_directory(st) && !is_regular_file(st)) {
    486         m_ec = make_error_code(errc::not_supported);
    487         set_or_throw(m_ec, ec, "is_empty");
    488         return false;
    489     }
    490     else if (is_directory(st)) {
    491         auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
    492         if (ec && *ec)
    493             return false;
    494         return it == directory_iterator{};
    495     }
    496     else if (is_regular_file(st))
    497         return static_cast<std::uintmax_t>(pst.st_size) == 0;
    498 
    499     _LIBCPP_UNREACHABLE();
    500 }
    501 
    502 
    503 namespace detail { namespace {
    504 
    505 using namespace std::chrono;
    506 
    507 template <class CType, class ChronoType>
    508 bool checked_set(CType* out, ChronoType time) {
    509     using Lim = numeric_limits<CType>;
    510     if (time > Lim::max() || time < Lim::min())
    511         return false;
    512     *out = static_cast<CType>(time);
    513     return true;
    514 }
    515 
    516 using TimeSpec = struct ::timespec;
    517 using StatT = struct ::stat;
    518 
    519 #if defined(__APPLE__)
    520 TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
    521 TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
    522 #else
    523 TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
    524 __attribute__((unused)) // Suppress warning
    525 TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
    526 #endif
    527 
    528 constexpr auto max_seconds = duration_cast<seconds>(
    529     file_time_type::duration::max()).count();
    530 
    531 constexpr auto max_nsec = duration_cast<nanoseconds>(
    532     file_time_type::duration::max() - seconds(max_seconds)).count();
    533 
    534 constexpr auto min_seconds = duration_cast<seconds>(
    535     file_time_type::duration::min()).count();
    536 
    537 constexpr auto min_nsec_timespec = duration_cast<nanoseconds>(
    538     (file_time_type::duration::min() - seconds(min_seconds)) + seconds(1)).count();
    539 
    540 // Static assert that these values properly round trip.
    541 static_assert((seconds(min_seconds) + duration_cast<microseconds>(nanoseconds(min_nsec_timespec)))
    542                   - duration_cast<microseconds>(seconds(1))
    543                   == file_time_type::duration::min(), "");
    544 
    545 constexpr auto max_time_t = numeric_limits<time_t>::max();
    546 constexpr auto min_time_t = numeric_limits<time_t>::min();
    547 
    548 #if !defined(__LP64__) && defined(__clang__)
    549 #pragma clang diagnostic push
    550 #pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
    551 #endif
    552 
    553 _LIBCPP_CONSTEXPR_AFTER_CXX11
    554 bool is_representable(TimeSpec const& tm) {
    555   if (tm.tv_sec >= 0) {
    556     return (tm.tv_sec < max_seconds) ||
    557         (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
    558   } else if (tm.tv_sec == (min_seconds - 1)) {
    559      return tm.tv_nsec >= min_nsec_timespec;
    560   } else {
    561     return (tm.tv_sec >= min_seconds);
    562   }
    563 }
    564 #ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
    565 #if defined(__LP64__)
    566 static_assert(is_representable({max_seconds, max_nsec}), "");
    567 static_assert(!is_representable({max_seconds + 1, 0}), "");
    568 static_assert(!is_representable({max_seconds, max_nsec + 1}), "");
    569 static_assert(!is_representable({max_time_t, 0}), "");
    570 static_assert(is_representable({min_seconds, 0}), "");
    571 static_assert(is_representable({min_seconds - 1, min_nsec_timespec}), "");
    572 static_assert(is_representable({min_seconds - 1, min_nsec_timespec + 1}), "");
    573 static_assert(!is_representable({min_seconds - 1, min_nsec_timespec - 1}), "");
    574 static_assert(!is_representable({min_time_t, 999999999}), "");
    575 #else
    576 static_assert(is_representable({max_time_t, 999999999}), "");
    577 static_assert(is_representable({max_time_t, 1000000000}), "");
    578 static_assert(is_representable({min_time_t, 0}), "");
    579 #endif
    580 #endif
    581 
    582 _LIBCPP_CONSTEXPR_AFTER_CXX11
    583 bool is_representable(file_time_type const& tm) {
    584   auto secs = duration_cast<seconds>(tm.time_since_epoch());
    585   auto nsecs = duration_cast<nanoseconds>(tm.time_since_epoch() - secs);
    586   if (nsecs.count() < 0) {
    587     secs = secs +  seconds(1);
    588     nsecs = nsecs + seconds(1);
    589   }
    590   using TLim = numeric_limits<time_t>;
    591   if (secs.count() >= 0)
    592     return secs.count() <= TLim::max();
    593   return secs.count() >= TLim::min();
    594 }
    595 #ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
    596 #if defined(__LP64__)
    597 static_assert(is_representable(file_time_type::max()), "");
    598 static_assert(is_representable(file_time_type::min()), "");
    599 #else
    600 static_assert(!is_representable(file_time_type::max()), "");
    601 static_assert(!is_representable(file_time_type::min()), "");
    602 static_assert(is_representable(file_time_type(seconds(max_time_t))), "");
    603 static_assert(is_representable(file_time_type(seconds(min_time_t))), "");
    604 #endif
    605 #endif
    606 
    607 _LIBCPP_CONSTEXPR_AFTER_CXX11
    608 file_time_type convert_timespec(TimeSpec const& tm) {
    609   auto adj_msec = duration_cast<microseconds>(nanoseconds(tm.tv_nsec));
    610   if (tm.tv_sec >= 0) {
    611     auto Dur = seconds(tm.tv_sec) + microseconds(adj_msec);
    612     return file_time_type(Dur);
    613   } else if (duration_cast<microseconds>(nanoseconds(tm.tv_nsec)).count() == 0) {
    614     return file_time_type(seconds(tm.tv_sec));
    615   } else { // tm.tv_sec < 0
    616     auto adj_subsec = duration_cast<microseconds>(seconds(1) - nanoseconds(tm.tv_nsec));
    617     auto Dur = seconds(tm.tv_sec + 1) - adj_subsec;
    618     return file_time_type(Dur);
    619   }
    620 }
    621 #ifndef _LIBCPP_HAS_NO_CXX14_CONSTEXPR
    622 #if defined(__LP64__)
    623 static_assert(convert_timespec({max_seconds, max_nsec}) == file_time_type::max(), "");
    624 static_assert(convert_timespec({max_seconds, max_nsec - 1}) < file_time_type::max(), "");
    625 static_assert(convert_timespec({max_seconds - 1, 999999999}) < file_time_type::max(), "");
    626 static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec}) == file_time_type::min(), "");
    627 static_assert(convert_timespec({min_seconds - 1, min_nsec_timespec + 1}) > file_time_type::min(), "");
    628 static_assert(convert_timespec({min_seconds , 0}) > file_time_type::min(), "");
    629 #else
    630 // FIXME add tests for 32 bit builds
    631 #endif
    632 #endif
    633 
    634 #if !defined(__LP64__) && defined(__clang__)
    635 #pragma clang diagnostic pop
    636 #endif
    637 
    638 template <class SubSecDurT, class SubSecT>
    639 bool set_times_checked(time_t* sec_out, SubSecT* subsec_out, file_time_type tp) {
    640     using namespace chrono;
    641     auto dur = tp.time_since_epoch();
    642     auto sec_dur = duration_cast<seconds>(dur);
    643     auto subsec_dur = duration_cast<SubSecDurT>(dur - sec_dur);
    644     // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
    645     if (subsec_dur.count() < 0) {
    646         if (sec_dur.count() > min_seconds) {
    647             sec_dur -= seconds(1);
    648             subsec_dur += seconds(1);
    649         } else {
    650             subsec_dur = SubSecDurT::zero();
    651         }
    652     }
    653     return checked_set(sec_out, sec_dur.count())
    654         && checked_set(subsec_out, subsec_dur.count());
    655 }
    656 
    657 }} // end namespace detail
    658 
    659 file_time_type __last_write_time(const path& p, std::error_code *ec)
    660 {
    661     using namespace ::std::chrono;
    662     std::error_code m_ec;
    663     struct ::stat st;
    664     detail::posix_stat(p, st, &m_ec);
    665     if (m_ec) {
    666         set_or_throw(m_ec, ec, "last_write_time", p);
    667         return file_time_type::min();
    668     }
    669     if (ec) ec->clear();
    670     auto ts = detail::extract_mtime(st);
    671     if (!detail::is_representable(ts)) {
    672         set_or_throw(error_code(EOVERFLOW, generic_category()), ec,
    673                      "last_write_time", p);
    674         return file_time_type::min();
    675     }
    676     return detail::convert_timespec(ts);
    677 }
    678 
    679 void __last_write_time(const path& p, file_time_type new_time,
    680                        std::error_code *ec)
    681 {
    682     using namespace std::chrono;
    683     std::error_code m_ec;
    684 
    685     // We can use the presence of UTIME_OMIT to detect platforms that do not
    686     // provide utimensat.
    687 #if !defined(UTIME_OMIT)
    688     // This implementation has a race condition between determining the
    689     // last access time and attempting to set it to the same value using
    690     // ::utimes
    691     struct ::stat st;
    692     file_status fst = detail::posix_stat(p, st, &m_ec);
    693     if (m_ec && !status_known(fst)) {
    694         set_or_throw(m_ec, ec, "last_write_time", p);
    695         return;
    696     }
    697     auto atime = detail::extract_atime(st);
    698     struct ::timeval tbuf[2];
    699     tbuf[0].tv_sec = atime.tv_sec;
    700     tbuf[0].tv_usec = duration_cast<microseconds>(nanoseconds(atime.tv_nsec)).count();
    701     const bool overflowed = !detail::set_times_checked<microseconds>(
    702         &tbuf[1].tv_sec, &tbuf[1].tv_usec, new_time);
    703 
    704     if (overflowed) {
    705         set_or_throw(make_error_code(errc::invalid_argument), ec,
    706                      "last_write_time", p);
    707         return;
    708     }
    709     if (::utimes(p.c_str(), tbuf) == -1) {
    710         m_ec = detail::capture_errno();
    711     }
    712 #else
    713     struct ::timespec tbuf[2];
    714     tbuf[0].tv_sec = 0;
    715     tbuf[0].tv_nsec = UTIME_OMIT;
    716 
    717     const bool overflowed = !detail::set_times_checked<nanoseconds>(
    718         &tbuf[1].tv_sec, &tbuf[1].tv_nsec, new_time);
    719     if (overflowed) {
    720         set_or_throw(make_error_code(errc::invalid_argument),
    721             ec, "last_write_time", p);
    722         return;
    723     }
    724     if (::utimensat(AT_FDCWD, p.c_str(), tbuf, 0) == -1) {
    725         m_ec = detail::capture_errno();
    726     }
    727 #endif
    728     if (m_ec)
    729         set_or_throw(m_ec, ec, "last_write_time", p);
    730     else if (ec)
    731         ec->clear();
    732 }
    733 
    734 
    735 void __permissions(const path& p, perms prms, std::error_code *ec)
    736 {
    737 
    738     const bool resolve_symlinks = !bool(perms::symlink_nofollow & prms);
    739     const bool add_perms = bool(perms::add_perms & prms);
    740     const bool remove_perms = bool(perms::remove_perms & prms);
    741     _LIBCPP_ASSERT(!(add_perms && remove_perms),
    742                    "Both add_perms and remove_perms are set");
    743 
    744     bool set_sym_perms = false;
    745     prms &= perms::mask;
    746     if (!resolve_symlinks || (add_perms || remove_perms)) {
    747         std::error_code m_ec;
    748         file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
    749                                           : detail::posix_lstat(p, &m_ec);
    750         set_sym_perms = is_symlink(st);
    751         if (m_ec) return set_or_throw(m_ec, ec, "permissions", p);
    752         _LIBCPP_ASSERT(st.permissions() != perms::unknown,
    753                        "Permissions unexpectedly unknown");
    754         if (add_perms)
    755             prms |= st.permissions();
    756         else if (remove_perms)
    757            prms = st.permissions() & ~prms;
    758     }
    759     const auto real_perms = detail::posix_convert_perms(prms);
    760 
    761 # if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
    762     const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
    763     if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
    764         return set_or_throw(ec, "permissions", p);
    765     }
    766 # else
    767     if (set_sym_perms)
    768         return set_or_throw(make_error_code(errc::operation_not_supported),
    769                             ec, "permissions", p);
    770     if (::chmod(p.c_str(), real_perms) == -1) {
    771         return set_or_throw(ec, "permissions", p);
    772     }
    773 # endif
    774     if (ec) ec->clear();
    775 }
    776 
    777 
    778 path __read_symlink(const path& p, std::error_code *ec) {
    779     char buff[PATH_MAX + 1];
    780     std::error_code m_ec;
    781     ::ssize_t ret;
    782     if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
    783         set_or_throw(ec, "read_symlink", p);
    784         return {};
    785     }
    786     _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
    787     _LIBCPP_ASSERT(ret > 0, "TODO");
    788     if (ec) ec->clear();
    789     buff[ret] = 0;
    790     return {buff};
    791 }
    792 
    793 
    794 bool __remove(const path& p, std::error_code *ec) {
    795     if (ec) ec->clear();
    796     if (::remove(p.c_str()) == -1) {
    797         set_or_throw(ec, "remove", p);
    798         return false;
    799     }
    800     return true;
    801 }
    802 
    803 namespace {
    804 
    805 std::uintmax_t remove_all_impl(path const & p, std::error_code& ec)
    806 {
    807     const auto npos = static_cast<std::uintmax_t>(-1);
    808     const file_status st = __symlink_status(p, &ec);
    809     if (ec) return npos;
    810      std::uintmax_t count = 1;
    811     if (is_directory(st)) {
    812         for (directory_iterator it(p, ec); !ec && it != directory_iterator();
    813              it.increment(ec)) {
    814             auto other_count = remove_all_impl(it->path(), ec);
    815             if (ec) return npos;
    816             count += other_count;
    817         }
    818         if (ec) return npos;
    819     }
    820     if (!__remove(p, &ec)) return npos;
    821     return count;
    822 }
    823 
    824 } // end namespace
    825 
    826 std::uintmax_t __remove_all(const path& p, std::error_code *ec) {
    827     std::error_code mec;
    828     auto count = remove_all_impl(p, mec);
    829     if (mec) {
    830         set_or_throw(mec, ec, "remove_all", p);
    831         return static_cast<std::uintmax_t>(-1);
    832     }
    833     if (ec) ec->clear();
    834     return count;
    835 }
    836 
    837 void __rename(const path& from, const path& to, std::error_code *ec) {
    838     if (::rename(from.c_str(), to.c_str()) == -1)
    839         set_or_throw(ec, "rename", from, to);
    840     else if (ec)
    841         ec->clear();
    842 }
    843 
    844 void __resize_file(const path& p, std::uintmax_t size, std::error_code *ec) {
    845     if (::truncate(p.c_str(), static_cast<long>(size)) == -1)
    846         set_or_throw(ec, "resize_file", p);
    847     else if (ec)
    848         ec->clear();
    849 }
    850 
    851 space_info __space(const path& p, std::error_code *ec) {
    852     space_info si;
    853     struct statvfs m_svfs = {};
    854     if (::statvfs(p.c_str(), &m_svfs) == -1)  {
    855         set_or_throw(ec, "space", p);
    856         si.capacity = si.free = si.available =
    857             static_cast<std::uintmax_t>(-1);
    858         return si;
    859     }
    860     if (ec) ec->clear();
    861     // Multiply with overflow checking.
    862     auto do_mult = [&](std::uintmax_t& out, std::uintmax_t other) {
    863       out = other * m_svfs.f_frsize;
    864       if (other == 0 || out / other != m_svfs.f_frsize)
    865           out = static_cast<std::uintmax_t>(-1);
    866     };
    867     do_mult(si.capacity, m_svfs.f_blocks);
    868     do_mult(si.free, m_svfs.f_bfree);
    869     do_mult(si.available, m_svfs.f_bavail);
    870     return si;
    871 }
    872 
    873 file_status __status(const path& p, std::error_code *ec) {
    874     return detail::posix_stat(p, ec);
    875 }
    876 
    877 file_status __symlink_status(const path& p, std::error_code *ec) {
    878     return detail::posix_lstat(p, ec);
    879 }
    880 
    881 path __system_complete(const path& p, std::error_code *ec) {
    882     if (ec) ec->clear();
    883     return absolute(p, current_path());
    884 }
    885 
    886 path __temp_directory_path(std::error_code* ec) {
    887   const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
    888   const char* ret = nullptr;
    889 
    890   for (auto& ep : env_paths)
    891     if ((ret = std::getenv(ep)))
    892       break;
    893   if (ret == nullptr)
    894     ret = "/tmp";
    895 
    896   path p(ret);
    897   std::error_code m_ec;
    898   if (!exists(p, m_ec) || !is_directory(p, m_ec)) {
    899     if (!m_ec || m_ec == make_error_code(errc::no_such_file_or_directory))
    900       m_ec = make_error_code(errc::not_a_directory);
    901     set_or_throw(m_ec, ec, "temp_directory_path");
    902     return {};
    903   }
    904 
    905   if (ec)
    906     ec->clear();
    907   return p;
    908 }
    909 
    910 // An absolute path is composed according to the table in [fs.op.absolute].
    911 path absolute(const path& p, const path& base) {
    912     auto root_name = p.root_name();
    913     auto root_dir = p.root_directory();
    914 
    915     if (!root_name.empty() && !root_dir.empty())
    916       return p;
    917 
    918     auto abs_base = base.is_absolute() ? base : absolute(base);
    919 
    920     /* !has_root_name && !has_root_dir */
    921     if (root_name.empty() && root_dir.empty())
    922     {
    923       return abs_base / p;
    924     }
    925     else if (!root_name.empty()) /* has_root_name && !has_root_dir */
    926     {
    927       return  root_name / abs_base.root_directory()
    928               /
    929               abs_base.relative_path() / p.relative_path();
    930     }
    931     else /* !has_root_name && has_root_dir */
    932     {
    933       if (abs_base.has_root_name())
    934         return abs_base.root_name() / p;
    935       // else p is absolute,  return outside of block
    936     }
    937     return p;
    938 }
    939 
    940 _LIBCPP_END_NAMESPACE_EXPERIMENTAL_FILESYSTEM
    941