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