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