ops.cc revision 1.1.1.2
1// Filesystem operations -*- C++ -*-
2
3// Copyright (C) 2014-2015 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25#ifndef _GLIBCXX_USE_CXX11_ABI
26# define _GLIBCXX_USE_CXX11_ABI 1
27#endif
28
29#include <experimental/filesystem>
30#include <functional>
31#include <ostream>
32#include <stack>
33#include <ext/stdio_filebuf.h>
34#include <stdlib.h>
35#include <stdio.h>
36#include <errno.h>
37#include <limits.h>  // PATH_MAX
38#ifdef _GLIBCXX_HAVE_UNISTD_H
39# include <unistd.h>
40# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
41#  include <sys/types.h>
42#  include <sys/stat.h>
43# endif
44#endif
45#ifdef _GLIBCXX_HAVE_FCNTL_H
46# include <fcntl.h>
47#endif
48#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
49# include <sys/statvfs.h>
50#endif
51#ifdef _GLIBCXX_USE_SENDFILE
52# include <sys/sendfile.h>
53#endif
54#if _GLIBCXX_HAVE_UTIME_H
55# include <utime.h>
56#endif
57
58#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
59# undef utime
60# define utime _wutime
61# undef chmod
62# define chmod _wchmod
63#endif
64
65namespace fs = std::experimental::filesystem;
66
67fs::path
68fs::absolute(const path& p, const path& base)
69{
70  const bool has_root_dir = p.has_root_directory();
71  const bool has_root_name = p.has_root_name();
72  path abs;
73  if (has_root_dir && has_root_name)
74    abs = p;
75  else
76    {
77      abs = base.is_absolute() ? base : absolute(base);
78      if (has_root_dir)
79	abs = abs.root_name() / p;
80      else if (has_root_name)
81	abs = p.root_name() / abs.root_directory() / abs.relative_path()
82	  / p.relative_path();
83      else
84	abs = abs / p;
85    }
86  return abs;
87}
88
89namespace
90{
91#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
92  inline bool is_dot(wchar_t c) { return c == L'.'; }
93#else
94  inline bool is_dot(char c) { return c == '.'; }
95#endif
96
97  inline bool is_dot(const fs::path& path)
98  {
99    const auto& filename = path.native();
100    return filename.size() == 1 && is_dot(filename[0]);
101  }
102
103  inline bool is_dotdot(const fs::path& path)
104  {
105    const auto& filename = path.native();
106    return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
107  }
108
109  struct free_as_in_malloc
110  {
111    void operator()(void* p) const { ::free(p); }
112  };
113
114  using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
115}
116
117fs::path
118fs::canonical(const path& p, const path& base, error_code& ec)
119{
120  const path pa = absolute(p, base);
121  path result;
122
123#ifdef _GLIBCXX_USE_REALPATH
124  char_ptr buf{ nullptr };
125# if _XOPEN_VERSION < 700
126  // Not safe to call realpath(path, NULL)
127  buf.reset( (char*)::malloc(PATH_MAX) );
128# endif
129  if (char* rp = ::realpath(pa.c_str(), buf.get()))
130    {
131      if (buf == nullptr)
132	buf.reset(rp);
133      result.assign(rp);
134      ec.clear();
135      return result;
136    }
137  if (errno != ENAMETOOLONG)
138    {
139      ec.assign(errno, std::generic_category());
140      return result;
141    }
142#endif
143
144  if (!exists(pa, ec))
145    {
146      if (!ec)
147	ec = make_error_code(std::errc::no_such_file_or_directory);
148      return result;
149    }
150  // else: we know there are (currently) no unresolvable symlink loops
151
152  result = pa.root_path();
153
154  deque<path> cmpts;
155  for (auto& f : pa.relative_path())
156    cmpts.push_back(f);
157
158  int max_allowed_symlinks = 40;
159
160  while (!cmpts.empty() && !ec)
161    {
162      path f = std::move(cmpts.front());
163      cmpts.pop_front();
164
165      if (is_dot(f))
166	{
167	  if (!is_directory(result, ec) && !ec)
168	    ec.assign(ENOTDIR, std::generic_category());
169	}
170      else if (is_dotdot(f))
171	{
172	  auto parent = result.parent_path();
173	  if (parent.empty())
174	    result = pa.root_path();
175	  else
176	    result.swap(parent);
177	}
178      else
179	{
180	  result /= f;
181
182	  if (is_symlink(result, ec))
183	    {
184	      path link = read_symlink(result, ec);
185	      if (!ec)
186		{
187		  if (--max_allowed_symlinks == 0)
188		    ec.assign(ELOOP, std::generic_category());
189		  else
190		    {
191		      if (link.is_absolute())
192			{
193			  result = link.root_path();
194			  link = link.relative_path();
195			}
196		      else
197			result.remove_filename();
198
199		      cmpts.insert(cmpts.begin(), link.begin(), link.end());
200		    }
201		}
202	    }
203	}
204    }
205
206  if (ec || !exists(result, ec))
207    result.clear();
208
209  return result;
210}
211
212fs::path
213fs::canonical(const path& p, error_code& ec)
214{
215  path cur = current_path(ec);
216  if (ec.value())
217    return {};
218  return canonical(p, cur, ec);
219}
220
221fs::path
222fs::canonical(const path& p, const path& base)
223{
224  error_code ec;
225  path can = canonical(p, base, ec);
226  if (ec)
227    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot canonicalize", p, base,
228					     ec));
229  return can;
230}
231
232void
233fs::copy(const path& from, const path& to, copy_options options)
234{
235  error_code ec;
236  copy(from, to, options, ec);
237  if (ec.value())
238    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
239}
240
241namespace
242{
243  template<typename Bitmask>
244    inline bool is_set(Bitmask obj, Bitmask bits)
245    {
246      return (obj & bits) != Bitmask::none;
247    }
248}
249
250#ifdef _GLIBCXX_HAVE_SYS_STAT_H
251namespace
252{
253  typedef struct ::stat stat_type;
254
255  inline fs::file_type
256  make_file_type(const stat_type& st) noexcept
257  {
258    using fs::file_type;
259#ifdef _GLIBCXX_HAVE_S_ISREG
260    if (S_ISREG(st.st_mode))
261      return file_type::regular;
262    else if (S_ISDIR(st.st_mode))
263      return file_type::directory;
264    else if (S_ISCHR(st.st_mode))
265      return file_type::character;
266    else if (S_ISBLK(st.st_mode))
267      return file_type::block;
268    else if (S_ISFIFO(st.st_mode))
269      return file_type::fifo;
270    else if (S_ISLNK(st.st_mode))
271      return file_type::symlink;
272    else if (S_ISSOCK(st.st_mode))
273      return file_type::socket;
274#endif
275    return file_type::unknown;
276
277  }
278
279  inline fs::file_status
280  make_file_status(const stat_type& st) noexcept
281  {
282    return fs::file_status{
283	make_file_type(st),
284	static_cast<fs::perms>(st.st_mode) & fs::perms::mask
285    };
286  }
287
288  inline bool
289  is_not_found_errno(int err) noexcept
290  {
291    return err == ENOENT || err == ENOTDIR;
292  }
293
294  inline fs::file_time_type
295  file_time(const stat_type& st, std::error_code& ec) noexcept
296  {
297    using namespace std::chrono;
298#ifdef _GLIBCXX_USE_ST_MTIM
299    time_t s = st.st_mtim.tv_sec;
300    nanoseconds ns{st.st_mtim.tv_nsec};
301#else
302    time_t s = st.st_mtime;
303    nanoseconds ns{};
304#endif
305
306    if (s >= (nanoseconds::max().count() / 1e9))
307      {
308	ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
309	return fs::file_time_type::min();
310      }
311    ec.clear();
312    return fs::file_time_type{seconds{s} + ns};
313  }
314
315  bool
316  do_copy_file(const fs::path& from, const fs::path& to,
317	       fs::copy_options option,
318	       stat_type* from_st, stat_type* to_st,
319	       std::error_code& ec) noexcept
320  {
321    stat_type st1, st2;
322    fs::file_status t, f;
323
324    if (to_st == nullptr)
325      {
326	if (::stat(to.c_str(), &st1))
327	  {
328	    int err = errno;
329	    if (!is_not_found_errno(err))
330	      {
331		ec.assign(err, std::generic_category());
332		return false;
333	      }
334	  }
335	else
336	  to_st = &st1;
337      }
338    else if (to_st == from_st)
339      to_st = nullptr;
340
341    if (to_st == nullptr)
342      t = fs::file_status{fs::file_type::not_found};
343    else
344      t = make_file_status(*to_st);
345
346    if (from_st == nullptr)
347      {
348	if (::stat(from.c_str(), &st2))
349	  {
350	    ec.assign(errno, std::generic_category());
351	    return false;
352	  }
353	else
354	  from_st = &st2;
355      }
356    f = make_file_status(*from_st);
357    // _GLIBCXX_RESOLVE_LIB_DEFECTS
358    // 2712. copy_file() has a number of unspecified error conditions
359    if (!is_regular_file(f))
360      {
361	ec = std::make_error_code(std::errc::not_supported);
362	return false;
363      }
364
365    using opts = fs::copy_options;
366
367    if (exists(t))
368      {
369	if (!is_regular_file(t))
370	  {
371	    ec = std::make_error_code(std::errc::not_supported);
372	    return false;
373	  }
374
375	if (to_st->st_dev == from_st->st_dev
376	    && to_st->st_ino == from_st->st_ino)
377	  {
378	    ec = std::make_error_code(std::errc::file_exists);
379	    return false;
380	  }
381
382	if (is_set(option, opts::skip_existing))
383	  {
384	    ec.clear();
385	    return false;
386	  }
387	else if (is_set(option, opts::update_existing))
388	  {
389	    const auto from_mtime = file_time(*from_st, ec);
390	    if (ec)
391	      return false;
392	    if ((from_mtime <= file_time(*to_st, ec)) || ec)
393	      return false;
394	  }
395	else if (!is_set(option, opts::overwrite_existing))
396	  {
397	    ec = std::make_error_code(std::errc::file_exists);
398	    return false;
399	  }
400	else if (!is_regular_file(t))
401	  {
402	    ec = std::make_error_code(std::errc::not_supported);
403	    return false;
404	  }
405      }
406
407    struct CloseFD {
408      ~CloseFD() { if (fd != -1) ::close(fd); }
409      bool close() { return ::close(std::exchange(fd, -1)) == 0; }
410      int fd;
411    };
412
413    CloseFD in = { ::open(from.c_str(), O_RDONLY) };
414    if (in.fd == -1)
415      {
416	ec.assign(errno, std::generic_category());
417	return false;
418      }
419    int oflag = O_WRONLY|O_CREAT;
420    if (is_set(option, opts::overwrite_existing|opts::update_existing))
421      oflag |= O_TRUNC;
422    else
423      oflag |= O_EXCL;
424    CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) };
425    if (out.fd == -1)
426      {
427	if (errno == EEXIST && is_set(option, opts::skip_existing))
428	  ec.clear();
429	else
430	  ec.assign(errno, std::generic_category());
431	return false;
432      }
433
434#ifdef _GLIBCXX_USE_FCHMOD
435    if (::fchmod(out.fd, from_st->st_mode))
436#elif defined _GLIBCXX_USE_FCHMODAT
437    if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
438#else
439    if (::chmod(to.c_str(), from_st->st_mode))
440#endif
441      {
442	ec.assign(errno, std::generic_category());
443	return false;
444      }
445
446#ifdef _GLIBCXX_USE_SENDFILE
447    off_t offset = 0;
448    const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
449    if (n < 0 && (errno == ENOSYS || errno == EINVAL))
450      {
451#endif
452	__gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
453	__gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
454	if (sbin.is_open())
455	  in.fd = -1;
456	if (sbout.is_open())
457	  out.fd = -1;
458	if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
459	  {
460	    ec = std::make_error_code(std::errc::io_error);
461	    return false;
462	  }
463	if (!sbout.close() || !sbin.close())
464	  {
465	    ec.assign(errno, std::generic_category());
466	    return false;
467	  }
468
469	ec.clear();
470	return true;
471
472#ifdef _GLIBCXX_USE_SENDFILE
473      }
474    if (n != from_st->st_size)
475      {
476	ec.assign(errno, std::generic_category());
477	return false;
478      }
479    if (!out.close() || !in.close())
480      {
481	ec.assign(errno, std::generic_category());
482	return false;
483      }
484
485    ec.clear();
486    return true;
487#endif
488  }
489}
490#endif
491
492void
493fs::copy(const path& from, const path& to, copy_options options,
494	 error_code& ec) noexcept
495{
496  const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
497  const bool create_symlinks = is_set(options, copy_options::create_symlinks);
498  const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
499  const bool use_lstat = create_symlinks || skip_symlinks;
500
501  file_status f, t;
502  stat_type from_st, to_st;
503  // _GLIBCXX_RESOLVE_LIB_DEFECTS
504  // 2681. filesystem::copy() cannot copy symlinks
505  if (use_lstat || copy_symlinks
506      ? ::lstat(from.c_str(), &from_st)
507      : ::stat(from.c_str(), &from_st))
508    {
509      ec.assign(errno, std::generic_category());
510      return;
511    }
512  if (use_lstat
513      ? ::lstat(to.c_str(), &to_st)
514      : ::stat(to.c_str(), &to_st))
515    {
516      if (!is_not_found_errno(errno))
517	{
518	  ec.assign(errno, std::generic_category());
519	  return;
520	}
521      t = file_status{file_type::not_found};
522    }
523  else
524    t = make_file_status(to_st);
525  f = make_file_status(from_st);
526
527  if (exists(t) && !is_other(t) && !is_other(f)
528      && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
529    {
530      ec = std::make_error_code(std::errc::file_exists);
531      return;
532    }
533  if (is_other(f) || is_other(t))
534    {
535      ec = std::make_error_code(std::errc::not_supported);
536      return;
537    }
538  if (is_directory(f) && is_regular_file(t))
539    {
540      ec = std::make_error_code(std::errc::is_a_directory);
541      return;
542    }
543
544  if (is_symlink(f))
545    {
546      if (skip_symlinks)
547	ec.clear();
548      else if (!exists(t) && copy_symlinks)
549	copy_symlink(from, to, ec);
550      else
551	// Not clear what should be done here.
552	// "Otherwise report an error as specified in Error reporting (7)."
553	ec = std::make_error_code(std::errc::invalid_argument);
554    }
555  else if (is_regular_file(f))
556    {
557      if (is_set(options, copy_options::directories_only))
558	ec.clear();
559      else if (create_symlinks)
560	create_symlink(from, to, ec);
561      else if (is_set(options, copy_options::create_hard_links))
562	create_hard_link(from, to, ec);
563      else if (is_directory(t))
564	do_copy_file(from, to / from.filename(), options, &from_st, 0, ec);
565      else
566	{
567	  auto ptr = exists(t) ? &to_st : &from_st;
568	  do_copy_file(from, to, options, &from_st, ptr,  ec);
569	}
570    }
571  // _GLIBCXX_RESOLVE_LIB_DEFECTS
572  // 2682. filesystem::copy() won't create a symlink to a directory
573  else if (is_directory(f) && create_symlinks)
574    ec = std::make_error_code(errc::is_a_directory);
575  else if (is_directory(f) && (is_set(options, copy_options::recursive)
576			       || options == copy_options::none))
577    {
578      if (!exists(t))
579	if (!create_directory(to, from, ec))
580	  return;
581      // set an unused bit in options to disable further recursion
582      if (!is_set(options, copy_options::recursive))
583	options |= static_cast<copy_options>(4096);
584      for (const directory_entry& x : directory_iterator(from))
585	copy(x.path(), to/x.path().filename(), options, ec);
586    }
587  // _GLIBCXX_RESOLVE_LIB_DEFECTS
588  // 2683. filesystem::copy() says "no effects"
589  else
590    ec.clear();
591}
592
593bool
594fs::copy_file(const path& from, const path& to, copy_options option)
595{
596  error_code ec;
597  bool result = copy_file(from, to, option, ec);
598  if (ec.value())
599    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
600	  ec));
601  return result;
602}
603
604bool
605fs::copy_file(const path& from, const path& to, copy_options option,
606	      error_code& ec) noexcept
607{
608#ifdef _GLIBCXX_HAVE_SYS_STAT_H
609  return do_copy_file(from, to, option, nullptr, nullptr, ec);
610#else
611  ec = std::make_error_code(std::errc::not_supported);
612  return false;
613#endif
614}
615
616
617void
618fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
619{
620  error_code ec;
621  copy_symlink(existing_symlink, new_symlink, ec);
622  if (ec.value())
623    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
624	  existing_symlink, new_symlink, ec));
625}
626
627void
628fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
629		 error_code& ec) noexcept
630{
631  auto p = read_symlink(existing_symlink, ec);
632  if (ec.value())
633    return;
634#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
635  if (is_directory(p))
636    {
637      create_directory_symlink(p, new_symlink, ec);
638      return;
639    }
640#endif
641  create_symlink(p, new_symlink, ec);
642}
643
644
645bool
646fs::create_directories(const path& p)
647{
648  error_code ec;
649  bool result = create_directories(p, ec);
650  if (ec.value())
651    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
652	  ec));
653  return result;
654}
655
656bool
657fs::create_directories(const path& p, error_code& ec) noexcept
658{
659  if (p.empty())
660    {
661      ec = std::make_error_code(errc::invalid_argument);
662      return false;
663    }
664  std::stack<path> missing;
665  path pp = p;
666
667  while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
668    {
669      ec.clear();
670      const auto& filename = pp.filename();
671      if (!is_dot(filename) && !is_dotdot(filename))
672	missing.push(pp);
673      pp.remove_filename();
674    }
675
676  if (ec || missing.empty())
677    return false;
678
679  do
680    {
681      const path& top = missing.top();
682      create_directory(top, ec);
683      if (ec && is_directory(top))
684	ec.clear();
685      missing.pop();
686    }
687  while (!missing.empty() && !ec);
688
689  return missing.empty();
690}
691
692namespace
693{
694  bool
695  create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
696  {
697    bool created = false;
698#ifdef _GLIBCXX_HAVE_SYS_STAT_H
699    ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
700    if (::mkdir(p.c_str(), mode))
701      {
702	const int err = errno;
703	if (err != EEXIST || !is_directory(p))
704	  ec.assign(err, std::generic_category());
705	else
706	  ec.clear();
707      }
708    else
709      {
710	ec.clear();
711	created = true;
712      }
713#else
714    ec = std::make_error_code(std::errc::not_supported);
715#endif
716    return created;
717  }
718} // namespace
719
720bool
721fs::create_directory(const path& p)
722{
723  error_code ec;
724  bool result = create_directory(p, ec);
725  if (ec.value())
726    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
727	  ec));
728  return result;
729}
730
731bool
732fs::create_directory(const path& p, error_code& ec) noexcept
733{
734  return create_dir(p, perms::all, ec);
735}
736
737
738bool
739fs::create_directory(const path& p, const path& attributes)
740{
741  error_code ec;
742  bool result = create_directory(p, attributes, ec);
743  if (ec.value())
744    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
745	  ec));
746  return result;
747}
748
749bool
750fs::create_directory(const path& p, const path& attributes,
751		     error_code& ec) noexcept
752{
753#ifdef _GLIBCXX_HAVE_SYS_STAT_H
754  stat_type st;
755  if (::stat(attributes.c_str(), &st))
756    {
757      ec.assign(errno, std::generic_category());
758      return false;
759    }
760  return create_dir(p, static_cast<perms>(st.st_mode), ec);
761#else
762  ec = std::make_error_code(std::errc::not_supported);
763  return false;
764#endif
765}
766
767
768void
769fs::create_directory_symlink(const path& to, const path& new_symlink)
770{
771  error_code ec;
772  create_directory_symlink(to, new_symlink, ec);
773  if (ec.value())
774    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
775	  to, new_symlink, ec));
776}
777
778void
779fs::create_directory_symlink(const path& to, const path& new_symlink,
780			     error_code& ec) noexcept
781{
782#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
783  ec = std::make_error_code(std::errc::not_supported);
784#else
785  create_symlink(to, new_symlink, ec);
786#endif
787}
788
789
790void
791fs::create_hard_link(const path& to, const path& new_hard_link)
792{
793  error_code ec;
794  create_hard_link(to, new_hard_link, ec);
795  if (ec.value())
796    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
797	  to, new_hard_link, ec));
798}
799
800void
801fs::create_hard_link(const path& to, const path& new_hard_link,
802		     error_code& ec) noexcept
803{
804#ifdef _GLIBCXX_HAVE_UNISTD_H
805  if (::link(to.c_str(), new_hard_link.c_str()))
806    ec.assign(errno, std::generic_category());
807  else
808    ec.clear();
809#else
810  ec = std::make_error_code(std::errc::not_supported);
811#endif
812}
813
814void
815fs::create_symlink(const path& to, const path& new_symlink)
816{
817  error_code ec;
818  create_symlink(to, new_symlink, ec);
819  if (ec.value())
820    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
821	  to, new_symlink, ec));
822}
823
824void
825fs::create_symlink(const path& to, const path& new_symlink,
826		   error_code& ec) noexcept
827{
828#ifdef _GLIBCXX_HAVE_UNISTD_H
829  if (::symlink(to.c_str(), new_symlink.c_str()))
830    ec.assign(errno, std::generic_category());
831  else
832    ec.clear();
833#else
834  ec = std::make_error_code(std::errc::not_supported);
835#endif
836}
837
838
839fs::path
840fs::current_path()
841{
842  error_code ec;
843  path p = current_path(ec);
844  if (ec.value())
845    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
846  return p;
847}
848
849fs::path
850fs::current_path(error_code& ec)
851{
852  path p;
853#ifdef _GLIBCXX_HAVE_UNISTD_H
854#ifdef __GLIBC__
855  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
856    {
857      p.assign(cwd.get());
858      ec.clear();
859    }
860  else
861    ec.assign(errno, std::generic_category());
862#else
863  long path_max = pathconf(".", _PC_PATH_MAX);
864  size_t size;
865  if (path_max == -1)
866      size = 1024;
867  else if (path_max > 10240)
868      size = 10240;
869  else
870      size = path_max;
871  for (char_ptr buf; p.empty(); size *= 2)
872    {
873      buf.reset((char*)malloc(size));
874      if (buf)
875	{
876	  if (getcwd(buf.get(), size))
877	    {
878	      p.assign(buf.get());
879	      ec.clear();
880	    }
881	  else if (errno != ERANGE)
882	    {
883	      ec.assign(errno, std::generic_category());
884	      return {};
885	    }
886	}
887      else
888	{
889	  ec = std::make_error_code(std::errc::not_enough_memory);
890	  return {};
891	}
892    }
893#endif  // __GLIBC__
894#else   // _GLIBCXX_HAVE_UNISTD_H
895  ec = std::make_error_code(std::errc::not_supported);
896#endif
897  return p;
898}
899
900void
901fs::current_path(const path& p)
902{
903  error_code ec;
904  current_path(p, ec);
905  if (ec.value())
906    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
907}
908
909void
910fs::current_path(const path& p, error_code& ec) noexcept
911{
912#ifdef _GLIBCXX_HAVE_UNISTD_H
913  if (::chdir(p.c_str()))
914    ec.assign(errno, std::generic_category());
915  else
916    ec.clear();
917#else
918  ec = std::make_error_code(std::errc::not_supported);
919#endif
920}
921
922bool
923fs::equivalent(const path& p1, const path& p2)
924{
925  error_code ec;
926  auto result = equivalent(p1, p2, ec);
927  if (ec)
928    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
929	  p1, p2, ec));
930  return result;
931}
932
933bool
934fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
935{
936#ifdef _GLIBCXX_HAVE_SYS_STAT_H
937  int err = 0;
938  file_status s1, s2;
939  stat_type st1, st2;
940  if (::stat(p1.c_str(), &st1) == 0)
941    s1 = make_file_status(st1);
942  else if (is_not_found_errno(errno))
943    s1.type(file_type::not_found);
944  else
945    err = errno;
946
947  if (::stat(p2.c_str(), &st2) == 0)
948    s2 = make_file_status(st2);
949  else if (is_not_found_errno(errno))
950    s2.type(file_type::not_found);
951  else
952    err = errno;
953
954  if (exists(s1) && exists(s2))
955    {
956      if (is_other(s1) && is_other(s2))
957	{
958	  ec = std::make_error_code(std::errc::not_supported);
959	  return false;
960	}
961      ec.clear();
962      if (is_other(s1) || is_other(s2))
963	return false;
964      return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
965    }
966  else if (!exists(s1) && !exists(s2))
967    ec = std::make_error_code(std::errc::no_such_file_or_directory);
968  else if (err)
969    ec.assign(err, std::generic_category());
970  else
971    ec.clear();
972  return false;
973#else
974  ec = std::make_error_code(std::errc::not_supported);
975#endif
976  return false;
977}
978
979std::uintmax_t
980fs::file_size(const path& p)
981{
982  error_code ec;
983  auto sz = file_size(p, ec);
984  if (ec.value())
985    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
986  return sz;
987}
988
989namespace
990{
991  template<typename Accessor, typename T>
992    inline T
993    do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
994    {
995#ifdef _GLIBCXX_HAVE_SYS_STAT_H
996      stat_type st;
997      if (::stat(p.c_str(), &st))
998	{
999	  ec.assign(errno, std::generic_category());
1000	  return deflt;
1001	}
1002      ec.clear();
1003      return f(st);
1004#else
1005      ec = std::make_error_code(std::errc::not_supported);
1006      return deflt;
1007#endif
1008    }
1009}
1010
1011std::uintmax_t
1012fs::file_size(const path& p, error_code& ec) noexcept
1013{
1014  struct S
1015  {
1016    S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
1017    S() : type(file_type::not_found) { }
1018    file_type type;
1019    size_t size;
1020  };
1021  auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
1022  if (s.type == file_type::regular)
1023    return s.size;
1024  if (!ec)
1025    {
1026      if (s.type == file_type::directory)
1027	ec = std::make_error_code(std::errc::is_a_directory);
1028      else
1029	ec = std::make_error_code(std::errc::not_supported);
1030    }
1031  return -1;
1032}
1033
1034std::uintmax_t
1035fs::hard_link_count(const path& p)
1036{
1037  error_code ec;
1038  auto count = hard_link_count(p, ec);
1039  if (ec.value())
1040    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
1041  return count;
1042}
1043
1044std::uintmax_t
1045fs::hard_link_count(const path& p, error_code& ec) noexcept
1046{
1047  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
1048		 static_cast<uintmax_t>(-1));
1049}
1050
1051bool
1052fs::is_empty(const path& p)
1053{
1054  error_code ec;
1055  bool e = is_empty(p, ec);
1056  if (ec)
1057    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1058					     p, ec));
1059  return e;
1060}
1061
1062bool
1063fs::is_empty(const path& p, error_code& ec) noexcept
1064{
1065  auto s = status(p, ec);
1066  if (ec)
1067    return false;
1068  bool empty = fs::is_directory(s)
1069    ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1070    : fs::file_size(p, ec) == 0;
1071  return ec ? false : empty;
1072}
1073
1074fs::file_time_type
1075fs::last_write_time(const path& p)
1076{
1077  error_code ec;
1078  auto t = last_write_time(p, ec);
1079  if (ec.value())
1080    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1081  return t;
1082}
1083
1084fs::file_time_type
1085fs::last_write_time(const path& p, error_code& ec) noexcept
1086{
1087  return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
1088		 file_time_type::min());
1089}
1090
1091void
1092fs::last_write_time(const path& p, file_time_type new_time)
1093{
1094  error_code ec;
1095  last_write_time(p, new_time, ec);
1096  if (ec.value())
1097    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1098}
1099
1100void
1101fs::last_write_time(const path& p __attribute__((__unused__)),
1102		    file_time_type new_time, error_code& ec) noexcept
1103{
1104  auto d = new_time.time_since_epoch();
1105  auto s = chrono::duration_cast<chrono::seconds>(d);
1106#if _GLIBCXX_USE_UTIMENSAT
1107  auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1108  if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1109    {
1110      --s;
1111      ns += chrono::seconds(1);
1112    }
1113  struct ::timespec ts[2];
1114  ts[0].tv_sec = 0;
1115  ts[0].tv_nsec = UTIME_OMIT;
1116  ts[1].tv_sec = static_cast<std::time_t>(s.count());
1117  ts[1].tv_nsec = static_cast<long>(ns.count());
1118  if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1119    ec.assign(errno, std::generic_category());
1120  else
1121    ec.clear();
1122#elif _GLIBCXX_HAVE_UTIME_H
1123  ::utimbuf times;
1124  times.modtime = s.count();
1125  times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1126			 times.modtime);
1127  if (::utime(p.c_str(), &times))
1128    ec.assign(errno, std::generic_category());
1129  else
1130    ec.clear();
1131#else
1132  ec = std::make_error_code(std::errc::not_supported);
1133#endif
1134}
1135
1136void
1137fs::permissions(const path& p, perms prms)
1138{
1139  error_code ec;
1140  permissions(p, prms, ec);
1141  if (ec.value())
1142    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1143}
1144
1145void
1146fs::permissions(const path& p, perms prms, error_code& ec) noexcept
1147{
1148  const bool add = is_set(prms, perms::add_perms);
1149  const bool remove = is_set(prms, perms::remove_perms);
1150  const bool nofollow = is_set(prms, perms::symlink_nofollow);
1151  if (add && remove)
1152    {
1153      ec = std::make_error_code(std::errc::invalid_argument);
1154      return;
1155    }
1156
1157  prms &= perms::mask;
1158
1159  file_status st;
1160  if (add || remove || nofollow)
1161    {
1162      st = nofollow ? symlink_status(p, ec) : status(p, ec);
1163      if (ec)
1164	return;
1165      auto curr = st.permissions();
1166      if (add)
1167	prms |= curr;
1168      else if (remove)
1169	prms = curr & ~prms;
1170    }
1171
1172  int err = 0;
1173#if _GLIBCXX_USE_FCHMODAT
1174  const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1175  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1176    err = errno;
1177#else
1178  if (nofollow && is_symlink(st))
1179    ec = std::make_error_code(std::errc::operation_not_supported);
1180  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
1181    err = errno;
1182#endif
1183
1184  if (err)
1185    ec.assign(err, std::generic_category());
1186  else
1187    ec.clear();
1188}
1189
1190fs::path
1191fs::read_symlink(const path& p)
1192{
1193  error_code ec;
1194  path tgt = read_symlink(p, ec);
1195  if (ec.value())
1196    _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1197  return tgt;
1198}
1199
1200fs::path fs::read_symlink(const path& p, error_code& ec)
1201{
1202#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1203  stat_type st;
1204  if (::lstat(p.c_str(), &st))
1205    {
1206      ec.assign(errno, std::generic_category());
1207      return {};
1208    }
1209  std::string buf(st.st_size, '\0');
1210  ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
1211  if (len == -1)
1212    {
1213      ec.assign(errno, std::generic_category());
1214      return {};
1215    }
1216  ec.clear();
1217  return path{buf.data(), buf.data()+len};
1218#else
1219  ec = std::make_error_code(std::errc::not_supported);
1220  return {};
1221#endif
1222}
1223
1224
1225bool
1226fs::remove(const path& p)
1227{
1228  error_code ec;
1229  bool result = fs::remove(p, ec);
1230  if (ec.value())
1231    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1232  return result;
1233}
1234
1235bool
1236fs::remove(const path& p, error_code& ec) noexcept
1237{
1238  if (exists(symlink_status(p, ec)))
1239    {
1240      if (::remove(p.c_str()) == 0)
1241	{
1242	  ec.clear();
1243	  return true;
1244	}
1245      else
1246	ec.assign(errno, std::generic_category());
1247    }
1248  return false;
1249}
1250
1251
1252std::uintmax_t
1253fs::remove_all(const path& p)
1254{
1255  error_code ec;
1256  bool result = remove_all(p, ec);
1257  if (ec.value())
1258    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1259  return result;
1260}
1261
1262std::uintmax_t
1263fs::remove_all(const path& p, error_code& ec) noexcept
1264{
1265  auto fs = symlink_status(p, ec);
1266  uintmax_t count = 0;
1267  if (ec.value() == 0 && fs.type() == file_type::directory)
1268    for (directory_iterator d(p, ec), end; ec.value() == 0 && d != end; ++d)
1269      count += fs::remove_all(d->path(), ec);
1270  if (ec.value())
1271    return -1;
1272  return fs::remove(p, ec) ? ++count : -1;  // fs:remove() calls ec.clear()
1273}
1274
1275void
1276fs::rename(const path& from, const path& to)
1277{
1278  error_code ec;
1279  rename(from, to, ec);
1280  if (ec.value())
1281    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1282}
1283
1284void
1285fs::rename(const path& from, const path& to, error_code& ec) noexcept
1286{
1287  if (::rename(from.c_str(), to.c_str()))
1288    ec.assign(errno, std::generic_category());
1289  else
1290    ec.clear();
1291}
1292
1293void
1294fs::resize_file(const path& p, uintmax_t size)
1295{
1296  error_code ec;
1297  resize_file(p, size, ec);
1298  if (ec.value())
1299    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1300}
1301
1302void
1303fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1304{
1305#ifdef _GLIBCXX_HAVE_UNISTD_H
1306  if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1307    ec.assign(EINVAL, std::generic_category());
1308  else if (::truncate(p.c_str(), size))
1309    ec.assign(errno, std::generic_category());
1310  else
1311    ec.clear();
1312#else
1313  ec = std::make_error_code(std::errc::not_supported);
1314#endif
1315}
1316
1317
1318fs::space_info
1319fs::space(const path& p)
1320{
1321  error_code ec;
1322  space_info s = space(p, ec);
1323  if (ec.value())
1324    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1325  return s;
1326}
1327
1328fs::space_info
1329fs::space(const path& p, error_code& ec) noexcept
1330{
1331  space_info info = {
1332    static_cast<uintmax_t>(-1),
1333    static_cast<uintmax_t>(-1),
1334    static_cast<uintmax_t>(-1)
1335  };
1336#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1337  struct ::statvfs f;
1338  if (::statvfs(p.c_str(), &f))
1339      ec.assign(errno, std::generic_category());
1340  else
1341    {
1342      info = space_info{
1343	f.f_blocks * f.f_frsize,
1344	f.f_bfree * f.f_frsize,
1345	f.f_bavail * f.f_frsize
1346      };
1347      ec.clear();
1348    }
1349#else
1350  ec = std::make_error_code(std::errc::not_supported);
1351#endif
1352  return info;
1353}
1354
1355#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1356fs::file_status
1357fs::status(const fs::path& p, error_code& ec) noexcept
1358{
1359  file_status status;
1360  stat_type st;
1361  if (::stat(p.c_str(), &st))
1362    {
1363      int err = errno;
1364      ec.assign(err, std::generic_category());
1365      if (is_not_found_errno(err))
1366	status.type(file_type::not_found);
1367#ifdef EOVERFLOW
1368      else if (err == EOVERFLOW)
1369	status.type(file_type::unknown);
1370#endif
1371    }
1372  else
1373    {
1374      status = make_file_status(st);
1375      ec.clear();
1376    }
1377  return status;
1378}
1379
1380fs::file_status
1381fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1382{
1383  file_status status;
1384  stat_type st;
1385  if (::lstat(p.c_str(), &st))
1386    {
1387      int err = errno;
1388      ec.assign(err, std::generic_category());
1389      if (is_not_found_errno(err))
1390	status.type(file_type::not_found);
1391    }
1392  else
1393    {
1394      status = make_file_status(st);
1395      ec.clear();
1396    }
1397  return status;
1398}
1399#endif
1400
1401fs::file_status
1402fs::status(const fs::path& p)
1403{
1404  std::error_code ec;
1405  auto result = status(p, ec);
1406  if (result.type() == file_type::none)
1407    _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1408  return result;
1409}
1410
1411fs::file_status
1412fs::symlink_status(const fs::path& p)
1413{
1414  std::error_code ec;
1415  auto result = symlink_status(p, ec);
1416  if (result.type() == file_type::none)
1417    _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1418  return result;
1419}
1420
1421fs::path
1422fs::system_complete(const path& p)
1423{
1424  error_code ec;
1425  path comp = system_complete(p, ec);
1426  if (ec.value())
1427    _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1428  return comp;
1429}
1430
1431fs::path
1432fs::system_complete(const path& p, error_code& ec)
1433{
1434  path base = current_path(ec);
1435#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1436  if (p.is_absolute() || !p.has_root_name()
1437      || p.root_name() == base.root_name())
1438    return absolute(p, base);
1439  // else TODO
1440  ec = std::make_error_code(std::errc::not_supported);
1441  return {};
1442#else
1443  if (ec.value())
1444    return {};
1445  return absolute(p, base);
1446#endif
1447}
1448
1449fs::path fs::temp_directory_path()
1450{
1451  error_code ec;
1452  path tmp = temp_directory_path(ec);
1453  if (ec.value())
1454    _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1455  return tmp;
1456}
1457
1458fs::path fs::temp_directory_path(error_code& ec)
1459{
1460#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1461  ec = std::make_error_code(std::errc::not_supported);
1462  return {}; // TODO
1463#else
1464  const char* tmpdir = nullptr;
1465  const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1466  for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1467    tmpdir = ::getenv(*e);
1468  path p = tmpdir ? tmpdir : "/tmp";
1469  auto st = status(p, ec);
1470  if (!ec)
1471    {
1472      if (is_directory(st))
1473	{
1474	  ec.clear();
1475	  return p;
1476	}
1477      else
1478	ec = std::make_error_code(std::errc::not_a_directory);
1479    }
1480  return {};
1481#endif
1482}
1483
1484