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