Commit f5b43ada46
Changed files (6)
std
std/c/darwin.zig
@@ -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
+};
std/c/index.zig
@@ -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;
std/os/linux/x86_64.zig
@@ -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
+};
+
std/os/darwin.zig
@@ -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 {
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,76 @@ 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) {
+ self.buf = try self.allocator.alloc(u8, page_size);
+ }
+
+ while (true) {
+ 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,
+ 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 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) {
@@ -1166,7 +1246,7 @@ pub const Dir = struct {
while (true) {
const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
- const err = linux.getErrno(result);
+ const err = posix.getErrno(result);
if (err > 0) {
switch (err) {
posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
@@ -1184,7 +1264,7 @@ pub const Dir = struct {
break;
}
}
- const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
+ 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.
std/os/test.zig
@@ -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");
+}