ops.cc revision 1.1.1.4
1// Filesystem operations -*- C++ -*-
2
3// Copyright (C) 2014-2016 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))
724	  ec.assign(err, std::generic_category());
725	else
726	  ec.clear();
727      }
728    else
729      {
730	ec.clear();
731	created = true;
732      }
733#else
734    ec = std::make_error_code(std::errc::not_supported);
735#endif
736    return created;
737  }
738} // namespace
739
740bool
741fs::create_directory(const path& p)
742{
743  error_code ec;
744  bool result = create_directory(p, ec);
745  if (ec.value())
746    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
747	  ec));
748  return result;
749}
750
751bool
752fs::create_directory(const path& p, error_code& ec) noexcept
753{
754  return create_dir(p, perms::all, ec);
755}
756
757
758bool
759fs::create_directory(const path& p, const path& attributes)
760{
761  error_code ec;
762  bool result = create_directory(p, attributes, ec);
763  if (ec.value())
764    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
765	  ec));
766  return result;
767}
768
769bool
770fs::create_directory(const path& p, const path& attributes,
771		     error_code& ec) noexcept
772{
773#ifdef _GLIBCXX_HAVE_SYS_STAT_H
774  stat_type st;
775  if (::stat(attributes.c_str(), &st))
776    {
777      ec.assign(errno, std::generic_category());
778      return false;
779    }
780  return create_dir(p, static_cast<perms>(st.st_mode), ec);
781#else
782  ec = std::make_error_code(std::errc::not_supported);
783  return false;
784#endif
785}
786
787
788void
789fs::create_directory_symlink(const path& to, const path& new_symlink)
790{
791  error_code ec;
792  create_directory_symlink(to, new_symlink, ec);
793  if (ec.value())
794    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
795	  to, new_symlink, ec));
796}
797
798void
799fs::create_directory_symlink(const path& to, const path& new_symlink,
800			     error_code& ec) noexcept
801{
802#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
803  ec = std::make_error_code(std::errc::not_supported);
804#else
805  create_symlink(to, new_symlink, ec);
806#endif
807}
808
809
810void
811fs::create_hard_link(const path& to, const path& new_hard_link)
812{
813  error_code ec;
814  create_hard_link(to, new_hard_link, ec);
815  if (ec.value())
816    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
817	  to, new_hard_link, ec));
818}
819
820void
821fs::create_hard_link(const path& to, const path& new_hard_link,
822		     error_code& ec) noexcept
823{
824#ifdef _GLIBCXX_HAVE_UNISTD_H
825  if (::link(to.c_str(), new_hard_link.c_str()))
826    ec.assign(errno, std::generic_category());
827  else
828    ec.clear();
829#else
830  ec = std::make_error_code(std::errc::not_supported);
831#endif
832}
833
834void
835fs::create_symlink(const path& to, const path& new_symlink)
836{
837  error_code ec;
838  create_symlink(to, new_symlink, ec);
839  if (ec.value())
840    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
841	  to, new_symlink, ec));
842}
843
844void
845fs::create_symlink(const path& to, const path& new_symlink,
846		   error_code& ec) noexcept
847{
848#ifdef _GLIBCXX_HAVE_UNISTD_H
849  if (::symlink(to.c_str(), new_symlink.c_str()))
850    ec.assign(errno, std::generic_category());
851  else
852    ec.clear();
853#else
854  ec = std::make_error_code(std::errc::not_supported);
855#endif
856}
857
858
859fs::path
860fs::current_path()
861{
862  error_code ec;
863  path p = current_path(ec);
864  if (ec.value())
865    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
866  return p;
867}
868
869fs::path
870fs::current_path(error_code& ec)
871{
872  path p;
873#ifdef _GLIBCXX_HAVE_UNISTD_H
874#ifdef __GLIBC__
875  if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
876    {
877      p.assign(cwd.get());
878      ec.clear();
879    }
880  else
881    ec.assign(errno, std::generic_category());
882#else
883  long path_max = pathconf(".", _PC_PATH_MAX);
884  size_t size;
885  if (path_max == -1)
886      size = 1024;
887  else if (path_max > 10240)
888      size = 10240;
889  else
890      size = path_max;
891  for (char_ptr buf; p.empty(); size *= 2)
892    {
893      buf.reset((char*)malloc(size));
894      if (buf)
895	{
896	  if (getcwd(buf.get(), size))
897	    {
898	      p.assign(buf.get());
899	      ec.clear();
900	    }
901	  else if (errno != ERANGE)
902	    {
903	      ec.assign(errno, std::generic_category());
904	      return {};
905	    }
906	}
907      else
908	{
909	  ec = std::make_error_code(std::errc::not_enough_memory);
910	  return {};
911	}
912    }
913#endif  // __GLIBC__
914#else   // _GLIBCXX_HAVE_UNISTD_H
915  ec = std::make_error_code(std::errc::not_supported);
916#endif
917  return p;
918}
919
920void
921fs::current_path(const path& p)
922{
923  error_code ec;
924  current_path(p, ec);
925  if (ec.value())
926    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
927}
928
929void
930fs::current_path(const path& p, error_code& ec) noexcept
931{
932#ifdef _GLIBCXX_HAVE_UNISTD_H
933  if (::chdir(p.c_str()))
934    ec.assign(errno, std::generic_category());
935  else
936    ec.clear();
937#else
938  ec = std::make_error_code(std::errc::not_supported);
939#endif
940}
941
942bool
943fs::equivalent(const path& p1, const path& p2)
944{
945  error_code ec;
946  auto result = equivalent(p1, p2, ec);
947  if (ec)
948    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
949	  p1, p2, ec));
950  return result;
951}
952
953bool
954fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
955{
956#ifdef _GLIBCXX_HAVE_SYS_STAT_H
957  int err = 0;
958  file_status s1, s2;
959  stat_type st1, st2;
960  if (::stat(p1.c_str(), &st1) == 0)
961    s1 = make_file_status(st1);
962  else if (is_not_found_errno(errno))
963    s1.type(file_type::not_found);
964  else
965    err = errno;
966
967  if (::stat(p2.c_str(), &st2) == 0)
968    s2 = make_file_status(st2);
969  else if (is_not_found_errno(errno))
970    s2.type(file_type::not_found);
971  else
972    err = errno;
973
974  if (exists(s1) && exists(s2))
975    {
976      if (is_other(s1) && is_other(s2))
977	{
978	  ec = std::make_error_code(std::errc::not_supported);
979	  return false;
980	}
981      ec.clear();
982      if (is_other(s1) || is_other(s2))
983	return false;
984      return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
985    }
986  else if (!exists(s1) && !exists(s2))
987    ec = std::make_error_code(std::errc::no_such_file_or_directory);
988  else if (err)
989    ec.assign(err, std::generic_category());
990  else
991    ec.clear();
992  return false;
993#else
994  ec = std::make_error_code(std::errc::not_supported);
995#endif
996  return false;
997}
998
999std::uintmax_t
1000fs::file_size(const path& p)
1001{
1002  error_code ec;
1003  auto sz = file_size(p, ec);
1004  if (ec.value())
1005    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
1006  return sz;
1007}
1008
1009namespace
1010{
1011  template<typename Accessor, typename T>
1012    inline T
1013    do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
1014    {
1015#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1016      stat_type st;
1017      if (::stat(p.c_str(), &st))
1018	{
1019	  ec.assign(errno, std::generic_category());
1020	  return deflt;
1021	}
1022      ec.clear();
1023      return f(st);
1024#else
1025      ec = std::make_error_code(std::errc::not_supported);
1026      return deflt;
1027#endif
1028    }
1029}
1030
1031std::uintmax_t
1032fs::file_size(const path& p, error_code& ec) noexcept
1033{
1034  struct S
1035  {
1036    S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
1037    S() : type(file_type::not_found) { }
1038    file_type type;
1039    size_t size;
1040  };
1041  auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
1042  if (s.type == file_type::regular)
1043    return s.size;
1044  if (!ec)
1045    {
1046      if (s.type == file_type::directory)
1047	ec = std::make_error_code(std::errc::is_a_directory);
1048      else
1049	ec = std::make_error_code(std::errc::not_supported);
1050    }
1051  return -1;
1052}
1053
1054std::uintmax_t
1055fs::hard_link_count(const path& p)
1056{
1057  error_code ec;
1058  auto count = hard_link_count(p, ec);
1059  if (ec.value())
1060    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
1061  return count;
1062}
1063
1064std::uintmax_t
1065fs::hard_link_count(const path& p, error_code& ec) noexcept
1066{
1067  return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
1068		 static_cast<uintmax_t>(-1));
1069}
1070
1071bool
1072fs::is_empty(const path& p)
1073{
1074  error_code ec;
1075  bool e = is_empty(p, ec);
1076  if (ec)
1077    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
1078					     p, ec));
1079  return e;
1080}
1081
1082bool
1083fs::is_empty(const path& p, error_code& ec) noexcept
1084{
1085  auto s = status(p, ec);
1086  if (ec)
1087    return false;
1088  bool empty = fs::is_directory(s)
1089    ? fs::directory_iterator(p, ec) == fs::directory_iterator()
1090    : fs::file_size(p, ec) == 0;
1091  return ec ? false : empty;
1092}
1093
1094fs::file_time_type
1095fs::last_write_time(const path& p)
1096{
1097  error_code ec;
1098  auto t = last_write_time(p, ec);
1099  if (ec.value())
1100    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
1101  return t;
1102}
1103
1104fs::file_time_type
1105fs::last_write_time(const path& p, error_code& ec) noexcept
1106{
1107  return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
1108		 file_time_type::min());
1109}
1110
1111void
1112fs::last_write_time(const path& p, file_time_type new_time)
1113{
1114  error_code ec;
1115  last_write_time(p, new_time, ec);
1116  if (ec.value())
1117    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
1118}
1119
1120void
1121fs::last_write_time(const path& p __attribute__((__unused__)),
1122		    file_time_type new_time, error_code& ec) noexcept
1123{
1124  auto d = new_time.time_since_epoch();
1125  auto s = chrono::duration_cast<chrono::seconds>(d);
1126#if _GLIBCXX_USE_UTIMENSAT
1127  auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
1128  if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
1129    {
1130      --s;
1131      ns += chrono::seconds(1);
1132    }
1133  struct ::timespec ts[2];
1134  ts[0].tv_sec = 0;
1135  ts[0].tv_nsec = UTIME_OMIT;
1136  ts[1].tv_sec = static_cast<std::time_t>(s.count());
1137  ts[1].tv_nsec = static_cast<long>(ns.count());
1138  if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
1139    ec.assign(errno, std::generic_category());
1140  else
1141    ec.clear();
1142#elif _GLIBCXX_HAVE_UTIME_H
1143  ::utimbuf times;
1144  times.modtime = s.count();
1145  times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
1146			 times.modtime);
1147  if (::utime(p.c_str(), &times))
1148    ec.assign(errno, std::generic_category());
1149  else
1150    ec.clear();
1151#else
1152  ec = std::make_error_code(std::errc::not_supported);
1153#endif
1154}
1155
1156void
1157fs::permissions(const path& p, perms prms)
1158{
1159  error_code ec;
1160  permissions(p, prms, ec);
1161  if (ec.value())
1162    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
1163}
1164
1165void
1166fs::permissions(const path& p, perms prms, error_code& ec) noexcept
1167{
1168  const bool add = is_set(prms, perms::add_perms);
1169  const bool remove = is_set(prms, perms::remove_perms);
1170  const bool nofollow = is_set(prms, perms::symlink_nofollow);
1171  if (add && remove)
1172    {
1173      ec = std::make_error_code(std::errc::invalid_argument);
1174      return;
1175    }
1176
1177  prms &= perms::mask;
1178
1179  file_status st;
1180  if (add || remove || nofollow)
1181    {
1182      st = nofollow ? symlink_status(p, ec) : status(p, ec);
1183      if (ec)
1184	return;
1185      auto curr = st.permissions();
1186      if (add)
1187	prms |= curr;
1188      else if (remove)
1189	prms = curr & ~prms;
1190    }
1191
1192  int err = 0;
1193#if _GLIBCXX_USE_FCHMODAT
1194  const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
1195  if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
1196    err = errno;
1197#else
1198  if (nofollow && is_symlink(st))
1199    ec = std::make_error_code(std::errc::operation_not_supported);
1200  else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
1201    err = errno;
1202#endif
1203
1204  if (err)
1205    ec.assign(err, std::generic_category());
1206  else
1207    ec.clear();
1208}
1209
1210fs::path
1211fs::read_symlink(const path& p)
1212{
1213  error_code ec;
1214  path tgt = read_symlink(p, ec);
1215  if (ec.value())
1216    _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
1217  return tgt;
1218}
1219
1220fs::path fs::read_symlink(const path& p, error_code& ec)
1221{
1222  path result;
1223#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1224  stat_type st;
1225  if (::lstat(p.c_str(), &st))
1226    {
1227      ec.assign(errno, std::generic_category());
1228      return result;
1229    }
1230  std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
1231  do
1232    {
1233      ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
1234      if (len == -1)
1235	{
1236	  ec.assign(errno, std::generic_category());
1237	  return result;
1238	}
1239      else if (len == (ssize_t)buf.size())
1240	{
1241	  if (buf.size() > 4096)
1242	    {
1243	      ec.assign(ENAMETOOLONG, std::generic_category());
1244	      return result;
1245	    }
1246	  buf.resize(buf.size() * 2);
1247	}
1248      else
1249	{
1250	  buf.resize(len);
1251	  result.assign(buf);
1252	  ec.clear();
1253	  break;
1254	}
1255    }
1256  while (true);
1257#else
1258  ec = std::make_error_code(std::errc::not_supported);
1259#endif
1260  return result;
1261}
1262
1263
1264bool
1265fs::remove(const path& p)
1266{
1267  error_code ec;
1268  bool result = fs::remove(p, ec);
1269  if (ec.value())
1270    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
1271  return result;
1272}
1273
1274bool
1275fs::remove(const path& p, error_code& ec) noexcept
1276{
1277    if (::remove(p.c_str()) == 0)
1278    {
1279      ec.clear();
1280      return true;
1281    }
1282  else if (errno == ENOENT)
1283    ec.clear();
1284  else
1285    ec.assign(errno, std::generic_category());
1286  return false;
1287}
1288
1289
1290std::uintmax_t
1291fs::remove_all(const path& p)
1292{
1293  error_code ec;
1294  const auto result = remove_all(p, ec);
1295  if (ec.value())
1296    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
1297  return result;
1298}
1299
1300std::uintmax_t
1301fs::remove_all(const path& p, error_code& ec) noexcept
1302{
1303    const auto s = symlink_status(p, ec);
1304  if (!status_known(s))
1305    return -1;
1306
1307  ec.clear();
1308  if (s.type() == file_type::not_found)
1309    return 0;
1310
1311  uintmax_t count = 0;
1312  if (s.type() == file_type::directory)
1313    {
1314      for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
1315	count += fs::remove_all(d->path(), ec);
1316      if (ec.value() == ENOENT)
1317	ec.clear();
1318      else if (ec)
1319	return -1;
1320    }
1321
1322  if (fs::remove(p, ec))
1323    ++count;
1324  return ec ? -1 : count;
1325}
1326
1327void
1328fs::rename(const path& from, const path& to)
1329{
1330  error_code ec;
1331  rename(from, to, ec);
1332  if (ec.value())
1333    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
1334}
1335
1336void
1337fs::rename(const path& from, const path& to, error_code& ec) noexcept
1338{
1339  if (::rename(from.c_str(), to.c_str()))
1340    ec.assign(errno, std::generic_category());
1341  else
1342    ec.clear();
1343}
1344
1345void
1346fs::resize_file(const path& p, uintmax_t size)
1347{
1348  error_code ec;
1349  resize_file(p, size, ec);
1350  if (ec.value())
1351    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
1352}
1353
1354void
1355fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
1356{
1357#ifdef _GLIBCXX_HAVE_UNISTD_H
1358  if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
1359    ec.assign(EINVAL, std::generic_category());
1360  else if (::truncate(p.c_str(), size))
1361    ec.assign(errno, std::generic_category());
1362  else
1363    ec.clear();
1364#else
1365  ec = std::make_error_code(std::errc::not_supported);
1366#endif
1367}
1368
1369
1370fs::space_info
1371fs::space(const path& p)
1372{
1373  error_code ec;
1374  space_info s = space(p, ec);
1375  if (ec.value())
1376    _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
1377  return s;
1378}
1379
1380fs::space_info
1381fs::space(const path& p, error_code& ec) noexcept
1382{
1383  space_info info = {
1384    static_cast<uintmax_t>(-1),
1385    static_cast<uintmax_t>(-1),
1386    static_cast<uintmax_t>(-1)
1387  };
1388#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
1389  struct ::statvfs f;
1390  if (::statvfs(p.c_str(), &f))
1391      ec.assign(errno, std::generic_category());
1392  else
1393    {
1394      uintmax_t fragment_size = f.f_frsize;
1395      info = space_info{
1396	f.f_blocks * fragment_size,
1397	f.f_bfree * fragment_size,
1398	f.f_bavail * fragment_size
1399      };
1400      ec.clear();
1401    }
1402#else
1403  ec = std::make_error_code(std::errc::not_supported);
1404#endif
1405  return info;
1406}
1407
1408#ifdef _GLIBCXX_HAVE_SYS_STAT_H
1409fs::file_status
1410fs::status(const fs::path& p, error_code& ec) noexcept
1411{
1412  file_status status;
1413  stat_type st;
1414  if (::stat(p.c_str(), &st))
1415    {
1416      int err = errno;
1417      ec.assign(err, std::generic_category());
1418      if (is_not_found_errno(err))
1419	status.type(file_type::not_found);
1420#ifdef EOVERFLOW
1421      else if (err == EOVERFLOW)
1422	status.type(file_type::unknown);
1423#endif
1424    }
1425  else
1426    {
1427      status = make_file_status(st);
1428      ec.clear();
1429    }
1430  return status;
1431}
1432
1433fs::file_status
1434fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
1435{
1436  file_status status;
1437  stat_type st;
1438  if (::lstat(p.c_str(), &st))
1439    {
1440      int err = errno;
1441      ec.assign(err, std::generic_category());
1442      if (is_not_found_errno(err))
1443	status.type(file_type::not_found);
1444    }
1445  else
1446    {
1447      status = make_file_status(st);
1448      ec.clear();
1449    }
1450  return status;
1451}
1452#endif
1453
1454fs::file_status
1455fs::status(const fs::path& p)
1456{
1457  std::error_code ec;
1458  auto result = status(p, ec);
1459  if (result.type() == file_type::none)
1460    _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
1461  return result;
1462}
1463
1464fs::file_status
1465fs::symlink_status(const fs::path& p)
1466{
1467  std::error_code ec;
1468  auto result = symlink_status(p, ec);
1469  if (result.type() == file_type::none)
1470    _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
1471  return result;
1472}
1473
1474fs::path
1475fs::system_complete(const path& p)
1476{
1477  error_code ec;
1478  path comp = system_complete(p, ec);
1479  if (ec.value())
1480    _GLIBCXX_THROW_OR_ABORT(filesystem_error("system_complete", p, ec));
1481  return comp;
1482}
1483
1484fs::path
1485fs::system_complete(const path& p, error_code& ec)
1486{
1487  path base = current_path(ec);
1488#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1489  if (p.is_absolute() || !p.has_root_name()
1490      || p.root_name() == base.root_name())
1491    return absolute(p, base);
1492  // else TODO
1493  ec = std::make_error_code(std::errc::not_supported);
1494  return {};
1495#else
1496  if (ec.value())
1497    return {};
1498  return absolute(p, base);
1499#endif
1500}
1501
1502fs::path fs::temp_directory_path()
1503{
1504  error_code ec;
1505  path tmp = temp_directory_path(ec);
1506  if (ec.value())
1507    _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
1508  return tmp;
1509}
1510
1511fs::path fs::temp_directory_path(error_code& ec)
1512{
1513#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1514  ec = std::make_error_code(std::errc::not_supported);
1515  return {}; // TODO
1516#else
1517  const char* tmpdir = nullptr;
1518  const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
1519  for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
1520    tmpdir = ::getenv(*e);
1521  path p = tmpdir ? tmpdir : "/tmp";
1522  auto st = status(p, ec);
1523  if (!ec)
1524    {
1525      if (is_directory(st))
1526	{
1527	  ec.clear();
1528	  return p;
1529	}
1530      else
1531	ec = std::make_error_code(std::errc::not_a_directory);
1532    }
1533  return {};
1534#endif
1535}
1536
1537