diff options
author | Rodrigo Salazar <4rodrigosalazar@gmail.com> | 2024-06-12 09:11:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-12 12:11:57 -0400 |
commit | 11399028ba2d74de770f46e7044ee0f008b01778 (patch) | |
tree | 4e25883c4f9a5fbd31900556582e544a3c6bcf40 /libcxx/src/filesystem/operations.cpp | |
parent | bce2498767d15724c1fbba8606f684f621a0a897 (diff) | |
download | llvm-11399028ba2d74de770f46e7044ee0f008b01778.zip llvm-11399028ba2d74de770f46e7044ee0f008b01778.tar.gz llvm-11399028ba2d74de770f46e7044ee0f008b01778.tar.bz2 |
[libcxx] Correct and clean-up filesystem operations error_code paths (#88341)
3 error_code related cleanups/corrections in the std::filesystem
operations functions.
1. In `__copy`, the `ec->clear()` is unnecessary as `ErrorHandler` at
the start of each function clears the error_code as part of its
initialization.
2. In `__copy`, in the recursive codepath we are not checking the
error_code result of `it.increment(m_ec2)` immediately after use in the
for loop condition (and we aren't checking it after the final increment
when we don't enter the loop).
3. In `__weakly_canonical`, it makes calls to `__canonical` (which
internally uses OS APIs implementing POSIX `realpath`) and we are not
checking the error code result from the `__canonical` call. Both
`weakly_canonical` and `canonical` are supposed to set the error_code
when underlying OS APIs result in an error
(https://eel.is/c++draft/fs.err.report#3.1). With this change we
propagate up the error_code from `__canonical` caused by any underlying
OS API failure up to the `__weakly_canonical`. Essentially, if
`__canonical` thinks an error code should be set, then
`__weakly_canonical` must as well. Before this change it would be
throwing an exception in the non-error_code form of the function when
`__canonical` fails, while not setting the error code in the error_code
form of the function (an inconsistency).
Added a little coverage in weakly_canonical.pass.cpp for the error_code
forms of the API that was missing. Though I am lacking utilities in
libcxx testing to add granular testing of the failure scenarios (like
forcing realpath to fail for a given path, as it could if you had
something like a flaky remote filesystem).
Diffstat (limited to 'libcxx/src/filesystem/operations.cpp')
-rw-r--r-- | libcxx/src/filesystem/operations.cpp | 28 |
1 files changed, 15 insertions, 13 deletions
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp index 87b38fb..abd8695 100644 --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -126,9 +126,6 @@ void __copy(const path& from, const path& to, copy_options options, error_code* return err.report(errc::function_not_supported); } - if (ec) - ec->clear(); - if (is_symlink(f)) { if (bool(copy_options::skip_symlinks & options)) { // do nothing @@ -166,15 +163,15 @@ void __copy(const path& from, const path& to, copy_options options, error_code* return; } error_code m_ec2; - for (; it != directory_iterator(); it.increment(m_ec2)) { - if (m_ec2) { - return err.report(m_ec2); - } + for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) { __copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec); if (ec && *ec) { return; } } + if (m_ec2) { + return err.report(m_ec2); + } } } @@ -936,23 +933,28 @@ path __weakly_canonical(const path& p, error_code* ec) { --PP; vector<string_view_t> DNEParts; + error_code m_ec; while (PP.State != PathParser::PS_BeforeBegin) { tmp.assign(createView(p.native().data(), &PP.RawEntry.back())); - error_code m_ec; file_status st = __status(tmp, &m_ec); if (!status_known(st)) { return err.report(m_ec); } else if (exists(st)) { - result = __canonical(tmp, ec); + result = __canonical(tmp, &m_ec); + if (m_ec) { + return err.report(m_ec); + } break; } DNEParts.push_back(*PP); --PP; } - if (PP.State == PathParser::PS_BeforeBegin) - result = __canonical("", ec); - if (ec) - ec->clear(); + if (PP.State == PathParser::PS_BeforeBegin) { + result = __canonical("", &m_ec); + if (m_ec) { + return err.report(m_ec); + } + } if (DNEParts.empty()) return result; for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It) |