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