ops.cc revision 1.3
1// Filesystem operations -*- C++ -*-
2
3// Copyright (C) 2014-2017 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    size_t count = from_st->st_size;
447#ifdef _GLIBCXX_USE_SENDFILE
448    off_t offset = 0;
449    ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
450    if (n < 0 && errno != ENOSYS && errno != EINVAL)
451      {
452	ec.assign(errno, std::generic_category());
453	return false;
454      }
455    if ((size_t)n == count)
456      {
457	if (!out.close() || !in.close())
458	  {
459	    ec.assign(errno, std::generic_category());
460	    return false;
461	  }
462	ec.clear();
463	return true;
464      }
465    else if (n > 0)
466      count -= n;
467#endif // _GLIBCXX_USE_SENDFILE
468
469    using std::ios;
470    __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
471    __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
472
473    if (sbin.is_open())
474      in.fd = -1;
475    if (sbout.is_open())
476      out.fd = -1;
477
478#ifdef _GLIBCXX_USE_SENDFILE
479    if (n != 0)
480      {
481	if (n < 0)
482	  n = 0;
483
484	const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in);
485	const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out);
486
487	const std::streampos errpos(std::streamoff(-1));
488	if (p1 == errpos || p2 == errpos)
489	  {
490	    ec = std::make_error_code(std::errc::io_error);
491	    return false;
492	  }
493      }
494#endif
495
496    if (count && !(std::ostream(&sbout) << &sbin))
497      {
498	ec = std::make_error_code(std::errc::io_error);
499	return false;
500      }
501    if (!sbout.close() || !sbin.close())
502      {
503	ec.assign(errno, std::generic_category());
504	return false;
505      }
506    ec.clear();
507    return true;
508  }
509}
510#endif
511
512void
513fs::copy(const path& from, const path& to, copy_options options,
514	 error_code& ec) noexcept
515{
516  const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
517  const bool create_symlinks = is_set(options, copy_options::create_symlinks);
518  const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
519  const bool use_lstat = create_symlinks || skip_symlinks;
520
521  file_status f, t;
522  stat_type from_st, to_st;
523  // _GLIBCXX_RESOLVE_LIB_DEFECTS
524  // 2681. filesystem::copy() cannot copy symlinks
525  if (use_lstat || copy_symlinks
526      ? ::lstat(from.c_str(), &from_st)
527      : ::stat(from.c_str(), &from_st))
528    {
529      ec.assign(errno, std::generic_category());
530      return;
531    }
532  if (use_lstat
533      ? ::lstat(to.c_str(), &to_st)
534      : ::stat(to.c_str(), &to_st))
535    {
536      if (!is_not_found_errno(errno))
537	{
538	  ec.assign(errno, std::generic_category());
539	  return;
540	}
541      t = file_status{file_type::not_found};
542    }
543  else
544    t = make_file_status(to_st);
545  f = make_file_status(from_st);
546
547  if (exists(t) && !is_other(t) && !is_other(f)
548      && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
549    {
550      ec = std::make_error_code(std::errc::file_exists);
551      return;
552    }
553  if (is_other(f) || is_other(t))
554    {
555      ec = std::make_error_code(std::errc::not_supported);
556      return;
557    }
558  if (is_directory(f) && is_regular_file(t))
559    {
560      ec = std::make_error_code(std::errc::is_a_directory);
561      return;
562    }
563
564  if (is_symlink(f))
565    {
566      if (skip_symlinks)
567	ec.clear();
568      else if (!exists(t) && copy_symlinks)
569	copy_symlink(from, to, ec);
570      else
571	// Not clear what should be done here.
572	// "Otherwise report an error as specified in Error reporting (7)."
573	ec = std::make_error_code(std::errc::invalid_argument);
574    }
575  else if (is_regular_file(f))
576    {
577      if (is_set(options, copy_options::directories_only))
578	ec.clear();
579      else if (create_symlinks)
580	create_symlink(from, to, ec);
581      else if (is_set(options, copy_options::create_hard_links))
582	create_hard_link(from, to, ec);
583      else if (is_directory(t))
584	do_copy_file(from, to / from.filename(), options, &from_st, 0, ec);
585      else
586	{
587	  auto ptr = exists(t) ? &to_st : &from_st;
588	  do_copy_file(from, to, options, &from_st, ptr,  ec);
589	}
590    }
591  // _GLIBCXX_RESOLVE_LIB_DEFECTS
592  // 2682. filesystem::copy() won't create a symlink to a directory
593  else if (is_directory(f) && create_symlinks)
594    ec = std::make_error_code(errc::is_a_directory);
595  else if (is_directory(f) && (is_set(options, copy_options::recursive)
596			       || options == copy_options::none))
597    {
598      if (!exists(t))
599	if (!create_directory(to, from, ec))
600	  return;
601      // set an unused bit in options to disable further recursion
602      if (!is_set(options, copy_options::recursive))
603	options |= static_cast<copy_options>(4096);
604      for (const directory_entry& x : directory_iterator(from))
605	copy(x.path(), to/x.path().filename(), options, ec);
606    }
607  // _GLIBCXX_RESOLVE_LIB_DEFECTS
608  // 2683. filesystem::copy() says "no effects"
609  else
610    ec.clear();
611}
612
613bool
614fs::copy_file(const path& from, const path& to, copy_options option)
615{
616  error_code ec;
617  bool result = copy_file(from, to, option, ec);
618  if (ec.value())
619    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
620	  ec));
621  return result;
622}
623
624bool
625fs::copy_file(const path& from, const path& to, copy_options option,
626	      error_code& ec) noexcept
627{
628#ifdef _GLIBCXX_HAVE_SYS_STAT_H
629  return do_copy_file(from, to, option, nullptr, nullptr, ec);
630#else
631  ec = std::make_error_code(std::errc::not_supported);
632  return false;
633#endif
634}
635
636
637void
638fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
639{
640  error_code ec;
641  copy_symlink(existing_symlink, new_symlink, ec);
642  if (ec.value())
643    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
644	  existing_symlink, new_symlink, ec));
645}
646
647void
648fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
649		 error_code& ec) noexcept
650{
651  auto p = read_symlink(existing_symlink, ec);
652  if (ec.value())
653    return;
654#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
655  if (is_directory(p))
656    {
657      create_directory_symlink(p, new_symlink, ec);
658      return;
659    }
660#endif
661  create_symlink(p, new_symlink, ec);
662}
663
664
665bool
666fs::create_directories(const path& p)
667{
668  error_code ec;
669  bool result = create_directories(p, ec);
670  if (ec.value())
671    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
672	  ec));
673  return result;
674}
675
676bool
677fs::create_directories(const path& p, error_code& ec) noexcept
678{
679  if (p.empty())
680    {
681      ec = std::make_error_code(errc::invalid_argument);
682      return false;
683    }
684  std::stack<path> missing;
685  path pp = p;
686
687  while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
688    {
689      ec.clear();
690      const auto& filename = pp.filename();
691      if (!is_dot(filename) && !is_dotdot(filename))
692	missing.push(pp);
693      pp.remove_filename();
694    }
695
696  if (ec || missing.empty())
697    return false;
698
699  do
700    {
701      const path& top = missing.top();
702      create_directory(top, ec);
703      if (ec && is_directory(top))
704	ec.clear();
705      missing.pop();
706    }
707  while (!missing.empty() && !ec);
708
709  return missing.empty();
710}
711
712namespace
713{
714  bool
715  create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
716  {
717    bool created = false;
718#ifdef _GLIBCXX_HAVE_SYS_STAT_H
719    ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
720    if (::mkdir(p.c_str(), mode))
721      {
722	const int err = errno;
723	if (err != EEXIST || !is_directory(p, ec))
724	  ec.assign(err, std::generic_category());
725      }
726    else
727      {
728	ec.clear();
729	created = true;
730      }
731#else
732    ec = std::make_error_code(std::errc::not_supported);
733#endif
734    return created;
735  }
736} // namespace
737
738bool
739fs::create_directory(const path& p)
740{
741  error_code ec;
742  bool result = create_directory(p, 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, error_code& ec) noexcept
751{
752  return create_dir(p, perms::all, ec);
753}
754
755
756bool
757fs::create_directory(const path& p, const path& attributes)
758{
759  error_code ec;
760  bool result = create_directory(p, attributes, ec);
761  if (ec.value())
762    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
763	  ec));
764  return result;
765}
766
767bool
768fs::create_directory(const path& p, const path& attributes,
769		     error_code& ec) noexcept
770{
771#ifdef _GLIBCXX_HAVE_SYS_STAT_H
772  stat_type st;
773  if (::stat(attributes.c_str(), &st))
774    {
775      ec.assign(errno, std::generic_category());
776      return false;
777    }
778  return create_dir(p, static_cast<perms>(st.st_mode), ec);
779#else
780  ec = std::make_error_code(std::errc::not_supported);
781  return false;
782#endif
783}
784
785
786void
787fs::create_directory_symlink(const path& to, const path& new_symlink)
788{
789  error_code ec;
790  create_directory_symlink(to, new_symlink, ec);
791  if (ec.value())
792    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
793	  to, new_symlink, ec));
794}
795
796void
797fs::create_directory_symlink(const path& to, const path& new_symlink,
798			     error_code& ec) noexcept
799{
800#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
801  ec = std::make_error_code(std::errc::not_supported);
802#else
803  create_symlink(to, new_symlink, ec);
804#endif
805}
806
807
808void
809fs::create_hard_link(const path& to, const path& new_hard_link)
810{
811  error_code ec;
812  create_hard_link(to, new_hard_link, ec);
813  if (ec.value())
814    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
815	  to, new_hard_link, ec));
816}
817
818void
819fs::create_hard_link(const path& to, const path& new_hard_link,
820		     error_code& ec) noexcept
821{
822#ifdef _GLIBCXX_HAVE_UNISTD_H
823  if (::link(to.c_str(), new_hard_link.c_str()))
824    ec.assign(errno, std::generic_category());
825  else
826    ec.clear();
827#else
828  ec = std::make_error_code(std::errc::not_supported);
829#endif
830}
831
832void
833fs::create_symlink(const path& to, const path& new_symlink)
834{
835  error_code ec;
836  create_symlink(to, new_symlink, ec);
837  if (ec.value())
838    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
839	  to, new_symlink, ec));
840}
841
842void
843fs::create_symlink(const path& to, const path& new_symlink,
844		   error_code& ec) noexcept
845{
846#ifdef _GLIBCXX_HAVE_UNISTD_H
847  if (::symlink(to.c_str(), new_symlink.c_str()))
848    ec.assign(errno, std::generic_category());
849  else
850    ec.clear();
851#else
852  ec = std::make_error_code(std::errc::not_supported);
853#endif
854}
855
856
857fs::path
858fs::current_path()
859{
860  error_code ec;
861  path p = current_path(ec);
862  if (ec.value())
863    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
864  return p;
865}
866
867fs::path
868fs::current_path(error_code& ec)
869{
870  path p;
871#ifdef _GLIBCXX_HAVE_UNISTD_H
872#ifdef __GLIBC__
873  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
874    {
875      p.assign(cwd.get());
876      ec.clear();
877    }
878  else
879    ec.assign(errno, std::generic_category());
880#else
881  long path_max = pathconf(".", _PC_PATH_MAX);
882  size_t size;
883  if (path_max == -1)
884      size = 1024;
885  else if (path_max > 10240)
886      size = 10240;
887  else
888      size = path_max;
889  for (char_ptr buf; p.empty(); size *= 2)
890    {
891      buf.reset((char*)malloc(size));
892      if (buf)
893	{
894	  if (getcwd(buf.get(), size))
895	    {
896	      p.assign(buf.get());
897	      ec.clear();
898	    }
899	  else if (errno != ERANGE)
900	    {
901	      ec.assign(errno, std::generic_category());
902	      return {};
903	    }
904	}
905      else
906	{
907	  ec = std::make_error_code(std::errc::not_enough_memory);
908	  return {};
909	}
910    }
911#endif  // __GLIBC__
912#else   // _GLIBCXX_HAVE_UNISTD_H
913  ec = std::make_error_code(std::errc::not_supported);
914#endif
915  return p;
916}
917
918void
919fs::current_path(const path& p)
920{
921  error_code ec;
922  current_path(p, ec);
923  if (ec.value())
924    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
925}
926
927void
928fs::current_path(const path& p, error_code& ec) noexcept
929{
930#ifdef _GLIBCXX_HAVE_UNISTD_H
931  if (::chdir(p.c_str()))
932    ec.assign(errno, std::generic_category());
933  else
934    ec.clear();
935#else
936  ec = std::make_error_code(std::errc::not_supported);
937#endif
938}
939
940bool
941fs::equivalent(const path& p1, const path& p2)
942{
943  error_code ec;
944  auto result = equivalent(p1, p2, ec);
945  if (ec)
946    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
947	  p1, p2, ec));
948  return result;
949}
950
951bool
952fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
953{
954#ifdef _GLIBCXX_HAVE_SYS_STAT_H
955  int err = 0;
956  file_status s1, s2;
957  stat_type st1, st2;
958  if (::stat(p1.c_str(), &st1) == 0)
959    s1 = make_file_status(st1);
960  else if (is_not_found_errno(errno))
961    s1.type(file_type::not_found);
962  else
963    err = errno;
964
965  if (::stat(p2.c_str(), &st2) == 0)
966    s2 = make_file_status(st2);
967  else if (is_not_found_errno(errno))
968    s2.type(file_type::not_found);
969  else
970    err = errno;
971
972  if (exists(s1) && exists(s2))
973    {
974      if (is_other(s1) && is_other(s2))
975	{
976	  ec = std::make_error_code(std::errc::not_supported);
977	  return false;
978	}
979      ec.clear();
980      if (is_other(s1) || is_other(s2))
981	return false;
982      return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
983    }
984  else if (!exists(s1) && !exists(s2))
985    ec = std::make_error_code(std::errc::no_such_file_or_directory);
986  else if (err)
987    ec.assign(err, std::generic_category());
988  else
989    ec.clear();
990  return false;
991#else
992  ec = std::make_error_code(std::errc::not_supported);
993#endif
994  return false;
995}
996
997std::uintmax_t
998fs::file_size(const path& p)
999{
1000  error_code ec;
1001  auto sz = file_size(p, ec);
1002  if (ec.value())
1003    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
1004  return sz;
1005}
1006
1007namespace
1008{
1009  template<typename Accessor, typename T>
1010    inline T
1011    do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
1012    {
1013#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1014      stat_type st;
1015      if (::stat(p.c_str(), &st))
1016	{
1017	  ec.assign(errno, std::generic_category());
1018	  return deflt;
1019	}
1020      ec.clear();
1021      return f(st);
1022#else
1023      ec = std::make_error_code(std::errc::not_supported);
1024      return deflt;
1025#endif
1026    }
1027}
1028
1029std::uintmax_t
1030fs::file_size(const path& p, error_code& ec) noexcept
1031{
1032  struct S
1033  {
1034    S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
1035    S() : type(file_type::not_found) { }
1036    file_type type;
1037    size_t size;
1038  };
1039  auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
1040  if (s.type == file_type::regular)
1041    return s.size;
1042  if (!ec)
1043    {
1044      if (s.type == file_type::directory)
1045	ec = std::make_error_code(std::errc::is_a_directory);
1046      else
1047	ec = std::make_error_code(std::errc::not_supported);
1048    }
1049  return -1;
1050}
1051
1052std::uintmax_t
1053fs::hard_link_count(const path& p)
1054{
1055  error_code ec;
1056  auto count = hard_link_count(p, ec);
1057  if (ec.value())
1058    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
1059  return count;
1060}
1061
1062std::uintmax_t
1063fs::hard_link_count(const path& p, error_code& ec) noexcept
1064{
1065  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
1066		 static_cast<uintmax_t>(-1));
1067}
1068
1069bool
1070fs::is_empty(const path& p)
1071{
1072  error_code ec;
1073  bool e = is_empty(p, ec);
1074  if (ec)
1075    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1076					     p, ec));
1077  return e;
1078}
1079
1080bool
1081fs::is_empty(const path& p, error_code& ec) noexcept
1082{
1083  auto s = status(p, ec);
1084  if (ec)
1085    return false;
1086  bool empty = fs::is_directory(s)
1087    ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1088    : fs::file_size(p, ec) == 0;
1089  return ec ? false : empty;
1090}
1091
1092fs::file_time_type
1093fs::last_write_time(const path& p)
1094{
1095  error_code ec;
1096  auto t = last_write_time(p, ec);
1097  if (ec.value())
1098    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1099  return t;
1100}
1101
1102fs::file_time_type
1103fs::last_write_time(const path& p, error_code& ec) noexcept
1104{
1105  return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
1106		 file_time_type::min());
1107}
1108
1109void
1110fs::last_write_time(const path& p, file_time_type new_time)
1111{
1112  error_code ec;
1113  last_write_time(p, new_time, ec);
1114  if (ec.value())
1115    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1116}
1117
1118void
1119fs::last_write_time(const path& p __attribute__((__unused__)),
1120		    file_time_type new_time, error_code& ec) noexcept
1121{
1122  auto d = new_time.time_since_epoch();
1123  auto s = chrono::duration_cast<chrono::seconds>(d);
1124#if _GLIBCXX_USE_UTIMENSAT
1125  auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1126  if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1127    {
1128      --s;
1129      ns += chrono::seconds(1);
1130    }
1131  struct ::timespec ts[2];
1132  ts[0].tv_sec = 0;
1133  ts[0].tv_nsec = UTIME_OMIT;
1134  ts[1].tv_sec = static_cast<std::time_t>(s.count());
1135  ts[1].tv_nsec = static_cast<long>(ns.count());
1136  if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1137    ec.assign(errno, std::generic_category());
1138  else
1139    ec.clear();
1140#elif _GLIBCXX_HAVE_UTIME_H
1141  ::utimbuf times;
1142  times.modtime = s.count();
1143  times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1144			 times.modtime);
1145  if (::utime(p.c_str(), &times))
1146    ec.assign(errno, std::generic_category());
1147  else
1148    ec.clear();
1149#else
1150  ec = std::make_error_code(std::errc::not_supported);
1151#endif
1152}
1153
1154void
1155fs::permissions(const path& p, perms prms)
1156{
1157  error_code ec;
1158  permissions(p, prms, ec);
1159  if (ec.value())
1160    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1161}
1162
1163void
1164fs::permissions(const path& p, perms prms, error_code& ec) noexcept
1165{
1166  const bool add = is_set(prms, perms::add_perms);
1167  const bool remove = is_set(prms, perms::remove_perms);
1168  const bool nofollow = is_set(prms, perms::symlink_nofollow);
1169  if (add && remove)
1170    {
1171      ec = std::make_error_code(std::errc::invalid_argument);
1172      return;
1173    }
1174
1175  prms &= perms::mask;
1176
1177  file_status st;
1178  if (add || remove || nofollow)
1179    {
1180      st = nofollow ? symlink_status(p, ec) : status(p, ec);
1181      if (ec)
1182	return;
1183      auto curr = st.permissions();
1184      if (add)
1185	prms |= curr;
1186      else if (remove)
1187	prms = curr & ~prms;
1188    }
1189
1190  int err = 0;
1191#if _GLIBCXX_USE_FCHMODAT
1192  const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1193  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1194    err = errno;
1195#else
1196  if (nofollow && is_symlink(st))
1197    ec = std::make_error_code(std::errc::operation_not_supported);
1198  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
1199    err = errno;
1200#endif
1201
1202  if (err)
1203    ec.assign(err, std::generic_category());
1204  else
1205    ec.clear();
1206}
1207
1208fs::path
1209fs::read_symlink(const path& p)
1210{
1211  error_code ec;
1212  path tgt = read_symlink(p, ec);
1213  if (ec.value())
1214    _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1215  return tgt;
1216}
1217
1218fs::path fs::read_symlink(const path& p, error_code& ec)
1219{
1220  path result;
1221#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1222  stat_type st;
1223  if (::lstat(p.c_str(), &st))
1224    {
1225      ec.assign(errno, std::generic_category());
1226      return result;
1227    }
1228  std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1229  do
1230    {
1231      ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
1232      if (len == -1)
1233	{
1234	  ec.assign(errno, std::generic_category());
1235	  return result;
1236	}
1237      else if (len == (ssize_t)buf.size())
1238	{
1239	  if (buf.size() > 4096)
1240	    {
1241	      ec.assign(ENAMETOOLONG, std::generic_category());
1242	      return result;
1243	    }
1244	  buf.resize(buf.size() * 2);
1245	}
1246      else
1247	{
1248	  buf.resize(len);
1249	  result.assign(buf);
1250	  ec.clear();
1251	  break;
1252	}
1253    }
1254  while (true);
1255#else
1256  ec = std::make_error_code(std::errc::not_supported);
1257#endif
1258  return result;
1259}
1260
1261
1262bool
1263fs::remove(const path& p)
1264{
1265  error_code ec;
1266  bool result = fs::remove(p, ec);
1267  if (ec)
1268    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1269  return result;
1270}
1271
1272bool
1273fs::remove(const path& p, error_code& ec) noexcept
1274{
1275  if (::remove(p.c_str()) == 0)
1276    {
1277      ec.clear();
1278      return true;
1279    }
1280  else if (errno == ENOENT)
1281    ec.clear();
1282  else
1283    ec.assign(errno, std::generic_category());
1284  return false;
1285}
1286
1287
1288std::uintmax_t
1289fs::remove_all(const path& p)
1290{
1291  error_code ec;
1292  const auto result = remove_all(p, ec);
1293  if (ec)
1294    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1295  return result;
1296}
1297
1298std::uintmax_t
1299fs::remove_all(const path& p, error_code& ec) noexcept
1300{
1301  const auto s = symlink_status(p, ec);
1302  if (!status_known(s))
1303    return -1;
1304
1305  ec.clear();
1306  if (s.type() == file_type::not_found)
1307    return 0;
1308
1309  uintmax_t count = 0;
1310  if (s.type() == file_type::directory)
1311    {
1312      for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
1313	count += fs::remove_all(d->path(), ec);
1314      if (ec.value() == ENOENT)
1315	ec.clear();
1316      else if (ec)
1317	return -1;
1318    }
1319
1320  if (fs::remove(p, ec))
1321    ++count;
1322  return ec ? -1 : count;
1323}
1324
1325void
1326fs::rename(const path& from, const path& to)
1327{
1328  error_code ec;
1329  rename(from, to, ec);
1330  if (ec.value())
1331    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1332}
1333
1334void
1335fs::rename(const path& from, const path& to, error_code& ec) noexcept
1336{
1337  if (::rename(from.c_str(), to.c_str()))
1338    ec.assign(errno, std::generic_category());
1339  else
1340    ec.clear();
1341}
1342
1343void
1344fs::resize_file(const path& p, uintmax_t size)
1345{
1346  error_code ec;
1347  resize_file(p, size, ec);
1348  if (ec.value())
1349    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1350}
1351
1352void
1353fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1354{
1355#ifdef _GLIBCXX_HAVE_UNISTD_H
1356  if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1357    ec.assign(EINVAL, std::generic_category());
1358  else if (::truncate(p.c_str(), size))
1359    ec.assign(errno, std::generic_category());
1360  else
1361    ec.clear();
1362#else
1363  ec = std::make_error_code(std::errc::not_supported);
1364#endif
1365}
1366
1367
1368fs::space_info
1369fs::space(const path& p)
1370{
1371  error_code ec;
1372  space_info s = space(p, ec);
1373  if (ec.value())
1374    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1375  return s;
1376}
1377
1378fs::space_info
1379fs::space(const path& p, error_code& ec) noexcept
1380{
1381  space_info info = {
1382    static_cast<uintmax_t>(-1),
1383    static_cast<uintmax_t>(-1),
1384    static_cast<uintmax_t>(-1)
1385  };
1386#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1387  struct ::statvfs f;
1388  if (::statvfs(p.c_str(), &f))
1389      ec.assign(errno, std::generic_category());
1390  else
1391    {
1392      uintmax_t fragment_size = f.f_frsize;
1393      info = space_info{
1394	f.f_blocks * fragment_size,
1395	f.f_bfree * fragment_size,
1396	f.f_bavail * fragment_size
1397      };
1398      ec.clear();
1399    }
1400#else
1401  ec = std::make_error_code(std::errc::not_supported);
1402#endif
1403  return info;
1404}
1405
1406#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1407fs::file_status
1408fs::status(const fs::path& p, error_code& ec) noexcept
1409{
1410  file_status status;
1411  stat_type st;
1412  if (::stat(p.c_str(), &st))
1413    {
1414      int err = errno;
1415      ec.assign(err, std::generic_category());
1416      if (is_not_found_errno(err))
1417	status.type(file_type::not_found);
1418#ifdef EOVERFLOW
1419      else if (err == EOVERFLOW)
1420	status.type(file_type::unknown);
1421#endif
1422    }
1423  else
1424    {
1425      status = make_file_status(st);
1426      ec.clear();
1427    }
1428  return status;
1429}
1430
1431fs::file_status
1432fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1433{
1434  file_status status;
1435  stat_type st;
1436  if (::lstat(p.c_str(), &st))
1437    {
1438      int err = errno;
1439      ec.assign(err, std::generic_category());
1440      if (is_not_found_errno(err))
1441	status.type(file_type::not_found);
1442    }
1443  else
1444    {
1445      status = make_file_status(st);
1446      ec.clear();
1447    }
1448  return status;
1449}
1450#endif
1451
1452fs::file_status
1453fs::status(const fs::path& p)
1454{
1455  std::error_code ec;
1456  auto result = status(p, ec);
1457  if (result.type() == file_type::none)
1458    _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1459  return result;
1460}
1461
1462fs::file_status
1463fs::symlink_status(const fs::path& p)
1464{
1465  std::error_code ec;
1466  auto result = symlink_status(p, ec);
1467  if (result.type() == file_type::none)
1468    _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1469  return result;
1470}
1471
1472fs::path
1473fs::system_complete(const path& p)
1474{
1475  error_code ec;
1476  path comp = system_complete(p, ec);
1477  if (ec.value())
1478    _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1479  return comp;
1480}
1481
1482fs::path
1483fs::system_complete(const path& p, error_code& ec)
1484{
1485  path base = current_path(ec);
1486#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1487  if (p.is_absolute() || !p.has_root_name()
1488      || p.root_name() == base.root_name())
1489    return absolute(p, base);
1490  // else TODO
1491  ec = std::make_error_code(std::errc::not_supported);
1492  return {};
1493#else
1494  if (ec.value())
1495    return {};
1496  return absolute(p, base);
1497#endif
1498}
1499
1500fs::path fs::temp_directory_path()
1501{
1502  error_code ec;
1503  path tmp = temp_directory_path(ec);
1504  if (ec.value())
1505    _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1506  return tmp;
1507}
1508
1509fs::path fs::temp_directory_path(error_code& ec)
1510{
1511#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1512  ec = std::make_error_code(std::errc::not_supported);
1513  return {}; // TODO
1514#else
1515  const char* tmpdir = nullptr;
1516  const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1517  for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1518    tmpdir = ::getenv(*e);
1519  path p = tmpdir ? tmpdir : "/tmp";
1520  auto st = status(p, ec);
1521  if (!ec)
1522    {
1523      if (is_directory(st))
1524	{
1525	  ec.clear();
1526	  return p;
1527	}
1528      else
1529	ec = std::make_error_code(std::errc::not_a_directory);
1530    }
1531  return {};
1532#endif
1533}
1534
1535