feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.dirReadWasi
fn dirReadWasi(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize
File
Code
fn dirReadWasi(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
// implementation is exactly the same as below, and we avoid the code
// complexity here.
const wasi = std.os.wasi;
const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t;
const Header = extern struct {
cookie: u64,
};
const header: *align(@alignOf(usize)) Header = @ptrCast(dr.buffer.ptr);
const header_end: usize = @sizeOf(Header);
if (dr.index < header_end) {
dr.index = header_end;
dr.end = header_end;
header.* = .{ .cookie = wasi.DIRCOOKIE_START };
}
var buffer_index: usize = 0;
while (buffer.len - buffer_index != 0) {
// need to check if the remaining buffer contains the whole dirent.
if (dr.end - dr.index < @sizeOf(wasi.dirent_t)) {
// buffered data.
if (buffer_index != 0) break;
if (dr.state == .reset) {
header.* = .{ .cookie = wasi.DIRCOOKIE_START };
dr.state = .reading;
}
const dents_buffer = dr.buffer[header_end..];
var n: usize = undefined;
const syscall: Syscall = try .start();
while (true) {
switch (wasi.fd_readdir(dr.dir.handle, dents_buffer.ptr, dents_buffer.len, header.cookie, &n)) {
.SUCCESS => {
syscall.finish();
break;
},
.INTR => {
try syscall.checkCancel();
continue;
},
else => |e| {
syscall.finish();
switch (e) {
.BADF => |err| return errnoBug(err),
.FAULT => |err| return errnoBug(err),
.NOTDIR => |err| return errnoBug(err),
.INVAL => |err| return errnoBug(err),
// ends if the directory being iterated is deleted
// during iteration. This matches the behavior of
// non-Linux, non-WASI UNIX platforms.
.NOENT => {
dr.state = .finished;
return 0;
},
.NOTCAPABLE => return error.AccessDenied,
else => |err| return posix.unexpectedErrno(err),
}
},
}
}
if (n == 0) {
dr.state = .finished;
return 0;
}
dr.index = header_end;
dr.end = header_end + n;
}
const entry: *align(1) wasi.dirent_t = @ptrCast(&dr.buffer[dr.index]);
const entry_size = @sizeOf(wasi.dirent_t);
const name_index = dr.index + entry_size;
if (name_index + entry.namlen > dr.end) {
dr.end = dr.index;
continue;
}
const name = dr.buffer[name_index..][0..entry.namlen];
const next_index = name_index + entry.namlen;
dr.index = next_index;
header.cookie = entry.next;
if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, ".."))
continue;
const entry_kind: File.Kind = switch (entry.type) {
.BLOCK_DEVICE => .block_device,
.CHARACTER_DEVICE => .character_device,
.DIRECTORY => .directory,
.SYMBOLIC_LINK => .sym_link,
.REGULAR_FILE => .file,
.SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
else => .unknown,
};
buffer[buffer_index] = .{
.name = name,
.kind = entry_kind,
.inode = entry.ino,
};
buffer_index += 1;
}
return buffer_index;
}