feature. See also
. The project being documented here (as the example) is the Zig library itself.
Uring.dirRead
fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize
File
Code
fn dirRead(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
const ev: *Evented = @ptrCast(@alignCast(userdata));
var buffer_index: usize = 0;
while (buffer.len - buffer_index != 0) {
if (dr.end - dr.index == 0) {
// buffered data.
if (buffer_index != 0) break;
var sync: CancelRegion.Sync = try .init(ev);
defer sync.deinit(ev);
if (dr.state == .reset) {
ev.lseek(&sync, dr.dir.handle, 0, linux.SEEK.SET) catch |err| switch (err) {
error.Unseekable => return error.Unexpected,
else => |e| return e,
};
dr.state = .reading;
}
const n = while (true) {
try sync.cancel_region.await(.nothing);
const rc = linux.getdents64(dr.dir.handle, dr.buffer.ptr, @min(dr.buffer.len, std.math.maxInt(c_uint)));
switch (linux.errno(rc)) {
.SUCCESS => break rc,
.INTR => {},
.BADF => |err| return errnoBug(err),
.FAULT => |err| return errnoBug(err),
.NOTDIR => |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;
},
// if the provided buffer is too small. Neither
// scenario is intended to be handled by this API.
.INVAL => return error.Unexpected,
.ACCES => return error.AccessDenied,
else => |err| return unexpectedErrno(err),
}
};
if (n == 0) {
dr.state = .finished;
return 0;
}
dr.index = 0;
dr.end = n;
}
// to align the next entry. This means we can find the end of the name
// by looking at only the 8 bytes before the next record. However since
// file names are usually short it's better to keep the machine code
// simpler.
//
// Furthermore, I observed qemu user mode to not align this struct, so
// this code makes the conservative choice to not assume alignment.
const linux_entry: *align(1) linux.dirent64 = @ptrCast(&dr.buffer[dr.index]);
const next_index = dr.index + linux_entry.reclen;
dr.index = next_index;
const name_ptr: [*]u8 = &linux_entry.name;
const padded_name = name_ptr[0 .. linux_entry.reclen - @offsetOf(linux.dirent64, "name")];
const name_len = std.mem.findScalar(u8, padded_name, 0).?;
const name = name_ptr[0..name_len :0];
if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) continue;
const entry_kind: File.Kind = switch (linux_entry.type) {
linux.DT.BLK => .block_device,
linux.DT.CHR => .character_device,
linux.DT.DIR => .directory,
linux.DT.FIFO => .named_pipe,
linux.DT.LNK => .sym_link,
linux.DT.REG => .file,
linux.DT.SOCK => .unix_domain_socket,
else => .unknown,
};
buffer[buffer_index] = .{
.name = name,
.kind = entry_kind,
.inode = linux_entry.ino,
};
buffer_index += 1;
}
return buffer_index;
}