authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-03 23:33:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-03 23:33:18-04:00
loge1e536e03d28942fe6dfa4a9f3881af3fb57a458
tree24181dfe6f2c22107ce987b01c0d4d8cb895291b
parent6050b9d8359d1ae6b808c332aa27142b0064a6be
parent7e951e504302dc2a7b0efa3e2ea0dcde5524ac60

Merge branch 'wip-macos-dirent' of https://github.com/hellerve/zig into hellerve-wip-macos-dirent


6 files changed, 160 insertions(+), 10 deletions(-)

std/c/darwin.zig+10
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1extern "c" fn __error() &c_int;1extern "c" fn __error() &c_int;
2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
45
5pub use @import("../os/darwin_errno.zig");6pub use @import("../os/darwin_errno.zig");
67
...@@ -45,3 +46,12 @@ pub const Sigaction = extern struct {...@@ -45,3 +46,12 @@ pub const Sigaction = extern struct {
45 sa_mask: sigset_t,46 sa_mask: sigset_t,
46 sa_flags: c_int,47 sa_flags: c_int,
47};48};
49
50pub const dirent = extern struct {
51 d_ino: usize,
52 d_seekoff: usize,
53 d_reclen: u16,
54 d_namlen: u16,
55 d_type: u8,
56 d_name: u8, // field address is address of first byte of name
57};
std/c/index.zig+1
...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o
44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
47pub extern "c" fn rmdir(path: &const u8) c_int;
4748
48pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;49pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
49pub extern "c" fn malloc(usize) ?&c_void;50pub extern "c" fn malloc(usize) ?&c_void;
std/os/darwin.zig+32
...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks
56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
5858
59pub const O_ACCMODE = 3;
60pub const O_ALERT = 536870912;
61pub const O_ASYNC = 64;
62pub const O_DIRECTORY = 1048576;
63pub const O_DP_GETRAWENCRYPTED = 1;
64pub const O_DP_GETRAWUNENCRYPTED = 2;
65pub const O_DSYNC = 4194304;
66pub const O_FSYNC = O_SYNC;
67pub const O_NOCTTY = 131072;
68pub const O_POPUP = 2147483648;
69pub const O_SYNC = 128;
70
59pub const SEEK_SET = 0x0;71pub const SEEK_SET = 0x0;
60pub const SEEK_CUR = 0x1;72pub const SEEK_CUR = 0x1;
61pub const SEEK_END = 0x2;73pub const SEEK_END = 0x2;
6274
75pub const DT_UNKNOWN = 0;
76pub const DT_FIFO = 1;
77pub const DT_CHR = 2;
78pub const DT_DIR = 4;
79pub const DT_BLK = 6;
80pub const DT_REG = 8;
81pub const DT_LNK = 10;
82pub const DT_SOCK = 12;
83pub const DT_WHT = 14;
84
63pub const SIG_BLOCK = 1; /// block specified signal set85pub const SIG_BLOCK = 1; /// block specified signal set
64pub const SIG_UNBLOCK = 2; /// unblock specified signal set86pub const SIG_UNBLOCK = 2; /// unblock specified signal set
65pub const SIG_SETMASK = 3; /// set specified signal set87pub const SIG_SETMASK = 3; /// set specified signal set
...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
192 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
193}215}
194216
217
218pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
219 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
220}
221
195pub fn mkdir(path: &const u8, mode: u32) usize {222pub fn mkdir(path: &const u8, mode: u32) usize {
196 return errnoWrap(c.mkdir(path, mode));223 return errnoWrap(c.mkdir(path, mode));
197}224}
...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
204 return errnoWrap(c.rename(old, new));231 return errnoWrap(c.rename(old, new));
205}232}
206233
234pub fn rmdir(path: &const u8) usize {
235 return errnoWrap(c.rmdir(path));
236}
237
207pub fn chdir(path: &const u8) usize {238pub fn chdir(path: &const u8) usize {
208 return errnoWrap(c.chdir(path));239 return errnoWrap(c.chdir(path));
209}240}
...@@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);...@@ -268,6 +299,7 @@ pub const empty_sigset = sigset_t(0);
268299
269pub const timespec = c.timespec;300pub const timespec = c.timespec;
270pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;
271303
272/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.304/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
273pub const Sigaction = struct {305pub const Sigaction = struct {
std/os/index.zig+91-10
...@@ -1055,10 +1055,11 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1055,10 +1055,11 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1055 return;1055 return;
1056 } else |err| switch (err) {1056 } else |err| switch (err) {
1057 error.FileNotFound => return,1057 error.FileNotFound => return,
1058
1059 error.AccessDenied,
1058 error.IsDir => {},1060 error.IsDir => {},
10591061
1060 error.OutOfMemory,1062 error.OutOfMemory,
1061 error.AccessDenied,
1062 error.SymLinkLoop,1063 error.SymLinkLoop,
1063 error.NameTooLong,1064 error.NameTooLong,
1064 error.SystemResources,1065 error.SystemResources,
...@@ -1109,18 +1110,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1109,18 +1110,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1109}1110}
11101111
1111pub const Dir = struct {1112pub const Dir = struct {
1112 // See man getdents
1113 fd: i32,1113 fd: i32,
1114 darwin_seek: darwin_seek_t,
1114 allocator: &Allocator,1115 allocator: &Allocator,
1115 buf: []u8,1116 buf: []u8,
1116 index: usize,1117 index: usize,
1117 end_index: usize,1118 end_index: usize,
11181119
1119 const LinuxEntry = extern struct {1120 const darwin_seek_t = switch (builtin.os) {
1120 d_ino: usize,1121 Os.macosx, Os.ios => i64,
1121 d_off: usize,1122 else => void,
1122 d_reclen: u16,
1123 d_name: u8, // field address is the address of first byte of name
1124 };1123 };
11251124
1126 pub const Entry = struct {1125 pub const Entry = struct {
...@@ -1135,15 +1134,26 @@ pub const Dir = struct {...@@ -1135,15 +1134,26 @@ pub const Dir = struct {
1135 SymLink,1134 SymLink,
1136 File,1135 File,
1137 UnixDomainSocket,1136 UnixDomainSocket,
1137 Whiteout,
1138 Unknown,1138 Unknown,
1139 };1139 };
1140 };1140 };
11411141
1142 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {1142 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
1143 const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0);1143 const fd = switch (builtin.os) {
1144 Os.windows => @compileError("TODO support Dir.open for windows"),
1145 Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1146 Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1147 else => @compileError("Dir.open is not supported for this platform"),
1148 };
1149 const darwin_seek_init = switch (builtin.os) {
1150 Os.macosx, Os.ios => 0,
1151 else => {},
1152 };
1144 return Dir {1153 return Dir {
1145 .allocator = allocator,1154 .allocator = allocator,
1146 .fd = fd,1155 .fd = fd,
1156 .darwin_seek = darwin_seek_init,
1147 .index = 0,1157 .index = 0,
1148 .end_index = 0,1158 .end_index = 0,
1149 .buf = []u8{},1159 .buf = []u8{},
...@@ -1158,6 +1168,76 @@ pub const Dir = struct {...@@ -1158,6 +1168,76 @@ pub const Dir = struct {
1158 /// Memory such as file names referenced in this returned entry becomes invalid1168 /// Memory such as file names referenced in this returned entry becomes invalid
1159 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.1169 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1160 pub fn next(self: &Dir) !?Entry {1170 pub fn next(self: &Dir) !?Entry {
1171 switch (builtin.os) {
1172 Os.linux => return self.nextLinux(),
1173 Os.macosx, Os.ios => return self.nextDarwin(),
1174 Os.windows => return self.nextWindows(),
1175 else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
1176 }
1177 }
1178
1179 fn nextDarwin(self: &Dir) !?Entry {
1180 start_over: while (true) {
1181 if (self.index >= self.end_index) {
1182 if (self.buf.len == 0) {
1183 self.buf = try self.allocator.alloc(u8, page_size);
1184 }
1185
1186 while (true) {
1187 const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len,
1188 &self.darwin_seek);
1189 const err = posix.getErrno(result);
1190 if (err > 0) {
1191 switch (err) {
1192 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1193 posix.EINVAL => {
1194 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1195 continue;
1196 },
1197 else => return unexpectedErrorPosix(err),
1198 }
1199 }
1200 if (result == 0)
1201 return null;
1202 self.index = 0;
1203 self.end_index = result;
1204 break;
1205 }
1206 }
1207 const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1208 const next_index = self.index + darwin_entry.d_reclen;
1209 self.index = next_index;
1210
1211 const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];
1212
1213 // skip . and .. entries
1214 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1215 continue :start_over;
1216 }
1217
1218 const entry_kind = switch (darwin_entry.d_type) {
1219 posix.DT_BLK => Entry.Kind.BlockDevice,
1220 posix.DT_CHR => Entry.Kind.CharacterDevice,
1221 posix.DT_DIR => Entry.Kind.Directory,
1222 posix.DT_FIFO => Entry.Kind.NamedPipe,
1223 posix.DT_LNK => Entry.Kind.SymLink,
1224 posix.DT_REG => Entry.Kind.File,
1225 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1226 posix.DT_WHT => Entry.Kind.Whiteout,
1227 else => Entry.Kind.Unknown,
1228 };
1229 return Entry {
1230 .name = name,
1231 .kind = entry_kind,
1232 };
1233 }
1234 }
1235
1236 fn nextWindows(self: &Dir) !?Entry {
1237 @compileError("TODO support Dir.next for windows");
1238 }
1239
1240 fn nextLinux(self: &Dir) !?Entry {
1161 start_over: while (true) {1241 start_over: while (true) {
1162 if (self.index >= self.end_index) {1242 if (self.index >= self.end_index) {
1163 if (self.buf.len == 0) {1243 if (self.buf.len == 0) {
...@@ -1166,7 +1246,7 @@ pub const Dir = struct {...@@ -1166,7 +1246,7 @@ pub const Dir = struct {
11661246
1167 while (true) {1247 while (true) {
1168 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);1248 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1169 const err = linux.getErrno(result);1249 const err = posix.getErrno(result);
1170 if (err > 0) {1250 if (err > 0) {
1171 switch (err) {1251 switch (err) {
1172 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,1252 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
...@@ -1184,7 +1264,7 @@ pub const Dir = struct {...@@ -1184,7 +1264,7 @@ pub const Dir = struct {
1184 break;1264 break;
1185 }1265 }
1186 }1266 }
1187 const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);1267 const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1188 const next_index = self.index + linux_entry.d_reclen;1268 const next_index = self.index + linux_entry.d_reclen;
1189 self.index = next_index;1269 self.index = next_index;
11901270
...@@ -1679,6 +1759,7 @@ test "std.os" {...@@ -1679,6 +1759,7 @@ test "std.os" {
1679 _ = @import("linux/index.zig");1759 _ = @import("linux/index.zig");
1680 _ = @import("path.zig");1760 _ = @import("path.zig");
1681 _ = @import("windows/index.zig");1761 _ = @import("windows/index.zig");
1762 _ = @import("test.zig");
1682}1763}
16831764
16841765
std/os/linux/x86_64.zig+8
...@@ -488,3 +488,11 @@ pub const timespec = extern struct {...@@ -488,3 +488,11 @@ pub const timespec = extern struct {
488 tv_sec: isize,488 tv_sec: isize,
489 tv_nsec: isize,489 tv_nsec: isize,
490};490};
491
492pub const dirent = extern struct {
493 d_ino: usize,
494 d_off: usize,
495 d_reclen: u16,
496 d_name: u8, // field address is the address of first byte of name
497};
498
std/os/test.zig created+18
...@@ -0,0 +1,18 @@
1const std = @import("../index.zig");
2const os = std.os;
3const debug = std.debug;
4const io = std.io;
5
6const a = std.debug.global_allocator;
7
8test "makePath, put some files in it, deleteTree" {
9 try os.makePath(a, "os_test_tmp/b/c");
10 try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
11 try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
12 try os.deleteTree(a, "os_test_tmp");
13 if (os.Dir.open(a, "os_test_tmp")) |dir| {
14 debug.assert(false); // this should not happen!
15 } else |err| {
16 debug.assert(err == error.PathNotFound);
17 }
18}