| author | |
| committer | |
| log | e1e536e03d28942fe6dfa4a9f3881af3fb57a458 |
| tree | 24181dfe6f2c22107ce987b01c0d4d8cb895291b |
| parent | 6050b9d8359d1ae6b808c332aa27142b0064a6be |
| parent | 7e951e504302dc2a7b0efa3e2ea0dcde5524ac60 |
6 files changed, 160 insertions(+), 10 deletions(-)
std/c/darwin.zig+10| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | extern "c" fn __error() &c_int; | 1 | extern "c" fn __error() &c_int; |
| 2 | pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int; | 2 | pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int; |
| 3 | 3 | ||
| 4 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize; | ||
| 4 | 5 | ||
| 5 | pub use @import("../os/darwin_errno.zig"); | 6 | pub use @import("../os/darwin_errno.zig"); |
| 6 | 7 | ||
| ... | @@ -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 | |||
| 50 | pub 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 |
| 44 | pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int; | 44 | pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int; |
| 45 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; | 45 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; |
| 46 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; | 46 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; |
| 47 | pub extern "c" fn rmdir(path: &const u8) c_int; | ||
| 47 | 48 | ||
| 48 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void; | 49 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void; |
| 49 | pub extern "c" fn malloc(usize) ?&c_void; | 50 | pub 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 |
| 56 | pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only | 56 | pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only |
| 57 | pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec | 57 | pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec |
| 58 | 58 | ||
| 59 | pub const O_ACCMODE = 3; | ||
| 60 | pub const O_ALERT = 536870912; | ||
| 61 | pub const O_ASYNC = 64; | ||
| 62 | pub const O_DIRECTORY = 1048576; | ||
| 63 | pub const O_DP_GETRAWENCRYPTED = 1; | ||
| 64 | pub const O_DP_GETRAWUNENCRYPTED = 2; | ||
| 65 | pub const O_DSYNC = 4194304; | ||
| 66 | pub const O_FSYNC = O_SYNC; | ||
| 67 | pub const O_NOCTTY = 131072; | ||
| 68 | pub const O_POPUP = 2147483648; | ||
| 69 | pub const O_SYNC = 128; | ||
| 70 | |||
| 59 | pub const SEEK_SET = 0x0; | 71 | pub const SEEK_SET = 0x0; |
| 60 | pub const SEEK_CUR = 0x1; | 72 | pub const SEEK_CUR = 0x1; |
| 61 | pub const SEEK_END = 0x2; | 73 | pub const SEEK_END = 0x2; |
| 62 | 74 | ||
| 75 | pub const DT_UNKNOWN = 0; | ||
| 76 | pub const DT_FIFO = 1; | ||
| 77 | pub const DT_CHR = 2; | ||
| 78 | pub const DT_DIR = 4; | ||
| 79 | pub const DT_BLK = 6; | ||
| 80 | pub const DT_REG = 8; | ||
| 81 | pub const DT_LNK = 10; | ||
| 82 | pub const DT_SOCK = 12; | ||
| 83 | pub const DT_WHT = 14; | ||
| 84 | |||
| 63 | pub const SIG_BLOCK = 1; /// block specified signal set | 85 | pub const SIG_BLOCK = 1; /// block specified signal set |
| 64 | pub const SIG_UNBLOCK = 2; /// unblock specified signal set | 86 | pub const SIG_UNBLOCK = 2; /// unblock specified signal set |
| 65 | pub const SIG_SETMASK = 3; /// set specified signal set | 87 | pub 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 | } |
| 194 | 216 | ||
| 217 | |||
| 218 | pub 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 | |||
| 195 | pub fn mkdir(path: &const u8, mode: u32) usize { | 222 | pub 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 | } |
| 206 | 233 | ||
| 234 | pub fn rmdir(path: &const u8) usize { | ||
| 235 | return errnoWrap(c.rmdir(path)); | ||
| 236 | } | ||
| 237 | |||
| 207 | pub fn chdir(path: &const u8) usize { | 238 | pub 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); |
| 268 | 299 | ||
| 269 | pub const timespec = c.timespec; | 300 | pub const timespec = c.timespec; |
| 270 | pub const Stat = c.Stat; | 301 | pub const Stat = c.Stat; |
| 302 | pub const dirent = c.dirent; | ||
| 271 | 303 | ||
| 272 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 304 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 273 | pub const Sigaction = struct { | 305 | pub 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 => {}, |
| 1059 | 1061 | ||
| 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 | } |
| 1110 | 1111 | ||
| 1111 | pub const Dir = struct { | 1112 | pub 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, |
| 1118 | 1119 | ||
| 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 | }; |
| 1125 | 1124 | ||
| 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 | }; |
| 1141 | 1141 | ||
| 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 invalid | 1168 | /// 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 { |
| 1166 | 1246 | ||
| 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; |
| 1190 | 1270 | ||
| ... | @@ -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 | } |
| 1683 | 1764 | ||
| 1684 | 1765 |
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 | |||
| 492 | pub 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 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const os = std.os; | ||
| 3 | const debug = std.debug; | ||
| 4 | const io = std.io; | ||
| 5 | |||
| 6 | const a = std.debug.global_allocator; | ||
| 7 | |||
| 8 | test "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 | } | ||