mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
std.fs: Split Iterator.next on Linux and WASI to allow for handling platform-specific errors
Follow up to #12226, implements the compromise detailed in https://github.com/ziglang/zig/issues/12211#issuecomment-1196011590
This commit is contained in:
parent
ff125db53d
commit
e7b6a18331
@ -595,6 +595,19 @@ pub const IterableDir = struct {
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Error!?Entry {
|
||||
return self.nextLinux() catch |err| switch (err) {
|
||||
// To be consistent across platforms, iteration ends if the directory being iterated is deleted during iteration.
|
||||
// This matches the behavior of non-Linux UNIX platforms.
|
||||
error.DirNotFound => null,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
pub const ErrorLinux = error{DirNotFound} || IteratorError;
|
||||
|
||||
/// Implementation of `next` that can return `error.DirNotFound` if the directory being
|
||||
/// iterated was deleted during iteration (this error is Linux specific).
|
||||
pub fn nextLinux(self: *Self) ErrorLinux!?Entry {
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
if (self.first_iter) {
|
||||
@ -607,7 +620,7 @@ pub const IterableDir = struct {
|
||||
.BADF => unreachable, // Dir is invalid or was opened without iteration ability
|
||||
.FAULT => unreachable,
|
||||
.NOTDIR => unreachable,
|
||||
.NOENT => return null, // The directory being iterated was deleted during iteration.
|
||||
.NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration.
|
||||
.INVAL => return error.Unexpected, // Linux may in some cases return EINVAL when reading /proc/$PID/net.
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
@ -729,6 +742,20 @@ pub const IterableDir = struct {
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Error!?Entry {
|
||||
return self.nextWasi() catch |err| switch (err) {
|
||||
// To be consistent across platforms, iteration ends if the directory being iterated is deleted during iteration.
|
||||
// This matches the behavior of non-Linux UNIX platforms.
|
||||
error.DirNotFound => null,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
pub const ErrorWasi = error{DirNotFound} || IteratorError;
|
||||
|
||||
/// Implementation of `next` that can return platform-dependent errors depending on the host platform.
|
||||
/// When the host platform is Linux, `error.DirNotFound` can be returned if the directory being
|
||||
/// iterated was deleted during iteration.
|
||||
pub fn nextWasi(self: *Self) ErrorWasi!?Entry {
|
||||
// We intentinally use fd_readdir even when linked with libc,
|
||||
// since its implementation is exactly the same as below,
|
||||
// and we avoid the code complexity here.
|
||||
@ -742,7 +769,7 @@ pub const IterableDir = struct {
|
||||
.FAULT => unreachable,
|
||||
.NOTDIR => unreachable,
|
||||
.INVAL => unreachable,
|
||||
.NOENT => return null, // The directory being iterated was deleted during iteration.
|
||||
.NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration.
|
||||
.NOTCAPABLE => return error.AccessDenied,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
|
||||
@ -241,6 +241,11 @@ test "Dir.Iterator but dir is deleted during iteration" {
|
||||
// Now, when we try to iterate, the next call should return null immediately.
|
||||
const entry = try iterator.next();
|
||||
try std.testing.expect(entry == null);
|
||||
|
||||
// On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
|
||||
if (builtin.os.tag == .linux) {
|
||||
try std.testing.expectError(error.DirNotFound, iterator.nextLinux());
|
||||
}
|
||||
}
|
||||
|
||||
fn entryEql(lhs: IterableDir.Entry, rhs: IterableDir.Entry) bool {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user