Skip to content

Commit 1139902

Browse files
[libcxx] Correct and clean-up filesystem operations error_code paths (llvm#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).
1 parent bce2498 commit 1139902

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

libcxx/src/filesystem/operations.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
126126
return err.report(errc::function_not_supported);
127127
}
128128

129-
if (ec)
130-
ec->clear();
131-
132129
if (is_symlink(f)) {
133130
if (bool(copy_options::skip_symlinks & options)) {
134131
// do nothing
@@ -166,15 +163,15 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
166163
return;
167164
}
168165
error_code m_ec2;
169-
for (; it != directory_iterator(); it.increment(m_ec2)) {
170-
if (m_ec2) {
171-
return err.report(m_ec2);
172-
}
166+
for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) {
173167
__copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec);
174168
if (ec && *ec) {
175169
return;
176170
}
177171
}
172+
if (m_ec2) {
173+
return err.report(m_ec2);
174+
}
178175
}
179176
}
180177

@@ -936,23 +933,28 @@ path __weakly_canonical(const path& p, error_code* ec) {
936933
--PP;
937934
vector<string_view_t> DNEParts;
938935

936+
error_code m_ec;
939937
while (PP.State != PathParser::PS_BeforeBegin) {
940938
tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
941-
error_code m_ec;
942939
file_status st = __status(tmp, &m_ec);
943940
if (!status_known(st)) {
944941
return err.report(m_ec);
945942
} else if (exists(st)) {
946-
result = __canonical(tmp, ec);
943+
result = __canonical(tmp, &m_ec);
944+
if (m_ec) {
945+
return err.report(m_ec);
946+
}
947947
break;
948948
}
949949
DNEParts.push_back(*PP);
950950
--PP;
951951
}
952-
if (PP.State == PathParser::PS_BeforeBegin)
953-
result = __canonical("", ec);
954-
if (ec)
955-
ec->clear();
952+
if (PP.State == PathParser::PS_BeforeBegin) {
953+
result = __canonical("", &m_ec);
954+
if (m_ec) {
955+
return err.report(m_ec);
956+
}
957+
}
956958
if (DNEParts.empty())
957959
return result;
958960
for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)

libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,23 @@ int main(int, char**) {
7474
fs::path p = TC.input;
7575
fs::path expect = TC.expect;
7676
expect.make_preferred();
77-
const fs::path output = fs::weakly_canonical(p);
7877

79-
TEST_REQUIRE(PathEq(output, expect),
80-
TEST_WRITE_CONCATENATED(
81-
"Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output.string()));
78+
{
79+
const fs::path output = fs::weakly_canonical(p);
80+
TEST_REQUIRE(PathEq(output, expect),
81+
TEST_WRITE_CONCATENATED(
82+
"Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output.string()));
83+
}
84+
85+
// Test the error_code variant
86+
{
87+
std::error_code ec;
88+
const fs::path output_c = fs::weakly_canonical(p, ec);
89+
90+
TEST_REQUIRE(PathEq(output_c, expect),
91+
TEST_WRITE_CONCATENATED(
92+
"Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output_c.string()));
93+
}
8294
}
8395
return 0;
8496
}

0 commit comments

Comments
 (0)