std/os: getting dir entries works on OS X
This commit is contained in:
parent
0b7b3190fd
commit
f5b43ada46
@ -1,6 +1,7 @@
|
||||
extern "c" fn __error() &c_int;
|
||||
pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
|
||||
|
||||
pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
|
||||
|
||||
pub use @import("../os/darwin_errno.zig");
|
||||
|
||||
@ -45,3 +46,12 @@ pub const Sigaction = extern struct {
|
||||
sa_mask: sigset_t,
|
||||
sa_flags: c_int,
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_ino: usize,
|
||||
d_seekoff: usize,
|
||||
d_reclen: u16,
|
||||
d_namlen: u16,
|
||||
d_type: u8,
|
||||
d_name: u8, // field address is address of first byte of name
|
||||
};
|
||||
|
@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o
|
||||
pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?×pec) c_int;
|
||||
pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
|
||||
pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
|
||||
pub extern "c" fn rmdir(path: &const u8) c_int;
|
||||
|
||||
pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
|
||||
pub extern "c" fn malloc(usize) ?&c_void;
|
||||
|
@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks
|
||||
pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
|
||||
pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
|
||||
|
||||
pub const O_ACCMODE = 3;
|
||||
pub const O_ALERT = 536870912;
|
||||
pub const O_ASYNC = 64;
|
||||
pub const O_DIRECTORY = 1048576;
|
||||
pub const O_DP_GETRAWENCRYPTED = 1;
|
||||
pub const O_DP_GETRAWUNENCRYPTED = 2;
|
||||
pub const O_DSYNC = 4194304;
|
||||
pub const O_FSYNC = O_SYNC;
|
||||
pub const O_NOCTTY = 131072;
|
||||
pub const O_POPUP = 2147483648;
|
||||
pub const O_SYNC = 128;
|
||||
|
||||
pub const SEEK_SET = 0x0;
|
||||
pub const SEEK_CUR = 0x1;
|
||||
pub const SEEK_END = 0x2;
|
||||
|
||||
pub const DT_UNKNOWN = 0;
|
||||
pub const DT_FIFO = 1;
|
||||
pub const DT_CHR = 2;
|
||||
pub const DT_DIR = 4;
|
||||
pub const DT_BLK = 6;
|
||||
pub const DT_REG = 8;
|
||||
pub const DT_LNK = 10;
|
||||
pub const DT_SOCK = 12;
|
||||
pub const DT_WHT = 14;
|
||||
|
||||
pub const SIG_BLOCK = 1; /// block specified signal set
|
||||
pub const SIG_UNBLOCK = 2; /// unblock specified signal set
|
||||
pub const SIG_SETMASK = 3; /// set specified signal set
|
||||
@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
|
||||
return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
|
||||
}
|
||||
|
||||
|
||||
pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
|
||||
return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
|
||||
}
|
||||
|
||||
pub fn mkdir(path: &const u8, mode: u32) usize {
|
||||
return errnoWrap(c.mkdir(path, mode));
|
||||
}
|
||||
@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
|
||||
return errnoWrap(c.rename(old, new));
|
||||
}
|
||||
|
||||
pub fn rmdir(path: &const u8) usize {
|
||||
return errnoWrap(c.rmdir(path));
|
||||
}
|
||||
|
||||
pub fn chdir(path: &const u8) usize {
|
||||
return errnoWrap(c.chdir(path));
|
||||
}
|
||||
@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);
|
||||
|
||||
pub const timespec = c.timespec;
|
||||
pub const Stat = c.Stat;
|
||||
pub const dirent = c.dirent;
|
||||
|
||||
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
|
||||
pub const Sigaction = struct {
|
||||
|
104
std/os/index.zig
104
std/os/index.zig
@ -1055,10 +1055,11 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
|
||||
return;
|
||||
} else |err| switch (err) {
|
||||
error.FileNotFound => return,
|
||||
|
||||
error.AccessDenied,
|
||||
error.IsDir => {},
|
||||
|
||||
error.OutOfMemory,
|
||||
error.AccessDenied,
|
||||
error.SymLinkLoop,
|
||||
error.NameTooLong,
|
||||
error.SystemResources,
|
||||
@ -1109,18 +1110,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
|
||||
}
|
||||
|
||||
pub const Dir = struct {
|
||||
// See man getdents
|
||||
fd: i32,
|
||||
darwin_seek: darwin_seek_t,
|
||||
allocator: &Allocator,
|
||||
buf: []u8,
|
||||
index: usize,
|
||||
end_index: usize,
|
||||
|
||||
const LinuxEntry = extern struct {
|
||||
d_ino: usize,
|
||||
d_off: usize,
|
||||
d_reclen: u16,
|
||||
d_name: u8, // field address is the address of first byte of name
|
||||
const darwin_seek_t = switch (builtin.os) {
|
||||
Os.macosx, Os.ios => i64,
|
||||
else => void,
|
||||
};
|
||||
|
||||
pub const Entry = struct {
|
||||
@ -1135,15 +1134,26 @@ pub const Dir = struct {
|
||||
SymLink,
|
||||
File,
|
||||
UnixDomainSocket,
|
||||
Wht, // TODO wtf is this
|
||||
Unknown,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
|
||||
const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0);
|
||||
const fd = switch (builtin.os) {
|
||||
Os.windows => @compileError("TODO support Dir.open for windows"),
|
||||
Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
|
||||
Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
|
||||
else => @compileError("Dir.open is not supported for this platform"),
|
||||
};
|
||||
const darwin_seek_init = switch (builtin.os) {
|
||||
Os.macosx, Os.ios => 0,
|
||||
else => {},
|
||||
};
|
||||
return Dir {
|
||||
.allocator = allocator,
|
||||
.fd = fd,
|
||||
.darwin_seek = darwin_seek_init,
|
||||
.index = 0,
|
||||
.end_index = 0,
|
||||
.buf = []u8{},
|
||||
@ -1158,6 +1168,15 @@ pub const Dir = 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: &Dir) !?Entry {
|
||||
switch (builtin.os) {
|
||||
Os.linux => return self.nextLinux(),
|
||||
Os.macosx, Os.ios => return self.nextDarwin(),
|
||||
Os.windows => return self.nextWindows(),
|
||||
else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
|
||||
}
|
||||
}
|
||||
|
||||
fn nextDarwin(self: &Dir) !?Entry {
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
if (self.buf.len == 0) {
|
||||
@ -1165,8 +1184,9 @@ pub const Dir = struct {
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
|
||||
const err = linux.getErrno(result);
|
||||
const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len,
|
||||
&self.darwin_seek);
|
||||
const err = posix.getErrno(result);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
||||
@ -1184,7 +1204,67 @@ pub const Dir = struct {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
|
||||
const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
|
||||
const next_index = self.index + darwin_entry.d_reclen;
|
||||
self.index = next_index;
|
||||
|
||||
const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];
|
||||
|
||||
// skip . and .. entries
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind = switch (darwin_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.Wht,
|
||||
else => Entry.Kind.Unknown,
|
||||
};
|
||||
return Entry {
|
||||
.name = name,
|
||||
.kind = entry_kind,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn nextWindows(self: &Dir) !?Entry {
|
||||
@compileError("TODO support Dir.next for windows");
|
||||
}
|
||||
|
||||
fn nextLinux(self: &Dir) !?Entry {
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
if (self.buf.len == 0) {
|
||||
self.buf = try self.allocator.alloc(u8, page_size);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
|
||||
const err = posix.getErrno(result);
|
||||
if (err > 0) {
|
||||
switch (err) {
|
||||
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
|
||||
posix.EINVAL => {
|
||||
self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
|
||||
continue;
|
||||
},
|
||||
else => return unexpectedErrorPosix(err),
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
return null;
|
||||
self.index = 0;
|
||||
self.end_index = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
|
||||
const next_index = self.index + linux_entry.d_reclen;
|
||||
self.index = next_index;
|
||||
|
||||
@ -1683,7 +1763,7 @@ test "std.os" {
|
||||
|
||||
|
||||
// TODO make this a build variable that you can set
|
||||
const unexpected_error_tracing = false;
|
||||
const unexpected_error_tracing = true;
|
||||
|
||||
/// Call this when you made a syscall or something that sets errno
|
||||
/// and you get an unexpected error.
|
||||
|
@ -488,3 +488,11 @@ pub const timespec = extern struct {
|
||||
tv_sec: isize,
|
||||
tv_nsec: isize,
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_ino: usize,
|
||||
d_off: usize,
|
||||
d_reclen: u16,
|
||||
d_name: u8, // field address is the address of first byte of name
|
||||
};
|
||||
|
||||
|
12
std/os/test.zig
Normal file
12
std/os/test.zig
Normal file
@ -0,0 +1,12 @@
|
||||
const std = @import("../index.zig");
|
||||
const os = std.os;
|
||||
const io = std.io;
|
||||
|
||||
const a = std.debug.global_allocator;
|
||||
|
||||
test "makePath, put some files in it, deleteTree" {
|
||||
try os.makePath(a, "os_test_tmp/b/c");
|
||||
try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
|
||||
try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
|
||||
try os.deleteTree(a, "os_test_tmp");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user