xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/src/filesystem/ops.cc (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
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 
65 namespace fs = std::experimental::filesystem;
66 
67 fs::path
68 fs::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 
89 namespace
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 
117 fs::path
118 fs::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 
212 fs::path
213 fs::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 
221 fs::path
222 fs::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 
232 void
233 fs::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 
241 namespace
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
251 namespace
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 
512 void
513 fs::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 
613 bool
614 fs::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 
624 bool
625 fs::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 
637 void
638 fs::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 
647 void
648 fs::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 
665 bool
666 fs::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 
676 bool
677 fs::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 
712 namespace
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 
740 bool
741 fs::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 
751 bool
752 fs::create_directory(const path& p, error_code& ec) noexcept
753 {
754   return create_dir(p, perms::all, ec);
755 }
756 
757 
758 bool
759 fs::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 
769 bool
770 fs::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 
788 void
789 fs::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 
798 void
799 fs::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 
810 void
811 fs::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 
820 void
821 fs::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 
834 void
835 fs::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 
844 void
845 fs::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 
859 fs::path
860 fs::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 
869 fs::path
870 fs::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 
920 void
921 fs::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 
929 void
930 fs::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 
942 bool
943 fs::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 
953 bool
954 fs::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 
999 std::uintmax_t
1000 fs::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 
1009 namespace
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 
1031 std::uintmax_t
1032 fs::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 
1054 std::uintmax_t
1055 fs::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 
1064 std::uintmax_t
1065 fs::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 
1071 bool
1072 fs::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 
1082 bool
1083 fs::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 
1094 fs::file_time_type
1095 fs::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 
1104 fs::file_time_type
1105 fs::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 
1111 void
1112 fs::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 
1120 void
1121 fs::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 
1156 void
1157 fs::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 
1165 void
1166 fs::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 
1210 fs::path
1211 fs::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 
1220 fs::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 
1264 bool
1265 fs::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 
1274 bool
1275 fs::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 
1290 std::uintmax_t
1291 fs::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 
1300 std::uintmax_t
1301 fs::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 
1327 void
1328 fs::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 
1336 void
1337 fs::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 
1345 void
1346 fs::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 
1354 void
1355 fs::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 
1370 fs::space_info
1371 fs::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 
1380 fs::space_info
1381 fs::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
1409 fs::file_status
1410 fs::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 
1433 fs::file_status
1434 fs::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 
1454 fs::file_status
1455 fs::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 
1464 fs::file_status
1465 fs::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 
1474 fs::path
1475 fs::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 
1484 fs::path
1485 fs::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 
1502 fs::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 
1511 fs::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