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