5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
fn dirReadBsd(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize {
const t: *Threaded = @ptrCast(@alignCast(userdata));
_ = t;
var buffer_index: usize = 0;
while (buffer.len - buffer_index != 0) {
if (dr.end - dr.index == 0) {
// Refill the buffer, unless we've already created references to
// buffered data.
if (buffer_index != 0) break;
if (dr.state == .reset) {
posixSeekTo(dr.dir.handle, 0) catch |err| switch (err) {
error.Unseekable => return error.Unexpected,
else => |e| return e,
};
dr.state = .reading;
}
const syscall: Syscall = try .start();
const n: usize = while (true) {
const rc = posix.system.getdents(dr.dir.handle, dr.buffer.ptr, dr.buffer.len);
switch (posix.errno(rc)) {
.SUCCESS => {
syscall.finish();
break @intCast(rc);
},
.INTR => {
try syscall.checkCancel();
continue;
},
else => |e| {
syscall.finish();
switch (e) {
.BADF => |err| return errnoBug(err), // Dir is invalid or was opened without iteration ability
.FAULT => |err| return errnoBug(err),
.NOTDIR => |err| return errnoBug(err),
.INVAL => |err| return errnoBug(err),
// Introduced in freebsd 13.2: directory unlinked
// but still open. To be consistent, iteration ends
// if the directory being iterated is deleted
// during iteration.
.NOENT => {
dr.state = .finished;
return 0;
},
else => |err| return posix.unexpectedErrno(err),
}
},
}
};
if (n == 0) {
dr.state = .finished;
return 0;
}
dr.index = 0;
dr.end = n;
}
const bsd_entry = @as(*align(1) posix.system.dirent, @ptrCast(&dr.buffer[dr.index]));
const next_index = dr.index +
if (@hasField(posix.system.dirent, "reclen")) bsd_entry.reclen else bsd_entry.reclen();
dr.index = next_index;
const name = @as([*]u8, @ptrCast(&bsd_entry.name))[0..bsd_entry.namlen];
const skip_zero_fileno = switch (native_os) {
// fileno=0 is used to mark invalid entries or deleted files.
.openbsd, .netbsd => true,
else => false,
};
if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..") or
(skip_zero_fileno and bsd_entry.fileno == 0))
{
continue;
}
const entry_kind: File.Kind = switch (bsd_entry.type) {
posix.DT.BLK => .block_device,
posix.DT.CHR => .character_device,
posix.DT.DIR => .directory,
posix.DT.FIFO => .named_pipe,
posix.DT.LNK => .sym_link,
posix.DT.REG => .file,
posix.DT.SOCK => .unix_domain_socket,
posix.DT.WHT => .whiteout,
else => .unknown,
};
buffer[buffer_index] = .{
.name = name,
.kind = entry_kind,
.inode = bsd_entry.fileno,
};
buffer_index += 1;
}
return buffer_index;
}