aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorMarcio Giaxa <i@mgxm.me>2018-12-17 22:06:28 -0200
committerMarcio Giaxa <i@mgxm.me>2018-12-19 18:41:59 -0200
commit5ea37f6e8c9226ec02fbc95cc5c6d06a8e9ee6f7 (patch)
tree2022cdb14f206ce6ad8a89960dc175d166affbad /std
parent666b153144eeb160c5b2279d406f8e0b23613857 (diff)
downloadzig-5ea37f6e8c9226ec02fbc95cc5c6d06a8e9ee6f7.tar.gz
zig-5ea37f6e8c9226ec02fbc95cc5c6d06a8e9ee6f7.zip
freebsd: add getdirentries
Diffstat (limited to 'std')
-rw-r--r--std/c/freebsd.zig12
-rw-r--r--std/os/freebsd/index.zig5
-rw-r--r--std/os/index.zig53
3 files changed, 68 insertions, 2 deletions
diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig
index a97cf52eb9..fbcd6236f0 100644
--- a/std/c/freebsd.zig
+++ b/std/c/freebsd.zig
@@ -13,6 +13,7 @@ pub extern "c" fn kevent(
pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
+pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
pub const Kevent = extern struct {
@@ -66,3 +67,14 @@ pub const timespec = extern struct {
tv_sec: isize,
tv_nsec: isize,
};
+
+pub const dirent = extern struct {
+ d_fileno: usize,
+ d_off: i64,
+ d_reclen: u64,
+ d_type: u8,
+ d_pad0: u8,
+ d_namlen: u16,
+ d_pad1: u16,
+ d_name: [256]u8,
+};
diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig
index 975479c1e0..880a49b4a8 100644
--- a/std/os/freebsd/index.zig
+++ b/std/os/freebsd/index.zig
@@ -562,6 +562,10 @@ pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
}
+pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
+ return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
+}
+
pub fn isatty(fd: i32) bool {
var wsz: winsize = undefined;
return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
@@ -743,6 +747,7 @@ pub fn raise(sig: i32) usize {
}
pub const Stat = c.Stat;
+pub const dirent = c.dirent;
pub const timespec = c.timespec;
pub fn fstat(fd: i32, stat_buf: *Stat) usize {
diff --git a/std/os/index.zig b/std/os/index.zig
index be82ad4716..778ab156b0 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -1753,8 +1753,57 @@ pub const Dir = struct {
}
fn nextFreebsd(self: *Dir) !?Entry {
- //self.handle.buf = try self.allocator.alloc(u8, page_size);
- @compileError("TODO implement dirs for FreeBSD");
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, page_size);
+ }
+
+ while (true) {
+ const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
+ const err = posix.getErrno(result);
+ if (err > 0) {
+ switch (err) {
+ posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
+ posix.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(u8, self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => return unexpectedErrorPosix(err),
+ }
+ }
+ if (result == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = result;
+ break;
+ }
+ }
+ const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + freebsd_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
+
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (freebsd_entry.d_type) {
+ posix.DT_BLK => Entry.Kind.BlockDevice,
+ posix.DT_CHR => Entry.Kind.CharacterDevice,
+ posix.DT_DIR => Entry.Kind.Directory,
+ posix.DT_FIFO => Entry.Kind.NamedPipe,
+ posix.DT_LNK => Entry.Kind.SymLink,
+ posix.DT_REG => Entry.Kind.File,
+ posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ posix.DT_WHT => Entry.Kind.Whiteout,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
}
};