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(), ×))
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