Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libcxx/src/filesystem/operations.cpp
35231 views
1
//===----------------------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include <__assert>
10
#include <__config>
11
#include <__utility/unreachable.h>
12
#include <array>
13
#include <climits>
14
#include <cstdlib>
15
#include <filesystem>
16
#include <iterator>
17
#include <string_view>
18
#include <type_traits>
19
#include <vector>
20
21
#include "error.h"
22
#include "file_descriptor.h"
23
#include "path_parser.h"
24
#include "posix_compat.h"
25
#include "time_utils.h"
26
27
#if defined(_LIBCPP_WIN32API)
28
# define WIN32_LEAN_AND_MEAN
29
# define NOMINMAX
30
# include <windows.h>
31
#else
32
# include <dirent.h>
33
# include <sys/stat.h>
34
# include <sys/statvfs.h>
35
# include <unistd.h>
36
#endif
37
#include <fcntl.h> /* values for fchmodat */
38
#include <time.h>
39
40
#if __has_include(<sys/sendfile.h>)
41
# include <sys/sendfile.h>
42
# define _LIBCPP_FILESYSTEM_USE_SENDFILE
43
#elif defined(__APPLE__) || __has_include(<copyfile.h>)
44
# include <copyfile.h>
45
# define _LIBCPP_FILESYSTEM_USE_COPYFILE
46
#else
47
# include <fstream>
48
# define _LIBCPP_FILESYSTEM_USE_FSTREAM
49
#endif
50
51
#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
52
# pragma comment(lib, "rt")
53
#endif
54
55
_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
56
57
using detail::capture_errno;
58
using detail::ErrorHandler;
59
using detail::StatT;
60
using detail::TimeSpec;
61
using parser::createView;
62
using parser::PathParser;
63
using parser::string_view_t;
64
65
static path __do_absolute(const path& p, path* cwd, error_code* ec) {
66
if (ec)
67
ec->clear();
68
if (p.is_absolute())
69
return p;
70
*cwd = __current_path(ec);
71
if (ec && *ec)
72
return {};
73
return (*cwd) / p;
74
}
75
76
path __absolute(const path& p, error_code* ec) {
77
path cwd;
78
return __do_absolute(p, &cwd, ec);
79
}
80
81
path __canonical(path const& orig_p, error_code* ec) {
82
path cwd;
83
ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
84
85
path p = __do_absolute(orig_p, &cwd, ec);
86
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
87
std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free);
88
if (hold.get() == nullptr)
89
return err.report(capture_errno());
90
return {hold.get()};
91
#else
92
# if defined(__MVS__) && !defined(PATH_MAX)
93
path::value_type buff[_XOPEN_PATH_MAX + 1];
94
# else
95
path::value_type buff[PATH_MAX + 1];
96
# endif
97
path::value_type* ret;
98
if ((ret = detail::realpath(p.c_str(), buff)) == nullptr)
99
return err.report(capture_errno());
100
return {ret};
101
#endif
102
}
103
104
void __copy(const path& from, const path& to, copy_options options, error_code* ec) {
105
ErrorHandler<void> err("copy", ec, &from, &to);
106
107
const bool sym_status = bool(options & (copy_options::create_symlinks | copy_options::skip_symlinks));
108
109
const bool sym_status2 = bool(options & copy_options::copy_symlinks);
110
111
error_code m_ec1;
112
StatT f_st;
113
const file_status f =
114
sym_status || sym_status2 ? detail::posix_lstat(from, f_st, &m_ec1) : detail::posix_stat(from, f_st, &m_ec1);
115
if (m_ec1)
116
return err.report(m_ec1);
117
118
StatT t_st;
119
const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) : detail::posix_stat(to, t_st, &m_ec1);
120
121
if (not status_known(t))
122
return err.report(m_ec1);
123
124
if (!exists(f) || is_other(f) || is_other(t) || (is_directory(f) && is_regular_file(t)) ||
125
(exists(t) && detail::stat_equivalent(f_st, t_st))) {
126
return err.report(errc::function_not_supported);
127
}
128
129
if (is_symlink(f)) {
130
if (bool(copy_options::skip_symlinks & options)) {
131
// do nothing
132
} else if (not exists(t)) {
133
__copy_symlink(from, to, ec);
134
} else {
135
return err.report(errc::file_exists);
136
}
137
return;
138
} else if (is_regular_file(f)) {
139
if (bool(copy_options::directories_only & options)) {
140
// do nothing
141
} else if (bool(copy_options::create_symlinks & options)) {
142
__create_symlink(from, to, ec);
143
} else if (bool(copy_options::create_hard_links & options)) {
144
__create_hard_link(from, to, ec);
145
} else if (is_directory(t)) {
146
__copy_file(from, to / from.filename(), options, ec);
147
} else {
148
__copy_file(from, to, options, ec);
149
}
150
return;
151
} else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
152
return err.report(errc::is_a_directory);
153
} else if (is_directory(f) && (bool(copy_options::recursive & options) || copy_options::none == options)) {
154
if (!exists(t)) {
155
// create directory to with attributes from 'from'.
156
__create_directory(to, from, ec);
157
if (ec && *ec) {
158
return;
159
}
160
}
161
directory_iterator it = ec ? directory_iterator(from, *ec) : directory_iterator(from);
162
if (ec && *ec) {
163
return;
164
}
165
error_code m_ec2;
166
for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) {
167
__copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec);
168
if (ec && *ec) {
169
return;
170
}
171
}
172
if (m_ec2) {
173
return err.report(m_ec2);
174
}
175
}
176
}
177
178
namespace detail {
179
namespace {
180
181
#if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
182
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
183
size_t count = read_fd.get_stat().st_size;
184
do {
185
ssize_t res;
186
if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
187
ec = capture_errno();
188
return false;
189
}
190
count -= res;
191
} while (count > 0);
192
193
ec.clear();
194
195
return true;
196
}
197
#elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
198
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
199
struct CopyFileState {
200
copyfile_state_t state;
201
CopyFileState() { state = copyfile_state_alloc(); }
202
~CopyFileState() { copyfile_state_free(state); }
203
204
private:
205
CopyFileState(CopyFileState const&) = delete;
206
CopyFileState& operator=(CopyFileState const&) = delete;
207
};
208
209
CopyFileState cfs;
210
if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
211
ec = capture_errno();
212
return false;
213
}
214
215
ec.clear();
216
return true;
217
}
218
#elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
219
bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
220
ifstream in;
221
in.__open(read_fd.fd, ios::binary);
222
if (!in.is_open()) {
223
// This assumes that __open didn't reset the error code.
224
ec = capture_errno();
225
return false;
226
}
227
read_fd.fd = -1;
228
ofstream out;
229
out.__open(write_fd.fd, ios::binary);
230
if (!out.is_open()) {
231
ec = capture_errno();
232
return false;
233
}
234
write_fd.fd = -1;
235
236
if (in.good() && out.good()) {
237
using InIt = istreambuf_iterator<char>;
238
using OutIt = ostreambuf_iterator<char>;
239
InIt bin(in);
240
InIt ein;
241
OutIt bout(out);
242
copy(bin, ein, bout);
243
}
244
if (out.fail() || in.fail()) {
245
ec = make_error_code(errc::io_error);
246
return false;
247
}
248
249
ec.clear();
250
return true;
251
}
252
#else
253
# error "Unknown implementation for copy_file_impl"
254
#endif // copy_file_impl implementation
255
256
} // end anonymous namespace
257
} // end namespace detail
258
259
bool __copy_file(const path& from, const path& to, copy_options options, error_code* ec) {
260
using detail::FileDescriptor;
261
ErrorHandler<bool> err("copy_file", ec, &to, &from);
262
263
error_code m_ec;
264
FileDescriptor from_fd = FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY);
265
if (m_ec)
266
return err.report(m_ec);
267
268
auto from_st = from_fd.get_status();
269
StatT const& from_stat = from_fd.get_stat();
270
if (!is_regular_file(from_st)) {
271
if (not m_ec)
272
m_ec = make_error_code(errc::not_supported);
273
return err.report(m_ec);
274
}
275
276
const bool skip_existing = bool(copy_options::skip_existing & options);
277
const bool update_existing = bool(copy_options::update_existing & options);
278
const bool overwrite_existing = bool(copy_options::overwrite_existing & options);
279
280
StatT to_stat_path;
281
file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
282
if (!status_known(to_st))
283
return err.report(m_ec);
284
285
const bool to_exists = exists(to_st);
286
if (to_exists && !is_regular_file(to_st))
287
return err.report(errc::not_supported);
288
289
if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
290
return err.report(errc::file_exists);
291
292
if (to_exists && skip_existing)
293
return false;
294
295
bool ShouldCopy = [&]() {
296
if (to_exists && update_existing) {
297
auto from_time = detail::extract_mtime(from_stat);
298
auto to_time = detail::extract_mtime(to_stat_path);
299
if (from_time.tv_sec < to_time.tv_sec)
300
return false;
301
if (from_time.tv_sec == to_time.tv_sec && from_time.tv_nsec <= to_time.tv_nsec)
302
return false;
303
return true;
304
}
305
if (!to_exists || overwrite_existing)
306
return true;
307
return err.report(errc::file_exists);
308
}();
309
if (!ShouldCopy)
310
return false;
311
312
// Don't truncate right away. We may not be opening the file we originally
313
// looked at; we'll check this later.
314
int to_open_flags = O_WRONLY | O_BINARY;
315
if (!to_exists)
316
to_open_flags |= O_CREAT;
317
FileDescriptor to_fd = FileDescriptor::create_with_status(&to, m_ec, to_open_flags, from_stat.st_mode);
318
if (m_ec)
319
return err.report(m_ec);
320
321
if (to_exists) {
322
// Check that the file we initially stat'ed is equivalent to the one
323
// we opened.
324
// FIXME: report this better.
325
if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
326
return err.report(errc::bad_file_descriptor);
327
328
// Set the permissions and truncate the file we opened.
329
if (detail::posix_fchmod(to_fd, from_stat, m_ec))
330
return err.report(m_ec);
331
if (detail::posix_ftruncate(to_fd, 0, m_ec))
332
return err.report(m_ec);
333
}
334
335
if (!detail::copy_file_impl(from_fd, to_fd, m_ec)) {
336
// FIXME: Remove the dest file if we failed, and it didn't exist previously.
337
return err.report(m_ec);
338
}
339
340
return true;
341
}
342
343
void __copy_symlink(const path& existing_symlink, const path& new_symlink, error_code* ec) {
344
const path real_path(__read_symlink(existing_symlink, ec));
345
if (ec && *ec) {
346
return;
347
}
348
#if defined(_LIBCPP_WIN32API)
349
error_code local_ec;
350
if (is_directory(real_path, local_ec))
351
__create_directory_symlink(real_path, new_symlink, ec);
352
else
353
#endif
354
__create_symlink(real_path, new_symlink, ec);
355
}
356
357
bool __create_directories(const path& p, error_code* ec) {
358
ErrorHandler<bool> err("create_directories", ec, &p);
359
360
error_code m_ec;
361
auto const st = detail::posix_stat(p, &m_ec);
362
if (!status_known(st))
363
return err.report(m_ec);
364
else if (is_directory(st))
365
return false;
366
else if (exists(st))
367
return err.report(errc::file_exists);
368
369
const path parent = p.parent_path();
370
if (!parent.empty()) {
371
const file_status parent_st = status(parent, m_ec);
372
if (not status_known(parent_st))
373
return err.report(m_ec);
374
if (not exists(parent_st)) {
375
if (parent == p)
376
return err.report(errc::invalid_argument);
377
__create_directories(parent, ec);
378
if (ec && *ec) {
379
return false;
380
}
381
} else if (not is_directory(parent_st))
382
return err.report(errc::not_a_directory);
383
}
384
bool ret = __create_directory(p, &m_ec);
385
if (m_ec)
386
return err.report(m_ec);
387
return ret;
388
}
389
390
bool __create_directory(const path& p, error_code* ec) {
391
ErrorHandler<bool> err("create_directory", ec, &p);
392
393
if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
394
return true;
395
396
if (errno != EEXIST)
397
return err.report(capture_errno());
398
error_code mec = capture_errno();
399
error_code ignored_ec;
400
const file_status st = status(p, ignored_ec);
401
if (!is_directory(st))
402
return err.report(mec);
403
return false;
404
}
405
406
bool __create_directory(path const& p, path const& attributes, error_code* ec) {
407
ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
408
409
StatT attr_stat;
410
error_code mec;
411
file_status st = detail::posix_stat(attributes, attr_stat, &mec);
412
if (!status_known(st))
413
return err.report(mec);
414
if (!is_directory(st))
415
return err.report(errc::not_a_directory, "the specified attribute path is invalid");
416
417
if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0)
418
return true;
419
420
if (errno != EEXIST)
421
return err.report(capture_errno());
422
423
mec = capture_errno();
424
error_code ignored_ec;
425
st = status(p, ignored_ec);
426
if (!is_directory(st))
427
return err.report(mec);
428
return false;
429
}
430
431
void __create_directory_symlink(path const& from, path const& to, error_code* ec) {
432
ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
433
if (detail::symlink_dir(from.c_str(), to.c_str()) == -1)
434
return err.report(capture_errno());
435
}
436
437
void __create_hard_link(const path& from, const path& to, error_code* ec) {
438
ErrorHandler<void> err("create_hard_link", ec, &from, &to);
439
if (detail::link(from.c_str(), to.c_str()) == -1)
440
return err.report(capture_errno());
441
}
442
443
void __create_symlink(path const& from, path const& to, error_code* ec) {
444
ErrorHandler<void> err("create_symlink", ec, &from, &to);
445
if (detail::symlink_file(from.c_str(), to.c_str()) == -1)
446
return err.report(capture_errno());
447
}
448
449
path __current_path(error_code* ec) {
450
ErrorHandler<path> err("current_path", ec);
451
452
#if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__)
453
// Common extension outside of POSIX getcwd() spec, without needing to
454
// preallocate a buffer. Also supported by a number of other POSIX libcs.
455
int size = 0;
456
path::value_type* ptr = nullptr;
457
typedef decltype(&::free) Deleter;
458
Deleter deleter = &::free;
459
#else
460
errno = 0; // Note: POSIX mandates that modifying `errno` is thread-safe.
461
auto size = ::pathconf(".", _PC_PATH_MAX);
462
if (size == -1) {
463
if (errno != 0) {
464
return err.report(capture_errno(), "call to pathconf failed");
465
466
// `pathconf` returns `-1` without an error to indicate no limit.
467
} else {
468
# if defined(__MVS__) && !defined(PATH_MAX)
469
size = _XOPEN_PATH_MAX + 1;
470
# else
471
size = PATH_MAX + 1;
472
# endif
473
}
474
}
475
476
auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]);
477
path::value_type* ptr = buff.get();
478
479
// Preallocated buffer, don't free the buffer in the second unique_ptr
480
// below.
481
struct Deleter {
482
void operator()(void*) const {}
483
};
484
Deleter deleter;
485
#endif
486
487
unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter);
488
if (hold.get() == nullptr)
489
return err.report(capture_errno(), "call to getcwd failed");
490
491
return {hold.get()};
492
}
493
494
void __current_path(const path& p, error_code* ec) {
495
ErrorHandler<void> err("current_path", ec, &p);
496
if (detail::chdir(p.c_str()) == -1)
497
err.report(capture_errno());
498
}
499
500
bool __equivalent(const path& p1, const path& p2, error_code* ec) {
501
ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
502
503
error_code ec1, ec2;
504
StatT st1 = {}, st2 = {};
505
auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
506
if (!exists(s1))
507
return err.report(errc::not_supported);
508
auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
509
if (!exists(s2))
510
return err.report(errc::not_supported);
511
512
return detail::stat_equivalent(st1, st2);
513
}
514
515
uintmax_t __file_size(const path& p, error_code* ec) {
516
ErrorHandler<uintmax_t> err("file_size", ec, &p);
517
518
error_code m_ec;
519
StatT st;
520
file_status fst = detail::posix_stat(p, st, &m_ec);
521
if (!exists(fst) || !is_regular_file(fst)) {
522
errc error_kind = is_directory(fst) ? errc::is_a_directory : errc::not_supported;
523
if (!m_ec)
524
m_ec = make_error_code(error_kind);
525
return err.report(m_ec);
526
}
527
// is_regular_file(p) == true
528
return static_cast<uintmax_t>(st.st_size);
529
}
530
531
uintmax_t __hard_link_count(const path& p, error_code* ec) {
532
ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
533
534
error_code m_ec;
535
StatT st;
536
detail::posix_stat(p, st, &m_ec);
537
if (m_ec)
538
return err.report(m_ec);
539
return static_cast<uintmax_t>(st.st_nlink);
540
}
541
542
bool __fs_is_empty(const path& p, error_code* ec) {
543
ErrorHandler<bool> err("is_empty", ec, &p);
544
545
error_code m_ec;
546
StatT pst;
547
auto st = detail::posix_stat(p, pst, &m_ec);
548
if (m_ec)
549
return err.report(m_ec);
550
else if (!is_directory(st) && !is_regular_file(st))
551
return err.report(errc::not_supported);
552
else if (is_directory(st)) {
553
auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
554
if (ec && *ec)
555
return false;
556
return it == directory_iterator{};
557
} else if (is_regular_file(st))
558
return static_cast<uintmax_t>(pst.st_size) == 0;
559
560
__libcpp_unreachable();
561
}
562
563
file_time_type __last_write_time(const path& p, error_code* ec) {
564
using namespace chrono;
565
ErrorHandler<file_time_type> err("last_write_time", ec, &p);
566
567
error_code m_ec;
568
StatT st;
569
detail::posix_stat(p, st, &m_ec);
570
if (m_ec)
571
return err.report(m_ec);
572
return detail::__extract_last_write_time(p, st, ec);
573
}
574
575
void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
576
using detail::fs_time;
577
ErrorHandler<void> err("last_write_time", ec, &p);
578
579
#if defined(_LIBCPP_WIN32API)
580
TimeSpec ts;
581
if (!fs_time::convert_to_timespec(ts, new_time))
582
return err.report(errc::value_too_large);
583
detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0);
584
if (!h)
585
return err.report(detail::make_windows_error(GetLastError()));
586
FILETIME last_write = timespec_to_filetime(ts);
587
if (!SetFileTime(h, nullptr, nullptr, &last_write))
588
return err.report(detail::make_windows_error(GetLastError()));
589
#else
590
error_code m_ec;
591
array<TimeSpec, 2> tbuf;
592
# if !defined(_LIBCPP_USE_UTIMENSAT)
593
// This implementation has a race condition between determining the
594
// last access time and attempting to set it to the same value using
595
// ::utimes
596
StatT st;
597
file_status fst = detail::posix_stat(p, st, &m_ec);
598
if (m_ec)
599
return err.report(m_ec);
600
tbuf[0] = detail::extract_atime(st);
601
# else
602
tbuf[0].tv_sec = 0;
603
tbuf[0].tv_nsec = UTIME_OMIT;
604
# endif
605
if (!fs_time::convert_to_timespec(tbuf[1], new_time))
606
return err.report(errc::value_too_large);
607
608
detail::set_file_times(p, tbuf, m_ec);
609
if (m_ec)
610
return err.report(m_ec);
611
#endif
612
}
613
614
void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) {
615
ErrorHandler<void> err("permissions", ec, &p);
616
617
auto has_opt = [&](perm_options o) { return bool(o & opts); };
618
const bool resolve_symlinks = !has_opt(perm_options::nofollow);
619
const bool add_perms = has_opt(perm_options::add);
620
const bool remove_perms = has_opt(perm_options::remove);
621
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
622
(add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
623
"One and only one of the perm_options constants 'replace', 'add', or 'remove' must be present in opts");
624
625
bool set_sym_perms = false;
626
prms &= perms::mask;
627
if (!resolve_symlinks || (add_perms || remove_perms)) {
628
error_code m_ec;
629
file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec) : detail::posix_lstat(p, &m_ec);
630
set_sym_perms = is_symlink(st);
631
if (m_ec)
632
return err.report(m_ec);
633
// TODO(hardening): double-check this assertion -- it might be a valid (if rare) case when the permissions are
634
// unknown.
635
_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(st.permissions() != perms::unknown, "Permissions unexpectedly unknown");
636
if (add_perms)
637
prms |= st.permissions();
638
else if (remove_perms)
639
prms = st.permissions() & ~prms;
640
}
641
const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask);
642
643
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
644
const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
645
if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
646
return err.report(capture_errno());
647
}
648
#else
649
if (set_sym_perms)
650
return err.report(errc::operation_not_supported);
651
if (::chmod(p.c_str(), real_perms) == -1) {
652
return err.report(capture_errno());
653
}
654
#endif
655
}
656
657
path __read_symlink(const path& p, error_code* ec) {
658
ErrorHandler<path> err("read_symlink", ec, &p);
659
660
#if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE)
661
struct NullDeleter {
662
void operator()(void*) const {}
663
};
664
# ifdef MAX_SYMLINK_SIZE
665
const size_t size = MAX_SYMLINK_SIZE + 1;
666
# else
667
const size_t size = PATH_MAX + 1;
668
# endif
669
path::value_type stack_buff[size];
670
auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff);
671
#else
672
StatT sb;
673
if (detail::lstat(p.c_str(), &sb) == -1) {
674
return err.report(capture_errno());
675
}
676
const size_t size = sb.st_size + 1;
677
auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]);
678
#endif
679
detail::SSizeT ret;
680
if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1)
681
return err.report(capture_errno());
682
// Note that `ret` returning `0` would work, resulting in a valid empty string being returned.
683
if (static_cast<size_t>(ret) >= size)
684
return err.report(errc::value_too_large);
685
buff[ret] = 0;
686
return {buff.get()};
687
}
688
689
bool __remove(const path& p, error_code* ec) {
690
ErrorHandler<bool> err("remove", ec, &p);
691
if (detail::remove(p.c_str()) == -1) {
692
if (errno != ENOENT)
693
err.report(capture_errno());
694
return false;
695
}
696
return true;
697
}
698
699
// We currently have two implementations of `__remove_all`. The first one is general and
700
// used on platforms where we don't have access to the `openat()` family of POSIX functions.
701
// That implementation uses `directory_iterator`, however it is vulnerable to some race
702
// conditions, see https://reviews.llvm.org/D118134 for details.
703
//
704
// The second implementation is used on platforms where `openat()` & friends are available,
705
// and it threads file descriptors through recursive calls to avoid such race conditions.
706
#if defined(_LIBCPP_WIN32API) || defined(__MVS__)
707
# define REMOVE_ALL_USE_DIRECTORY_ITERATOR
708
#endif
709
710
#if defined(REMOVE_ALL_USE_DIRECTORY_ITERATOR)
711
712
namespace {
713
714
uintmax_t remove_all_impl(path const& p, error_code& ec) {
715
const auto npos = static_cast<uintmax_t>(-1);
716
const file_status st = __symlink_status(p, &ec);
717
if (ec)
718
return npos;
719
uintmax_t count = 1;
720
if (is_directory(st)) {
721
for (directory_iterator it(p, ec); !ec && it != directory_iterator(); it.increment(ec)) {
722
auto other_count = remove_all_impl(it->path(), ec);
723
if (ec)
724
return npos;
725
count += other_count;
726
}
727
if (ec)
728
return npos;
729
}
730
if (!__remove(p, &ec))
731
return npos;
732
return count;
733
}
734
735
} // end namespace
736
737
uintmax_t __remove_all(const path& p, error_code* ec) {
738
ErrorHandler<uintmax_t> err("remove_all", ec, &p);
739
740
error_code mec;
741
auto count = remove_all_impl(p, mec);
742
if (mec) {
743
if (mec == errc::no_such_file_or_directory)
744
return 0;
745
return err.report(mec);
746
}
747
return count;
748
}
749
750
#else // !REMOVE_ALL_USE_DIRECTORY_ITERATOR
751
752
namespace {
753
754
template <class Cleanup>
755
struct scope_exit {
756
explicit scope_exit(Cleanup const& cleanup) : cleanup_(cleanup) {}
757
758
~scope_exit() { cleanup_(); }
759
760
private:
761
Cleanup cleanup_;
762
};
763
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scope_exit);
764
765
uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) {
766
// First, try to open the path as a directory.
767
const int options = O_CLOEXEC | O_RDONLY | O_DIRECTORY | O_NOFOLLOW;
768
int fd = ::openat(parent_directory, p.c_str(), options);
769
if (fd != -1) {
770
// If that worked, iterate over the contents of the directory and
771
// remove everything in it, recursively.
772
DIR* stream = ::fdopendir(fd);
773
if (stream == nullptr) {
774
::close(fd);
775
ec = detail::capture_errno();
776
return 0;
777
}
778
// Note: `::closedir` will also close the associated file descriptor, so
779
// there should be no call to `close(fd)`.
780
scope_exit close_stream([=] { ::closedir(stream); });
781
782
uintmax_t count = 0;
783
while (true) {
784
auto [str, type] = detail::posix_readdir(stream, ec);
785
static_assert(std::is_same_v<decltype(str), std::string_view>);
786
if (str == "." || str == "..") {
787
continue;
788
} else if (ec || str.empty()) {
789
break; // we're done iterating through the directory
790
} else {
791
count += remove_all_impl(fd, str, ec);
792
}
793
}
794
795
// Then, remove the now-empty directory itself.
796
if (::unlinkat(parent_directory, p.c_str(), AT_REMOVEDIR) == -1) {
797
ec = detail::capture_errno();
798
return count;
799
}
800
801
return count + 1; // the contents of the directory + the directory itself
802
}
803
804
ec = detail::capture_errno();
805
806
// If we failed to open `p` because it didn't exist, it's not an
807
// error -- it might have moved or have been deleted already.
808
if (ec == errc::no_such_file_or_directory) {
809
ec.clear();
810
return 0;
811
}
812
813
// If opening `p` failed because it wasn't a directory, remove it as
814
// a normal file instead. Note that `openat()` can return either ENOTDIR
815
// or ELOOP depending on the exact reason of the failure. On FreeBSD it
816
// may return EMLINK instead of ELOOP, contradicting POSIX.
817
if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) {
818
ec.clear();
819
if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) {
820
ec = detail::capture_errno();
821
return 0;
822
}
823
return 1;
824
}
825
826
// Otherwise, it's a real error -- we don't remove anything.
827
return 0;
828
}
829
830
} // end namespace
831
832
uintmax_t __remove_all(const path& p, error_code* ec) {
833
ErrorHandler<uintmax_t> err("remove_all", ec, &p);
834
error_code mec;
835
uintmax_t count = remove_all_impl(AT_FDCWD, p, mec);
836
if (mec)
837
return err.report(mec);
838
return count;
839
}
840
841
#endif // REMOVE_ALL_USE_DIRECTORY_ITERATOR
842
843
void __rename(const path& from, const path& to, error_code* ec) {
844
ErrorHandler<void> err("rename", ec, &from, &to);
845
if (detail::rename(from.c_str(), to.c_str()) == -1)
846
err.report(capture_errno());
847
}
848
849
void __resize_file(const path& p, uintmax_t size, error_code* ec) {
850
ErrorHandler<void> err("resize_file", ec, &p);
851
if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
852
return err.report(capture_errno());
853
}
854
855
space_info __space(const path& p, error_code* ec) {
856
ErrorHandler<void> err("space", ec, &p);
857
space_info si;
858
detail::StatVFS m_svfs = {};
859
if (detail::statvfs(p.c_str(), &m_svfs) == -1) {
860
err.report(capture_errno());
861
si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
862
return si;
863
}
864
// Multiply with overflow checking.
865
auto do_mult = [&](uintmax_t& out, uintmax_t other) {
866
out = other * m_svfs.f_frsize;
867
if (other == 0 || out / other != m_svfs.f_frsize)
868
out = static_cast<uintmax_t>(-1);
869
};
870
do_mult(si.capacity, m_svfs.f_blocks);
871
do_mult(si.free, m_svfs.f_bfree);
872
do_mult(si.available, m_svfs.f_bavail);
873
return si;
874
}
875
876
file_status __status(const path& p, error_code* ec) { return detail::posix_stat(p, ec); }
877
878
file_status __symlink_status(const path& p, error_code* ec) { return detail::posix_lstat(p, ec); }
879
880
path __temp_directory_path(error_code* ec) {
881
ErrorHandler<path> err("temp_directory_path", ec);
882
883
#if defined(_LIBCPP_WIN32API)
884
wchar_t buf[MAX_PATH];
885
DWORD retval = GetTempPathW(MAX_PATH, buf);
886
if (!retval)
887
return err.report(detail::make_windows_error(GetLastError()));
888
if (retval > MAX_PATH)
889
return err.report(errc::filename_too_long);
890
// GetTempPathW returns a path with a trailing slash, which we
891
// shouldn't include for consistency.
892
if (buf[retval - 1] == L'\\')
893
buf[retval - 1] = L'\0';
894
path p(buf);
895
#else
896
const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
897
const char* ret = nullptr;
898
899
for (auto& ep : env_paths)
900
if ((ret = getenv(ep)))
901
break;
902
if (ret == nullptr) {
903
# if defined(__ANDROID__)
904
ret = "/data/local/tmp";
905
# else
906
ret = "/tmp";
907
# endif
908
}
909
910
path p(ret);
911
#endif
912
error_code m_ec;
913
file_status st = detail::posix_stat(p, &m_ec);
914
if (!status_known(st))
915
return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str());
916
917
if (!exists(st) || !is_directory(st))
918
return err.report(errc::not_a_directory, "path " PATH_CSTR_FMT " is not a directory", p.c_str());
919
920
return p;
921
}
922
923
path __weakly_canonical(const path& p, error_code* ec) {
924
ErrorHandler<path> err("weakly_canonical", ec, &p);
925
926
if (p.empty())
927
return __canonical("", ec);
928
929
path result;
930
path tmp;
931
tmp.__reserve(p.native().size());
932
auto PP = PathParser::CreateEnd(p.native());
933
--PP;
934
vector<string_view_t> DNEParts;
935
936
error_code m_ec;
937
while (PP.State_ != PathParser::PS_BeforeBegin) {
938
tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
939
file_status st = __status(tmp, &m_ec);
940
if (!status_known(st)) {
941
return err.report(m_ec);
942
} else if (exists(st)) {
943
result = __canonical(tmp, &m_ec);
944
if (m_ec) {
945
return err.report(m_ec);
946
}
947
break;
948
}
949
DNEParts.push_back(*PP);
950
--PP;
951
}
952
if (PP.State_ == PathParser::PS_BeforeBegin) {
953
result = __canonical("", &m_ec);
954
if (m_ec) {
955
return err.report(m_ec);
956
}
957
}
958
if (DNEParts.empty())
959
return result;
960
for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
961
result /= *It;
962
return result.lexically_normal();
963
}
964
965
_LIBCPP_END_NAMESPACE_FILESYSTEM
966
967