authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-11 18:08:08-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-11 18:08:08-08:00
logc3eb592a343d25bbb0f79b80104d7890877c7af6
tree48d0295374ad0b69edb164e7e9ec61a1a1e01253
parent320c4d68f5f40794ae31d5535de9c3a8ff5cb471
parent616f74ba2098297fbe430651930f9e784909263f
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18886 from ziglang/std.os.O-safety

some API work on std.c, std.os, std.os.wasi

47 files changed, 1809 insertions(+), 1992 deletions(-)

ci/aarch64-linux-debug.sh+1-1
...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"
12PREFIX="$HOME/deps/$CACHE_BASENAME"12PREFIX="$HOME/deps/$CACHE_BASENAME"
13ZIG="$PREFIX/bin/zig"13ZIG="$PREFIX/bin/zig"
1414
15export PATH="$HOME/deps/wasmtime-v2.0.2-$ARCH-linux:$PATH"15export PATH="$HOME/deps/wasmtime-v10.0.2-$ARCH-linux:$PATH"
1616
17# Make the `zig version` number consistent.17# Make the `zig version` number consistent.
18# This will affect the cmake command below.18# This will affect the cmake command below.
ci/aarch64-linux-release.sh+1-1
...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"
12PREFIX="$HOME/deps/$CACHE_BASENAME"12PREFIX="$HOME/deps/$CACHE_BASENAME"
13ZIG="$PREFIX/bin/zig"13ZIG="$PREFIX/bin/zig"
1414
15export PATH="$HOME/deps/wasmtime-v2.0.2-$ARCH-linux:$PATH"15export PATH="$HOME/deps/wasmtime-v10.0.2-$ARCH-linux:$PATH"
1616
17# Make the `zig version` number consistent.17# Make the `zig version` number consistent.
18# This will affect the cmake command below.18# This will affect the cmake command below.
ci/x86_64-linux-debug.sh+1-1
...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"
12PREFIX="$HOME/deps/$CACHE_BASENAME"12PREFIX="$HOME/deps/$CACHE_BASENAME"
13ZIG="$PREFIX/bin/zig"13ZIG="$PREFIX/bin/zig"
1414
15export PATH="$HOME/deps/wasmtime-v2.0.2-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-6.1.0.1/bin:$PATH"15export PATH="$HOME/deps/wasmtime-v10.0.2-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-6.1.0.1/bin:$PATH"
1616
17# Make the `zig version` number consistent.17# Make the `zig version` number consistent.
18# This will affect the cmake command below.18# This will affect the cmake command below.
ci/x86_64-linux-release.sh+1-1
...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"...@@ -12,7 +12,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.12.0-dev.203+d3bc1cfc4"
12PREFIX="$HOME/deps/$CACHE_BASENAME"12PREFIX="$HOME/deps/$CACHE_BASENAME"
13ZIG="$PREFIX/bin/zig"13ZIG="$PREFIX/bin/zig"
1414
15export PATH="$HOME/deps/wasmtime-v2.0.2-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-6.1.0.1/bin:$PATH"15export PATH="$HOME/deps/wasmtime-v10.0.2-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-6.1.0.1/bin:$PATH"
1616
17# Make the `zig version` number consistent.17# Make the `zig version` number consistent.
18# This will affect the cmake command below.18# This will affect the cmake command below.
lib/std/c.zig+567-38
...@@ -4,6 +4,10 @@ const c = @This();...@@ -4,6 +4,10 @@ const c = @This();
4const page_size = std.mem.page_size;4const page_size = std.mem.page_size;
5const iovec = std.os.iovec;5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;6const iovec_const = std.os.iovec_const;
7const wasi = @import("c/wasi.zig");
8const native_abi = builtin.abi;
9const native_arch = builtin.cpu.arch;
10const native_os = builtin.os.tag;
711
8/// If not linking libc, returns false.12/// If not linking libc, returns false.
9/// If linking musl libc, returns true.13/// If linking musl libc, returns true.
...@@ -13,7 +17,7 @@ const iovec_const = std.os.iovec_const;...@@ -13,7 +17,7 @@ const iovec_const = std.os.iovec_const;
13pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {17pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
14 return comptime blk: {18 return comptime blk: {
15 if (!builtin.link_libc) break :blk false;19 if (!builtin.link_libc) break :blk false;
16 if (builtin.abi.isMusl()) break :blk true;20 if (native_abi.isMusl()) break :blk true;
17 if (builtin.target.isGnuLibC()) {21 if (builtin.target.isGnuLibC()) {
18 const ver = builtin.os.version_range.linux.glibc;22 const ver = builtin.os.version_range.linux.glibc;
19 const order = ver.order(glibc_version);23 const order = ver.order(glibc_version);
...@@ -27,7 +31,7 @@ pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {...@@ -27,7 +31,7 @@ pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
27 };31 };
28}32}
2933
30pub usingnamespace switch (builtin.os.tag) {34pub usingnamespace switch (native_os) {
31 .linux => @import("c/linux.zig"),35 .linux => @import("c/linux.zig"),
32 .windows => @import("c/windows.zig"),36 .windows => @import("c/windows.zig"),
33 .macos, .ios, .tvos, .watchos => @import("c/darwin.zig"),37 .macos, .ios, .tvos, .watchos => @import("c/darwin.zig"),
...@@ -36,16 +40,504 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -36,16 +40,504 @@ pub usingnamespace switch (builtin.os.tag) {
36 .dragonfly => @import("c/dragonfly.zig"),40 .dragonfly => @import("c/dragonfly.zig"),
37 .openbsd => @import("c/openbsd.zig"),41 .openbsd => @import("c/openbsd.zig"),
38 .haiku => @import("c/haiku.zig"),42 .haiku => @import("c/haiku.zig"),
39 .hermit => @import("c/hermit.zig"),
40 .solaris, .illumos => @import("c/solaris.zig"),43 .solaris, .illumos => @import("c/solaris.zig"),
41 .fuchsia => @import("c/fuchsia.zig"),
42 .minix => @import("c/minix.zig"),
43 .emscripten => @import("c/emscripten.zig"),44 .emscripten => @import("c/emscripten.zig"),
44 .wasi => @import("c/wasi.zig"),45 .wasi => wasi,
45 else => struct {},46 else => struct {},
46};47};
4748
48pub const MAP = switch (builtin.os.tag) {49pub const pthread_mutex_t = switch (native_os) {
50 .linux, .minix => extern struct {
51 data: [data_len]u8 align(@alignOf(usize)) = [_]u8{0} ** data_len,
52
53 const data_len = switch (native_abi) {
54 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
55 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (native_arch) {
56 .aarch64 => 48,
57 .x86_64 => if (native_abi == .gnux32) 40 else 32,
58 .mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
59 else => if (@sizeOf(usize) == 8) 40 else 24,
60 },
61 .android => if (@sizeOf(usize) == 8) 40 else 4,
62 else => @compileError("unsupported ABI"),
63 };
64 },
65 .macos, .ios, .tvos, .watchos => extern struct {
66 sig: c_long = 0x32AAABA7,
67 data: [data_len]u8 = [_]u8{0} ** data_len,
68
69 const data_len = if (@sizeOf(usize) == 8) 56 else 40;
70 },
71 .freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
72 inner: ?*anyopaque = null,
73 },
74 .hermit => extern struct {
75 ptr: usize = std.math.maxInt(usize),
76 },
77 .netbsd => extern struct {
78 magic: u32 = 0x33330003,
79 errorcheck: c.padded_pthread_spin_t = 0,
80 ceiling: c.padded_pthread_spin_t = 0,
81 owner: usize = 0,
82 waiters: ?*u8 = null,
83 recursed: u32 = 0,
84 spare2: ?*anyopaque = null,
85 },
86 .haiku => extern struct {
87 flags: u32 = 0,
88 lock: i32 = 0,
89 unused: i32 = -42,
90 owner: i32 = -1,
91 owner_count: i32 = 0,
92 },
93 .solaris, .illumos => extern struct {
94 flag1: u16 = 0,
95 flag2: u8 = 0,
96 ceiling: u8 = 0,
97 type: u16 = 0,
98 magic: u16 = 0x4d58,
99 lock: u64 = 0,
100 data: u64 = 0,
101 },
102 .fuchsia => extern struct {
103 data: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
104 },
105 .emscripten => extern struct {
106 data: [24]u8 align(4) = [_]u8{0} ** 24,
107 },
108 else => @compileError("target libc does not have pthread_mutex_t"),
109};
110
111pub const pthread_cond_t = switch (native_os) {
112 .linux => extern struct {
113 data: [48]u8 align(@alignOf(usize)) = [_]u8{0} ** 48,
114 },
115 .macos, .ios, .tvos, .watchos => extern struct {
116 sig: c_long = 0x3CB0B1BB,
117 data: [data_len]u8 = [_]u8{0} ** data_len,
118 const data_len = if (@sizeOf(usize) == 8) 40 else 24;
119 },
120 .freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
121 inner: ?*anyopaque = null,
122 },
123 .hermit => extern struct {
124 ptr: usize = std.math.maxInt(usize),
125 },
126 .netbsd => extern struct {
127 magic: u32 = 0x55550005,
128 lock: c.pthread_spin_t = 0,
129 waiters_first: ?*u8 = null,
130 waiters_last: ?*u8 = null,
131 mutex: ?*pthread_mutex_t = null,
132 private: ?*anyopaque = null,
133 },
134 .haiku => extern struct {
135 flags: u32 = 0,
136 unused: i32 = -42,
137 mutex: ?*anyopaque = null,
138 waiter_count: i32 = 0,
139 lock: i32 = 0,
140 },
141 .solaris, .illumos => extern struct {
142 flag: [4]u8 = [_]u8{0} ** 4,
143 type: u16 = 0,
144 magic: u16 = 0x4356,
145 data: u64 = 0,
146 },
147 .fuchsia, .minix, .emscripten => extern struct {
148 data: [48]u8 align(@alignOf(usize)) = [_]u8{0} ** 48,
149 },
150 else => @compileError("target libc does not have pthread_cond_t"),
151};
152
153pub const pthread_rwlock_t = switch (native_os) {
154 .linux => switch (native_abi) {
155 .android => switch (@sizeOf(usize)) {
156 4 => extern struct {
157 data: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
158 },
159 8 => extern struct {
160 data: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
161 },
162 else => @compileError("impossible pointer size"),
163 },
164 else => extern struct {
165 data: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
166 },
167 },
168 .macos, .ios, .tvos, .watchos => extern struct {
169 sig: c_long = 0x2DA8B3B4,
170 data: [192]u8 = [_]u8{0} ** 192,
171 },
172 .freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
173 ptr: ?*anyopaque = null,
174 },
175 .hermit => extern struct {
176 ptr: usize = std.math.maxInt(usize),
177 },
178 .netbsd => extern struct {
179 magic: c_uint = 0x99990009,
180 interlock: switch (builtin.cpu.arch) {
181 .aarch64, .sparc, .x86_64, .x86 => u8,
182 .arm, .powerpc => c_int,
183 else => unreachable,
184 } = 0,
185 rblocked_first: ?*u8 = null,
186 rblocked_last: ?*u8 = null,
187 wblocked_first: ?*u8 = null,
188 wblocked_last: ?*u8 = null,
189 nreaders: c_uint = 0,
190 owner: ?pthread_t = null,
191 private: ?*anyopaque = null,
192 },
193 .solaris, .illumos => extern struct {
194 readers: i32 = 0,
195 type: u16 = 0,
196 magic: u16 = 0x5257,
197 mutex: pthread_mutex_t = .{},
198 readercv: pthread_cond_t = .{},
199 writercv: pthread_cond_t = .{},
200 },
201 .fuchsia => extern struct {
202 size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
203 },
204 .emscripten => extern struct {
205 size: [32]u8 align(4) = [_]u8{0} ** 32,
206 },
207 else => @compileError("target libc does not have pthread_rwlock_t"),
208};
209
210pub const AT = switch (native_os) {
211 .linux => std.os.linux.AT,
212 .windows => struct {
213 /// Remove directory instead of unlinking file
214 pub const REMOVEDIR = 0x200;
215 },
216 .macos, .ios, .tvos, .watchos => struct {
217 pub const FDCWD = -2;
218 /// Use effective ids in access check
219 pub const EACCESS = 0x0010;
220 /// Act on the symlink itself not the target
221 pub const SYMLINK_NOFOLLOW = 0x0020;
222 /// Act on target of symlink
223 pub const SYMLINK_FOLLOW = 0x0040;
224 /// Path refers to directory
225 pub const REMOVEDIR = 0x0080;
226 },
227 .freebsd, .kfreebsd => struct {
228 /// Magic value that specify the use of the current working directory
229 /// to determine the target of relative file paths in the openat() and
230 /// similar syscalls.
231 pub const FDCWD = -100;
232 /// Check access using effective user and group ID
233 pub const EACCESS = 0x0100;
234 /// Do not follow symbolic links
235 pub const SYMLINK_NOFOLLOW = 0x0200;
236 /// Follow symbolic link
237 pub const SYMLINK_FOLLOW = 0x0400;
238 /// Remove directory instead of file
239 pub const REMOVEDIR = 0x0800;
240 /// Fail if not under dirfd
241 pub const BENEATH = 0x1000;
242 },
243 .netbsd => struct {
244 /// Magic value that specify the use of the current working directory
245 /// to determine the target of relative file paths in the openat() and
246 /// similar syscalls.
247 pub const FDCWD = -100;
248 /// Check access using effective user and group ID
249 pub const EACCESS = 0x0100;
250 /// Do not follow symbolic links
251 pub const SYMLINK_NOFOLLOW = 0x0200;
252 /// Follow symbolic link
253 pub const SYMLINK_FOLLOW = 0x0400;
254 /// Remove directory instead of file
255 pub const REMOVEDIR = 0x0800;
256 },
257 .dragonfly => struct {
258 pub const FDCWD = -328243;
259 pub const SYMLINK_NOFOLLOW = 1;
260 pub const REMOVEDIR = 2;
261 pub const EACCESS = 4;
262 pub const SYMLINK_FOLLOW = 8;
263 },
264 .openbsd => struct {
265 /// Magic value that specify the use of the current working directory
266 /// to determine the target of relative file paths in the openat() and
267 /// similar syscalls.
268 pub const FDCWD = -100;
269 /// Check access using effective user and group ID
270 pub const EACCESS = 0x01;
271 /// Do not follow symbolic links
272 pub const SYMLINK_NOFOLLOW = 0x02;
273 /// Follow symbolic link
274 pub const SYMLINK_FOLLOW = 0x04;
275 /// Remove directory instead of file
276 pub const REMOVEDIR = 0x08;
277 },
278 .haiku => struct {
279 pub const FDCWD = -1;
280 pub const SYMLINK_NOFOLLOW = 0x01;
281 pub const SYMLINK_FOLLOW = 0x02;
282 pub const REMOVEDIR = 0x04;
283 pub const EACCESS = 0x08;
284 },
285 .solaris, .illumos => struct {
286 /// Magic value that specify the use of the current working directory
287 /// to determine the target of relative file paths in the openat() and
288 /// similar syscalls.
289 pub const FDCWD: c.fd_t = @bitCast(@as(u32, 0xffd19553));
290 /// Do not follow symbolic links
291 pub const SYMLINK_NOFOLLOW = 0x1000;
292 /// Follow symbolic link
293 pub const SYMLINK_FOLLOW = 0x2000;
294 /// Remove directory instead of file
295 pub const REMOVEDIR = 0x1;
296 pub const TRIGGER = 0x2;
297 /// Check access using effective user and group ID
298 pub const EACCESS = 0x4;
299 },
300 .emscripten => struct {
301 pub const FDCWD = -100;
302 pub const SYMLINK_NOFOLLOW = 0x100;
303 pub const REMOVEDIR = 0x200;
304 pub const SYMLINK_FOLLOW = 0x400;
305 pub const NO_AUTOMOUNT = 0x800;
306 pub const EMPTY_PATH = 0x1000;
307 pub const STATX_SYNC_TYPE = 0x6000;
308 pub const STATX_SYNC_AS_STAT = 0x0000;
309 pub const STATX_FORCE_SYNC = 0x2000;
310 pub const STATX_DONT_SYNC = 0x4000;
311 pub const RECURSIVE = 0x8000;
312 },
313 .wasi => struct {
314 pub const SYMLINK_NOFOLLOW = 0x100;
315 pub const SYMLINK_FOLLOW = 0x400;
316 pub const REMOVEDIR: u32 = 0x4;
317 /// When linking libc, we follow their convention and use -2 for current working directory.
318 /// However, without libc, Zig does a different convention: it assumes the
319 /// current working directory is the first preopen. This behavior can be
320 /// overridden with a public function called `wasi_cwd` in the root source
321 /// file.
322 pub const FDCWD: c.fd_t = if (builtin.link_libc) -2 else 3;
323 },
324
325 else => @compileError("target libc does not have AT"),
326};
327
328pub const O = switch (native_os) {
329 .linux => std.os.linux.O,
330 .emscripten => packed struct(u32) {
331 ACCMODE: std.os.ACCMODE = .RDONLY,
332 _2: u4 = 0,
333 CREAT: bool = false,
334 EXCL: bool = false,
335 NOCTTY: bool = false,
336 TRUNC: bool = false,
337 APPEND: bool = false,
338 NONBLOCK: bool = false,
339 DSYNC: bool = false,
340 ASYNC: bool = false,
341 DIRECT: bool = false,
342 LARGEFILE: bool = false,
343 DIRECTORY: bool = false,
344 NOFOLLOW: bool = false,
345 NOATIME: bool = false,
346 CLOEXEC: bool = false,
347 SYNC: bool = false,
348 PATH: bool = false,
349 TMPFILE: bool = false,
350 _: u9 = 0,
351 },
352 .wasi => packed struct(u32) {
353 APPEND: bool = false,
354 DSYNC: bool = false,
355 NONBLOCK: bool = false,
356 RSYNC: bool = false,
357 SYNC: bool = false,
358 _5: u7 = 0,
359 CREAT: bool = false,
360 DIRECTORY: bool = false,
361 EXCL: bool = false,
362 TRUNC: bool = false,
363 _16: u8 = 0,
364 NOFOLLOW: bool = false,
365 EXEC: bool = false,
366 read: bool = false,
367 SEARCH: bool = false,
368 write: bool = false,
369 _: u3 = 0,
370 },
371 .solaris => packed struct(u32) {
372 ACCMODE: std.os.ACCMODE = .RDONLY,
373 NDELAY: bool = false,
374 APPEND: bool = false,
375 SYNC: bool = false,
376 _5: u1 = 0,
377 DSYNC: bool = false,
378 NONBLOCK: bool = false,
379 CREAT: bool = false,
380 TRUNC: bool = false,
381 EXCL: bool = false,
382 NOCTTY: bool = false,
383 _12: u1 = 0,
384 LARGEFILE: bool = false,
385 XATTR: bool = false,
386 RSYNC: bool = false,
387 _16: u1 = 0,
388 NOFOLLOW: bool = false,
389 NOLINKS: bool = false,
390 _19: u2 = 0,
391 SEARCH: bool = false,
392 EXEC: bool = false,
393 CLOEXEC: bool = false,
394 DIRECTORY: bool = false,
395 DIRECT: bool = false,
396 _: u6 = 0,
397 },
398 .netbsd => packed struct(u32) {
399 ACCMODE: std.os.ACCMODE = .RDONLY,
400 NONBLOCK: bool = false,
401 APPEND: bool = false,
402 SHLOCK: bool = false,
403 EXLOCK: bool = false,
404 ASYNC: bool = false,
405 SYNC: bool = false,
406 NOFOLLOW: bool = false,
407 CREAT: bool = false,
408 TRUNC: bool = false,
409 EXCL: bool = false,
410 _12: u3 = 0,
411 NOCTTY: bool = false,
412 DSYNC: bool = false,
413 RSYNC: bool = false,
414 ALT_IO: bool = false,
415 DIRECT: bool = false,
416 _20: u1 = 0,
417 DIRECTORY: bool = false,
418 CLOEXEC: bool = false,
419 SEARCH: bool = false,
420 _: u8 = 0,
421 },
422 .openbsd => packed struct(u32) {
423 ACCMODE: std.os.ACCMODE = .RDONLY,
424 NONBLOCK: bool = false,
425 APPEND: bool = false,
426 SHLOCK: bool = false,
427 EXLOCK: bool = false,
428 ASYNC: bool = false,
429 SYNC: bool = false,
430 NOFOLLOW: bool = false,
431 CREAT: bool = false,
432 TRUNC: bool = false,
433 EXCL: bool = false,
434 _12: u3 = 0,
435 NOCTTY: bool = false,
436 CLOEXEC: bool = false,
437 DIRECTORY: bool = false,
438 _: u14 = 0,
439 },
440 .haiku => packed struct(u32) {
441 ACCMODE: std.os.ACCMODE = .RDONLY,
442 _2: u4 = 0,
443 CLOEXEC: bool = false,
444 NONBLOCK: bool = false,
445 EXCL: bool = false,
446 CREAT: bool = false,
447 TRUNC: bool = false,
448 APPEND: bool = false,
449 NOCTTY: bool = false,
450 NOTRAVERSE: bool = false,
451 _14: u2 = 0,
452 SYNC: bool = false,
453 RSYNC: bool = false,
454 DSYNC: bool = false,
455 NOFOLLOW: bool = false,
456 DIRECT: bool = false,
457 DIRECTORY: bool = false,
458 _: u10 = 0,
459 },
460 .macos, .ios, .tvos, .watchos => packed struct(u32) {
461 ACCMODE: std.os.ACCMODE = .RDONLY,
462 NONBLOCK: bool = false,
463 APPEND: bool = false,
464 SHLOCK: bool = false,
465 EXLOCK: bool = false,
466 ASYNC: bool = false,
467 SYNC: bool = false,
468 NOFOLLOW: bool = false,
469 CREAT: bool = false,
470 TRUNC: bool = false,
471 EXCL: bool = false,
472 _12: u3 = 0,
473 EVTONLY: bool = false,
474 _16: u1 = 0,
475 NOCTTY: bool = false,
476 _18: u2 = 0,
477 DIRECTORY: bool = false,
478 SYMLINK: bool = false,
479 DSYNC: bool = false,
480 _23: u1 = 0,
481 CLOEXEC: bool = false,
482 _25: u4 = 0,
483 ALERT: bool = false,
484 _30: u1 = 0,
485 POPUP: bool = false,
486 },
487 .dragonfly => packed struct(u32) {
488 ACCMODE: std.os.ACCMODE = .RDONLY,
489 NONBLOCK: bool = false,
490 APPEND: bool = false,
491 SHLOCK: bool = false,
492 EXLOCK: bool = false,
493 ASYNC: bool = false,
494 SYNC: bool = false,
495 NOFOLLOW: bool = false,
496 CREAT: bool = false,
497 TRUNC: bool = false,
498 EXCL: bool = false,
499 _12: u3 = 0,
500 NOCTTY: bool = false,
501 DIRECT: bool = false,
502 CLOEXEC: bool = false,
503 FBLOCKING: bool = false,
504 FNONBLOCKING: bool = false,
505 FAPPEND: bool = false,
506 FOFFSET: bool = false,
507 FSYNCWRITE: bool = false,
508 FASYNCWRITE: bool = false,
509 _24: u3 = 0,
510 DIRECTORY: bool = false,
511 _: u4 = 0,
512 },
513 .freebsd => packed struct(u32) {
514 ACCMODE: std.os.ACCMODE = .RDONLY,
515 NONBLOCK: bool = false,
516 APPEND: bool = false,
517 SHLOCK: bool = false,
518 EXLOCK: bool = false,
519 ASYNC: bool = false,
520 SYNC: bool = false,
521 NOFOLLOW: bool = false,
522 CREAT: bool = false,
523 TRUNC: bool = false,
524 EXCL: bool = false,
525 DSYNC: bool = false,
526 _13: u2 = 0,
527 NOCTTY: bool = false,
528 DIRECT: bool = false,
529 DIRECTORY: bool = false,
530 NOATIME: bool = false,
531 _19: u1 = 0,
532 CLOEXEC: bool = false,
533 PATH: bool = false,
534 TMPFILE: bool = false,
535 _: u9 = 0,
536 },
537 else => @compileError("target libc does not have O"),
538};
539
540pub const MAP = switch (native_os) {
49 .linux => std.os.linux.MAP,541 .linux => std.os.linux.MAP,
50 .emscripten => packed struct(u32) {542 .emscripten => packed struct(u32) {
51 TYPE: enum(u4) {543 TYPE: enum(u4) {
...@@ -187,10 +679,10 @@ pub const MAP = switch (builtin.os.tag) {...@@ -187,10 +679,10 @@ pub const MAP = switch (builtin.os.tag) {
187/// Used by libc to communicate failure. Not actually part of the underlying syscall.679/// Used by libc to communicate failure. Not actually part of the underlying syscall.
188pub const MAP_FAILED: *anyopaque = @ptrFromInt(std.math.maxInt(usize));680pub const MAP_FAILED: *anyopaque = @ptrFromInt(std.math.maxInt(usize));
189681
190pub const whence_t = if (builtin.os.tag == .wasi) std.os.wasi.whence_t else c_int;682pub const whence_t = if (native_os == .wasi) std.os.wasi.whence_t else c_int;
191683
192// Unix-like systems684// Unix-like systems
193pub usingnamespace switch (builtin.os.tag) {685pub usingnamespace switch (native_os) {
194 .netbsd, .windows => struct {},686 .netbsd, .windows => struct {},
195 else => struct {687 else => struct {
196 pub const DIR = opaque {};688 pub const DIR = opaque {};
...@@ -225,25 +717,40 @@ pub usingnamespace switch (builtin.os.tag) {...@@ -225,25 +717,40 @@ pub usingnamespace switch (builtin.os.tag) {
225 },717 },
226};718};
227719
228pub usingnamespace switch (builtin.os.tag) {720pub const fstat = switch (native_os) {
229 .netbsd, .macos, .ios, .watchos, .tvos, .windows => struct {},721 .netbsd => private.__fstat50,
230 else => struct {722 .macos, .ios, .watchos, .tvos => switch (native_arch) {
231 pub extern "c" fn fstat(fd: c.fd_t, buf: *c.Stat) c_int;723 .aarch64 => private.fstat,
232 pub extern "c" fn readdir(dp: *c.DIR) ?*c.dirent;724 else => private.@"fstat$INODE64",
233 },725 },
726 else => private.fstat,
234};727};
235728
236pub usingnamespace switch (builtin.os.tag) {729pub const fstatat = switch (native_os) {
237 .macos, .ios, .watchos, .tvos => struct {},730 .macos, .ios, .watchos, .tvos => switch (native_arch) {
238 else => struct {731 .aarch64 => private.fstatat,
239 pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;732 else => private.@"fstatat$INODE64",
240 pub extern "c" fn fstatat(dirfd: c.fd_t, path: [*:0]const u8, stat_buf: *c.Stat, flags: u32) c_int;
241 },733 },
734 else => private.fstatat,
735};
736
737pub const readdir = switch (native_os) {
738 .macos, .ios, .watchos, .tvos => switch (native_arch) {
739 .aarch64 => private.readdir,
740 else => private.@"readdir$INODE64",
741 },
742 .windows => @compileError("not available"),
743 else => private.readdir,
744};
745
746pub const realpath = switch (native_os) {
747 .macos, .ios, .watchos, .tvos => private.@"realpath$DARWIN_EXTSN",
748 else => private.realpath,
242};749};
243750
244pub fn getErrno(rc: anytype) c.E {751pub fn getErrno(rc: anytype) c.E {
245 if (rc == -1) {752 if (rc == -1) {
246 return @as(c.E, @enumFromInt(c._errno().*));753 return @enumFromInt(c._errno().*);
247 } else {754 } else {
248 return .SUCCESS;755 return .SUCCESS;
249 }756 }
...@@ -263,8 +770,8 @@ pub extern "c" fn _exit(code: c_int) noreturn;...@@ -263,8 +770,8 @@ pub extern "c" fn _exit(code: c_int) noreturn;
263pub extern "c" fn isatty(fd: c.fd_t) c_int;770pub extern "c" fn isatty(fd: c.fd_t) c_int;
264pub extern "c" fn close(fd: c.fd_t) c_int;771pub extern "c" fn close(fd: c.fd_t) c_int;
265pub extern "c" fn lseek(fd: c.fd_t, offset: c.off_t, whence: whence_t) c.off_t;772pub extern "c" fn lseek(fd: c.fd_t, offset: c.off_t, whence: whence_t) c.off_t;
266pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int;773pub extern "c" fn open(path: [*:0]const u8, oflag: O, ...) c_int;
267pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;774pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;
268pub extern "c" fn ftruncate(fd: c_int, length: c.off_t) c_int;775pub extern "c" fn ftruncate(fd: c_int, length: c.off_t) c_int;
269pub extern "c" fn raise(sig: c_int) c_int;776pub extern "c" fn raise(sig: c_int) c_int;
270pub extern "c" fn read(fd: c.fd_t, buf: [*]u8, nbyte: usize) isize;777pub extern "c" fn read(fd: c.fd_t, buf: [*]u8, nbyte: usize) isize;
...@@ -275,7 +782,7 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i...@@ -275,7 +782,7 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i
275pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: c.off_t) isize;782pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: c.off_t) isize;
276pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;783pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;
277pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;784pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;
278pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: c.fd_t, offset: c.off_t) *anyopaque;785pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: c.fd_t, offset: c.off_t) *anyopaque;
279pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;786pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
280pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;787pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
281pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;788pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
...@@ -348,7 +855,7 @@ pub extern "c" fn recv(...@@ -348,7 +855,7 @@ pub extern "c" fn recv(
348 arg1: ?*anyopaque,855 arg1: ?*anyopaque,
349 arg2: usize,856 arg2: usize,
350 arg3: c_int,857 arg3: c_int,
351) if (builtin.os.tag == .windows) c_int else isize;858) if (native_os == .windows) c_int else isize;
352pub extern "c" fn recvfrom(859pub extern "c" fn recvfrom(
353 sockfd: c.fd_t,860 sockfd: c.fd_t,
354 noalias buf: *anyopaque,861 noalias buf: *anyopaque,
...@@ -356,7 +863,7 @@ pub extern "c" fn recvfrom(...@@ -356,7 +863,7 @@ pub extern "c" fn recvfrom(
356 flags: u32,863 flags: u32,
357 noalias src_addr: ?*c.sockaddr,864 noalias src_addr: ?*c.sockaddr,
358 noalias addrlen: ?*c.socklen_t,865 noalias addrlen: ?*c.socklen_t,
359) if (builtin.os.tag == .windows) c_int else isize;866) if (native_os == .windows) c_int else isize;
360pub extern "c" fn recvmsg(sockfd: c.fd_t, msg: *c.msghdr, flags: u32) isize;867pub extern "c" fn recvmsg(sockfd: c.fd_t, msg: *c.msghdr, flags: u32) isize;
361868
362pub extern "c" fn kill(pid: c.pid_t, sig: c_int) c_int;869pub extern "c" fn kill(pid: c.pid_t, sig: c_int) c_int;
...@@ -492,18 +999,18 @@ pub extern "c" fn dn_expand(...@@ -492,18 +999,18 @@ pub extern "c" fn dn_expand(
492 length: c_int,999 length: c_int,
493) c_int;1000) c_int;
4941001
495pub const PTHREAD_MUTEX_INITIALIZER = c.pthread_mutex_t{};1002pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
496pub extern "c" fn pthread_mutex_lock(mutex: *c.pthread_mutex_t) c.E;1003pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c.E;
497pub extern "c" fn pthread_mutex_unlock(mutex: *c.pthread_mutex_t) c.E;1004pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c.E;
498pub extern "c" fn pthread_mutex_trylock(mutex: *c.pthread_mutex_t) c.E;1005pub extern "c" fn pthread_mutex_trylock(mutex: *pthread_mutex_t) c.E;
499pub extern "c" fn pthread_mutex_destroy(mutex: *c.pthread_mutex_t) c.E;1006pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c.E;
5001007
501pub const PTHREAD_COND_INITIALIZER = c.pthread_cond_t{};1008pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
502pub extern "c" fn pthread_cond_wait(noalias cond: *c.pthread_cond_t, noalias mutex: *c.pthread_mutex_t) c.E;1009pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c.E;
503pub extern "c" fn pthread_cond_timedwait(noalias cond: *c.pthread_cond_t, noalias mutex: *c.pthread_mutex_t, noalias abstime: *const c.timespec) c.E;1010pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const c.timespec) c.E;
504pub extern "c" fn pthread_cond_signal(cond: *c.pthread_cond_t) c.E;1011pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c.E;
505pub extern "c" fn pthread_cond_broadcast(cond: *c.pthread_cond_t) c.E;1012pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c.E;
506pub extern "c" fn pthread_cond_destroy(cond: *c.pthread_cond_t) c.E;1013pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c.E;
5071014
508pub extern "c" fn pthread_rwlock_destroy(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;1015pub extern "c" fn pthread_rwlock_destroy(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;
509pub extern "c" fn pthread_rwlock_rdlock(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;1016pub extern "c" fn pthread_rwlock_rdlock(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;
...@@ -542,14 +1049,14 @@ pub usingnamespace if (builtin.target.isAndroid()) struct {...@@ -542,14 +1049,14 @@ pub usingnamespace if (builtin.target.isAndroid()) struct {
542 // android bionic libc does not implement getcontext,1049 // android bionic libc does not implement getcontext,
543 // and std.os.linux.getcontext also cannot be built for1050 // and std.os.linux.getcontext also cannot be built for
544 // bionic libc currently.1051 // bionic libc currently.
545} else if (builtin.os.tag == .linux and builtin.target.isMusl()) struct {1052} else if (native_os == .linux and builtin.target.isMusl()) struct {
546 // musl does not implement getcontext1053 // musl does not implement getcontext
547 pub const getcontext = std.os.linux.getcontext;1054 pub const getcontext = std.os.linux.getcontext;
548} else struct {1055} else struct {
549 pub extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;1056 pub extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;
550};1057};
5511058
552pub const max_align_t = if (builtin.abi == .msvc)1059pub const max_align_t = if (native_abi == .msvc)
553 f641060 f64
554else if (builtin.target.isDarwin())1061else if (builtin.target.isDarwin())
555 c_longdouble1062 c_longdouble
...@@ -558,3 +1065,25 @@ else...@@ -558,3 +1065,25 @@ else
558 a: c_longlong,1065 a: c_longlong,
559 b: c_longdouble,1066 b: c_longdouble,
560 };1067 };
1068
1069const private = struct {
1070 extern "c" fn fstat(fd: c.fd_t, buf: *c.Stat) c_int;
1071 /// On x86_64 Darwin, fstat has to be manually linked with $INODE64 suffix to
1072 /// force 64bit version.
1073 /// Note that this is fixed on aarch64 and no longer necessary.
1074 extern "c" fn @"fstat$INODE64"(fd: c.fd_t, buf: *c.Stat) c_int;
1075
1076 extern "c" fn fstatat(dirfd: c.fd_t, path: [*:0]const u8, stat_buf: *c.Stat, flags: u32) c_int;
1077 /// On x86_64 Darwin, fstatat has to be manually linked with $INODE64 suffix to
1078 /// force 64bit version.
1079 /// Note that this is fixed on aarch64 and no longer necessary.
1080 extern "c" fn @"fstatat$INODE64"(dirfd: c.fd_t, path_name: [*:0]const u8, buf: *c.Stat, flags: u32) c_int;
1081
1082 extern "c" fn __fstat50(fd: c.fd_t, buf: *c.Stat) c_int;
1083
1084 extern "c" fn readdir(dir: *c.DIR) ?*c.dirent;
1085 extern "c" fn @"readdir$INODE64"(dir: *c.DIR) ?*c.dirent;
1086
1087 extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
1088 extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
1089};
lib/std/c/darwin.zig+6-102
...@@ -169,31 +169,8 @@ pub const COPYFILE_DATA = 1 << 3;...@@ -169,31 +169,8 @@ pub const COPYFILE_DATA = 1 << 3;
169pub const copyfile_state_t = *opaque {};169pub const copyfile_state_t = *opaque {};
170pub extern "c" fn fcopyfile(from: fd_t, to: fd_t, state: ?copyfile_state_t, flags: u32) c_int;170pub extern "c" fn fcopyfile(from: fd_t, to: fd_t, state: ?copyfile_state_t, flags: u32) c_int;
171171
172pub extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
173pub const realpath = @"realpath$DARWIN_EXTSN";
174
175pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;172pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
176173
177const private = struct {
178 extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
179 /// On x86_64 Darwin, fstat has to be manually linked with $INODE64 suffix to
180 /// force 64bit version.
181 /// Note that this is fixed on aarch64 and no longer necessary.
182 extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
183
184 extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int;
185 /// On x86_64 Darwin, fstatat has to be manually linked with $INODE64 suffix to
186 /// force 64bit version.
187 /// Note that this is fixed on aarch64 and no longer necessary.
188 extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *Stat, flags: u32) c_int;
189
190 extern "c" fn readdir(dir: *std.c.DIR) ?*dirent;
191 extern "c" fn @"readdir$INODE64"(dir: *std.c.DIR) ?*dirent;
192};
193pub const fstat = if (native_arch == .aarch64) private.fstat else private.@"fstat$INODE64";
194pub const fstatat = if (native_arch == .aarch64) private.fstatat else private.@"fstatat$INODE64";
195pub const readdir = if (native_arch == .aarch64) private.readdir else private.@"readdir$INODE64";
196
197pub extern "c" fn mach_absolute_time() u64;174pub extern "c" fn mach_absolute_time() u64;
198pub extern "c" fn mach_continuous_time() u64;175pub extern "c" fn mach_continuous_time() u64;
199pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_return_t;176pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_return_t;
...@@ -866,21 +843,7 @@ pub const qos_class_t = enum(c_uint) {...@@ -866,21 +843,7 @@ pub const qos_class_t = enum(c_uint) {
866 QOS_CLASS_UNSPECIFIED = 0x00,843 QOS_CLASS_UNSPECIFIED = 0x00,
867};844};
868845
869pub const pthread_mutex_t = extern struct {
870 __sig: c_long = 0x32AAABA7,
871 __opaque: [__PTHREAD_MUTEX_SIZE__]u8 = [_]u8{0} ** __PTHREAD_MUTEX_SIZE__,
872};
873pub const pthread_cond_t = extern struct {
874 __sig: c_long = 0x3CB0B1BB,
875 __opaque: [__PTHREAD_COND_SIZE__]u8 = [_]u8{0} ** __PTHREAD_COND_SIZE__,
876};
877pub const pthread_rwlock_t = extern struct {
878 __sig: c_long = 0x2DA8B3B4,
879 __opaque: [192]u8 = [_]u8{0} ** 192,
880};
881pub const sem_t = c_int;846pub const sem_t = c_int;
882const __PTHREAD_MUTEX_SIZE__ = if (@sizeOf(usize) == 8) 56 else 40;
883const __PTHREAD_COND_SIZE__ = if (@sizeOf(usize) == 8) 40 else 24;
884847
885pub const pthread_attr_t = extern struct {848pub const pthread_attr_t = extern struct {
886 __sig: c_long,849 __sig: c_long,
...@@ -1202,16 +1165,12 @@ pub const Sigaction = extern struct {...@@ -1202,16 +1165,12 @@ pub const Sigaction = extern struct {
1202};1165};
12031166
1204pub const dirent = extern struct {1167pub const dirent = extern struct {
1205 d_ino: u64,1168 ino: u64,
1206 d_seekoff: u64,1169 seekoff: u64,
1207 d_reclen: u16,1170 reclen: u16,
1208 d_namlen: u16,1171 namlen: u16,
1209 d_type: u8,1172 type: u8,
1210 d_name: [1024]u8,1173 name: [1024]u8,
1211
1212 pub fn reclen(self: dirent) u16 {
1213 return self.d_reclen;
1214 }
1215};1174};
12161175
1217/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.1176/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
...@@ -1346,49 +1305,6 @@ pub const X_OK = 1;...@@ -1346,49 +1305,6 @@ pub const X_OK = 1;
1346pub const W_OK = 2;1305pub const W_OK = 2;
1347pub const R_OK = 4;1306pub const R_OK = 4;
13481307
1349pub const O = struct {
1350 pub const PATH = 0x0000;
1351 /// open for reading only
1352 pub const RDONLY = 0x0000;
1353 /// open for writing only
1354 pub const WRONLY = 0x0001;
1355 /// open for reading and writing
1356 pub const RDWR = 0x0002;
1357 /// do not block on open or for data to become available
1358 pub const NONBLOCK = 0x0004;
1359 /// append on each write
1360 pub const APPEND = 0x0008;
1361 /// create file if it does not exist
1362 pub const CREAT = 0x0200;
1363 /// truncate size to 0
1364 pub const TRUNC = 0x0400;
1365 /// error if CREAT and the file exists
1366 pub const EXCL = 0x0800;
1367 /// atomically obtain a shared lock
1368 pub const SHLOCK = 0x0010;
1369 /// atomically obtain an exclusive lock
1370 pub const EXLOCK = 0x0020;
1371 /// do not follow symlinks
1372 pub const NOFOLLOW = 0x0100;
1373 /// allow open of symlinks
1374 pub const SYMLINK = 0x200000;
1375 /// descriptor requested for event notifications only
1376 pub const EVTONLY = 0x8000;
1377 /// mark as close-on-exec
1378 pub const CLOEXEC = 0x1000000;
1379 pub const ACCMODE = 3;
1380 pub const ALERT = 536870912;
1381 pub const ASYNC = 64;
1382 pub const DIRECTORY = 1048576;
1383 pub const DP_GETRAWENCRYPTED = 1;
1384 pub const DP_GETRAWUNENCRYPTED = 2;
1385 pub const DSYNC = 4194304;
1386 pub const FSYNC = SYNC;
1387 pub const NOCTTY = 131072;
1388 pub const POPUP = 2147483648;
1389 pub const SYNC = 128;
1390};
1391
1392pub const SEEK = struct {1308pub const SEEK = struct {
1393 pub const SET = 0x0;1309 pub const SET = 0x0;
1394 pub const CUR = 0x1;1310 pub const CUR = 0x1;
...@@ -2529,18 +2445,6 @@ pub const S = struct {...@@ -2529,18 +2445,6 @@ pub const S = struct {
25292445
2530pub const HOST_NAME_MAX = 72;2446pub const HOST_NAME_MAX = 72;
25312447
2532pub const AT = struct {
2533 pub const FDCWD = -2;
2534 /// Use effective ids in access check
2535 pub const EACCESS = 0x0010;
2536 /// Act on the symlink itself not the target
2537 pub const SYMLINK_NOFOLLOW = 0x0020;
2538 /// Act on target of symlink
2539 pub const SYMLINK_FOLLOW = 0x0040;
2540 /// Path refers to directory
2541 pub const REMOVEDIR = 0x0080;
2542};
2543
2544pub const addrinfo = extern struct {2448pub const addrinfo = extern struct {
2545 flags: i32,2449 flags: i32,
2546 family: i32,2450 family: i32,
lib/std/c/dragonfly.zig+7-55
...@@ -22,22 +22,11 @@ pub extern "c" fn lwp_gettid() c_int;...@@ -22,22 +22,11 @@ pub extern "c" fn lwp_gettid() c_int;
2222
23pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;23pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
2424
25pub const pthread_mutex_t = extern struct {
26 inner: ?*anyopaque = null,
27};
28pub const pthread_cond_t = extern struct {
29 inner: ?*anyopaque = null,
30};
31
32pub const pthread_attr_t = extern struct { // copied from freebsd25pub const pthread_attr_t = extern struct { // copied from freebsd
33 __size: [56]u8,26 __size: [56]u8,
34 __align: c_long,27 __align: c_long,
35};28};
3629
37pub const pthread_rwlock_t = extern struct {
38 ptr: ?*anyopaque = null,
39};
40
41pub const sem_t = ?*opaque {};30pub const sem_t = ?*opaque {};
4231
43pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;32pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
...@@ -394,35 +383,6 @@ pub const X_OK = 1; // test for execute or search permission...@@ -394,35 +383,6 @@ pub const X_OK = 1; // test for execute or search permission
394pub const W_OK = 2; // test for write permission383pub const W_OK = 2; // test for write permission
395pub const R_OK = 4; // test for read permission384pub const R_OK = 4; // test for read permission
396385
397pub const O = struct {
398 pub const RDONLY = 0;
399 pub const NDELAY = NONBLOCK;
400 pub const WRONLY = 1;
401 pub const RDWR = 2;
402 pub const ACCMODE = 3;
403 pub const NONBLOCK = 4;
404 pub const APPEND = 8;
405 pub const SHLOCK = 16;
406 pub const EXLOCK = 32;
407 pub const ASYNC = 64;
408 pub const FSYNC = 128;
409 pub const SYNC = 128;
410 pub const NOFOLLOW = 256;
411 pub const CREAT = 512;
412 pub const TRUNC = 1024;
413 pub const EXCL = 2048;
414 pub const NOCTTY = 32768;
415 pub const DIRECT = 65536;
416 pub const CLOEXEC = 131072;
417 pub const FBLOCKING = 262144;
418 pub const FNONBLOCKING = 524288;
419 pub const FAPPEND = 1048576;
420 pub const FOFFSET = 2097152;
421 pub const FSYNCWRITE = 4194304;
422 pub const FASYNCWRITE = 8388608;
423 pub const DIRECTORY = 134217728;
424};
425
426pub const SEEK = struct {386pub const SEEK = struct {
427 pub const SET = 0;387 pub const SET = 0;
428 pub const CUR = 1;388 pub const CUR = 1;
...@@ -458,24 +418,16 @@ pub const F = struct {...@@ -458,24 +418,16 @@ pub const F = struct {
458418
459pub const FD_CLOEXEC = 1;419pub const FD_CLOEXEC = 1;
460420
461pub const AT = struct {
462 pub const FDCWD = -328243;
463 pub const SYMLINK_NOFOLLOW = 1;
464 pub const REMOVEDIR = 2;
465 pub const EACCESS = 4;
466 pub const SYMLINK_FOLLOW = 8;
467};
468
469pub const dirent = extern struct {421pub const dirent = extern struct {
470 d_fileno: c_ulong,422 fileno: c_ulong,
471 d_namlen: u16,423 namlen: u16,
472 d_type: u8,424 type: u8,
473 d_unused1: u8,425 unused1: u8,
474 d_unused2: u32,426 unused2: u32,
475 d_name: [256]u8,427 name: [256]u8,
476428
477 pub fn reclen(self: dirent) u16 {429 pub fn reclen(self: dirent) u16 {
478 return (@offsetOf(dirent, "d_name") + self.d_namlen + 1 + 7) & ~@as(u16, 7);430 return (@offsetOf(dirent, "name") + self.namlen + 1 + 7) & ~@as(u16, 7);
479 }431 }
480};432};
481433
lib/std/c/emscripten.zig+5-20
...@@ -3,7 +3,6 @@ const maxInt = std.math.maxInt;...@@ -3,7 +3,6 @@ const maxInt = std.math.maxInt;
3const emscripten = std.os.emscripten;3const emscripten = std.os.emscripten;
44
5pub const AF = emscripten.AF;5pub const AF = emscripten.AF;
6pub const AT = emscripten.AT;
7pub const CLOCK = emscripten.CLOCK;6pub const CLOCK = emscripten.CLOCK;
8pub const CPU_COUNT = emscripten.CPU_COUNT;7pub const CPU_COUNT = emscripten.CPU_COUNT;
9pub const E = emscripten.E;8pub const E = emscripten.E;
...@@ -19,7 +18,6 @@ pub const MADV = emscripten.MADV;...@@ -19,7 +18,6 @@ pub const MADV = emscripten.MADV;
19pub const MSF = emscripten.MSF;18pub const MSF = emscripten.MSF;
20pub const MSG = emscripten.MSG;19pub const MSG = emscripten.MSG;
21pub const NAME_MAX = emscripten.NAME_MAX;20pub const NAME_MAX = emscripten.NAME_MAX;
22pub const O = emscripten.O;
23pub const PATH_MAX = emscripten.PATH_MAX;21pub const PATH_MAX = emscripten.PATH_MAX;
24pub const POLL = emscripten.POLL;22pub const POLL = emscripten.POLL;
25pub const PROT = emscripten.PROT;23pub const PROT = emscripten.PROT;
...@@ -159,19 +157,6 @@ pub const pthread_attr_t = extern struct {...@@ -159,19 +157,6 @@ pub const pthread_attr_t = extern struct {
159 __align: c_long,157 __align: c_long,
160};158};
161159
162pub const pthread_mutex_t = extern struct {
163 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
164};
165pub const pthread_cond_t = extern struct {
166 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
167};
168pub const pthread_rwlock_t = extern struct {
169 size: [32]u8 align(4) = [_]u8{0} ** 32,
170};
171
172const __SIZEOF_PTHREAD_COND_T = 48;
173const __SIZEOF_PTHREAD_MUTEX_T = 24;
174
175pub const pthread_key_t = c_uint;160pub const pthread_key_t = c_uint;
176pub const sem_t = extern struct {161pub const sem_t = extern struct {
177 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),162 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
...@@ -189,9 +174,9 @@ pub const RTLD = struct {...@@ -189,9 +174,9 @@ pub const RTLD = struct {
189};174};
190175
191pub const dirent = struct {176pub const dirent = struct {
192 d_ino: c_uint,177 ino: c_uint,
193 d_off: c_uint,178 off: c_uint,
194 d_reclen: c_ushort,179 reclen: c_ushort,
195 d_type: u8,180 type: u8,
196 d_name: [256]u8,181 name: [256]u8,
197};182};
lib/std/c/freebsd.zig+9-70
...@@ -44,16 +44,6 @@ pub extern "c" fn sendfile(...@@ -44,16 +44,6 @@ pub extern "c" fn sendfile(
44pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int;44pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int;
45pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int;45pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int;
4646
47pub const pthread_mutex_t = extern struct {
48 inner: ?*anyopaque = null,
49};
50pub const pthread_cond_t = extern struct {
51 inner: ?*anyopaque = null,
52};
53pub const pthread_rwlock_t = extern struct {
54 ptr: ?*anyopaque = null,
55};
56
57pub const pthread_attr_t = extern struct {47pub const pthread_attr_t = extern struct {
58 inner: ?*anyopaque = null,48 inner: ?*anyopaque = null,
59};49};
...@@ -376,23 +366,19 @@ pub const timeval = extern struct {...@@ -376,23 +366,19 @@ pub const timeval = extern struct {
376366
377pub const dirent = extern struct {367pub const dirent = extern struct {
378 /// File number of entry.368 /// File number of entry.
379 d_fileno: ino_t,369 fileno: ino_t,
380 /// Directory offset of entry.370 /// Directory offset of entry.
381 d_off: off_t,371 off: off_t,
382 /// Length of this record.372 /// Length of this record.
383 d_reclen: u16,373 reclen: u16,
384 /// File type, one of DT_.374 /// File type, one of DT_.
385 d_type: u8,375 type: u8,
386 _d_pad0: u8,376 pad0: u8 = 0,
387 /// Length of the d_name member.377 /// Length of the name member.
388 d_namlen: u16,378 namlen: u16,
389 _d_pad1: u16,379 pad1: u16 = 0,
390 /// Name of entry.380 /// Name of entry.
391 d_name: [255:0]u8,381 name: [255:0]u8,
392
393 pub fn reclen(self: dirent) u16 {
394 return self.d_reclen;
395 }
396};382};
397383
398pub const in_port_t = u16;384pub const in_port_t = u16;
...@@ -746,36 +732,6 @@ pub const X_OK = 1; // test for execute or search permission...@@ -746,36 +732,6 @@ pub const X_OK = 1; // test for execute or search permission
746pub const W_OK = 2; // test for write permission732pub const W_OK = 2; // test for write permission
747pub const R_OK = 4; // test for read permission733pub const R_OK = 4; // test for read permission
748734
749pub const O = struct {
750 pub const RDONLY = 0x0000;
751 pub const WRONLY = 0x0001;
752 pub const RDWR = 0x0002;
753 pub const ACCMODE = 0x0003;
754
755 pub const SHLOCK = 0x0010;
756 pub const EXLOCK = 0x0020;
757
758 pub const CREAT = 0x0200;
759 pub const EXCL = 0x0800;
760 pub const NOCTTY = 0x8000;
761 pub const TRUNC = 0x0400;
762 pub const APPEND = 0x0008;
763 pub const NONBLOCK = 0x0004;
764 pub const DSYNC = 0o10000;
765 pub const SYNC = 0x0080;
766 pub const RSYNC = 0o4010000;
767 pub const DIRECTORY = 0x20000;
768 pub const NOFOLLOW = 0x0100;
769 pub const CLOEXEC = 0x00100000;
770
771 pub const ASYNC = 0x0040;
772 pub const DIRECT = 0x00010000;
773 pub const NOATIME = 0o1000000;
774 pub const PATH = 0o10000000;
775 pub const TMPFILE = 0o20200000;
776 pub const NDELAY = NONBLOCK;
777};
778
779/// Command flags for fcntl(2).735/// Command flags for fcntl(2).
780pub const F = struct {736pub const F = struct {
781 /// Duplicate file descriptor.737 /// Duplicate file descriptor.
...@@ -1573,23 +1529,6 @@ pub const S = struct {...@@ -1573,23 +1529,6 @@ pub const S = struct {
15731529
1574pub const HOST_NAME_MAX = 255;1530pub const HOST_NAME_MAX = 255;
15751531
1576pub const AT = struct {
1577 /// Magic value that specify the use of the current working directory
1578 /// to determine the target of relative file paths in the openat() and
1579 /// similar syscalls.
1580 pub const FDCWD = -100;
1581 /// Check access using effective user and group ID
1582 pub const EACCESS = 0x0100;
1583 /// Do not follow symbolic links
1584 pub const SYMLINK_NOFOLLOW = 0x0200;
1585 /// Follow symbolic link
1586 pub const SYMLINK_FOLLOW = 0x0400;
1587 /// Remove directory instead of file
1588 pub const REMOVEDIR = 0x0800;
1589 /// Fail if not under dirfd
1590 pub const BENEATH = 0x1000;
1591};
1592
1593pub const addrinfo = extern struct {1532pub const addrinfo = extern struct {
1594 flags: i32,1533 flags: i32,
1595 family: i32,1534 family: i32,
lib/std/c/fuchsia.zig deleted-11
...@@ -1,11 +0,0 @@
1pub const pthread_mutex_t = extern struct {
2 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
3};
4pub const pthread_cond_t = extern struct {
5 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
6};
7pub const pthread_rwlock_t = extern struct {
8 size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
9};
10const __SIZEOF_PTHREAD_COND_T = 48;
11const __SIZEOF_PTHREAD_MUTEX_T = 40;
lib/std/c/haiku.zig+6-60
...@@ -45,22 +45,6 @@ pub const pthread_attr_t = extern struct {...@@ -45,22 +45,6 @@ pub const pthread_attr_t = extern struct {
45 __stack_address: ?*anyopaque,45 __stack_address: ?*anyopaque,
46};46};
4747
48pub const pthread_mutex_t = extern struct {
49 flags: u32 = 0,
50 lock: i32 = 0,
51 unused: i32 = -42,
52 owner: i32 = -1,
53 owner_count: i32 = 0,
54};
55
56pub const pthread_cond_t = extern struct {
57 flags: u32 = 0,
58 unused: i32 = -42,
59 mutex: ?*anyopaque = null,
60 waiter_count: i32 = 0,
61 lock: i32 = 0,
62};
63
64pub const EAI = enum(c_int) {48pub const EAI = enum(c_int) {
65 /// address family for hostname not supported49 /// address family for hostname not supported
66 ADDRFAMILY = 1,50 ADDRFAMILY = 1,
...@@ -238,16 +222,12 @@ pub const timespec = extern struct {...@@ -238,16 +222,12 @@ pub const timespec = extern struct {
238};222};
239223
240pub const dirent = extern struct {224pub const dirent = extern struct {
241 d_dev: i32,225 dev: i32,
242 d_pdev: i32,226 pdev: i32,
243 d_ino: i64,227 ino: i64,
244 d_pino: i64,228 pino: i64,
245 d_reclen: u16,229 reclen: u16,
246 d_name: [256]u8,230 name: [256]u8,
247
248 pub fn reclen(self: dirent) u16 {
249 return self.d_reclen;
250 }
251};231};
252232
253pub const B_OS_NAME_LENGTH = 32; // OS.h233pub const B_OS_NAME_LENGTH = 32; // OS.h
...@@ -510,32 +490,6 @@ pub const X_OK = 1; // test for execute or search permission...@@ -510,32 +490,6 @@ pub const X_OK = 1; // test for execute or search permission
510pub const W_OK = 2; // test for write permission490pub const W_OK = 2; // test for write permission
511pub const R_OK = 4; // test for read permission491pub const R_OK = 4; // test for read permission
512492
513pub const O = struct {
514 pub const RDONLY = 0x0000;
515 pub const WRONLY = 0x0001;
516 pub const RDWR = 0x0002;
517 pub const ACCMODE = 0x0003;
518 pub const RWMASK = ACCMODE;
519
520 pub const EXCL = 0x0100;
521 pub const CREAT = 0x0200;
522 pub const TRUNC = 0x0400;
523 pub const NOCTTY = 0x1000;
524 pub const NOTRAVERSE = 0x2000;
525
526 pub const CLOEXEC = 0x00000040;
527 pub const NONBLOCK = 0x00000080;
528 pub const NDELAY = NONBLOCK;
529 pub const APPEND = 0x00000800;
530 pub const SYNC = 0x00010000;
531 pub const RSYNC = 0x00020000;
532 pub const DSYNC = 0x00040000;
533 pub const NOFOLLOW = 0x00080000;
534 pub const DIRECT = 0x00100000;
535 pub const NOCACHE = DIRECT;
536 pub const DIRECTORY = 0x00200000;
537};
538
539pub const F = struct {493pub const F = struct {
540 pub const DUPFD = 0x0001;494 pub const DUPFD = 0x0001;
541 pub const GETFD = 0x0002;495 pub const GETFD = 0x0002;
...@@ -923,14 +877,6 @@ pub const S = struct {...@@ -923,14 +877,6 @@ pub const S = struct {
923877
924pub const HOST_NAME_MAX = 255;878pub const HOST_NAME_MAX = 255;
925879
926pub const AT = struct {
927 pub const FDCWD = -1;
928 pub const SYMLINK_NOFOLLOW = 0x01;
929 pub const SYMLINK_FOLLOW = 0x02;
930 pub const REMOVEDIR = 0x04;
931 pub const EACCESS = 0x08;
932};
933
934pub const addrinfo = extern struct {880pub const addrinfo = extern struct {
935 flags: i32,881 flags: i32,
936 family: i32,882 family: i32,
lib/std/c/hermit.zig deleted-12
...@@ -1,12 +0,0 @@
1const std = @import("std");
2const maxInt = std.math.maxInt;
3
4pub const pthread_mutex_t = extern struct {
5 inner: usize = ~@as(usize, 0),
6};
7pub const pthread_cond_t = extern struct {
8 inner: usize = ~@as(usize, 0),
9};
10pub const pthread_rwlock_t = extern struct {
11 ptr: usize = maxInt(usize),
12};
lib/std/c/linux.zig+13-47
...@@ -9,7 +9,6 @@ const FILE = std.c.FILE;...@@ -9,7 +9,6 @@ const FILE = std.c.FILE;
99
10pub const AF = linux.AF;10pub const AF = linux.AF;
11pub const ARCH = linux.ARCH;11pub const ARCH = linux.ARCH;
12pub const AT = linux.AT;
13pub const CLOCK = linux.CLOCK;12pub const CLOCK = linux.CLOCK;
14pub const CPU_COUNT = linux.CPU_COUNT;13pub const CPU_COUNT = linux.CPU_COUNT;
15pub const E = linux.E;14pub const E = linux.E;
...@@ -28,7 +27,6 @@ pub const MSF = linux.MSF;...@@ -28,7 +27,6 @@ pub const MSF = linux.MSF;
28pub const MMAP2_UNIT = linux.MMAP2_UNIT;27pub const MMAP2_UNIT = linux.MMAP2_UNIT;
29pub const MSG = linux.MSG;28pub const MSG = linux.MSG;
30pub const NAME_MAX = linux.NAME_MAX;29pub const NAME_MAX = linux.NAME_MAX;
31pub const O = linux.O;
32pub const PATH_MAX = linux.PATH_MAX;30pub const PATH_MAX = linux.PATH_MAX;
33pub const POLL = linux.POLL;31pub const POLL = linux.POLL;
34pub const PROT = linux.PROT;32pub const PROT = linux.PROT;
...@@ -241,8 +239,8 @@ pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;...@@ -241,8 +239,8 @@ pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
241pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;239pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
242pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;240pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
243pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;241pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
244pub extern "c" fn open64(path: [*:0]const u8, oflag: c_uint, ...) c_int;242pub extern "c" fn open64(path: [*:0]const u8, oflag: linux.O, ...) c_int;
245pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;243pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: linux.O, ...) c_int;
246pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;244pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
247pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;245pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;
248pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize;246pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize;
...@@ -277,7 +275,7 @@ pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*an...@@ -277,7 +275,7 @@ pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*an
277pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;275pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
278276
279pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;277pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
280pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;278pub extern "c" fn pipe2(fds: *[2]fd_t, flags: linux.O) c_int;
281279
282pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;280pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
283281
...@@ -313,43 +311,11 @@ pub const pthread_attr_t = extern struct {...@@ -313,43 +311,11 @@ pub const pthread_attr_t = extern struct {
313 __align: c_long,311 __align: c_long,
314};312};
315313
316pub const pthread_mutex_t = extern struct {
317 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
318};
319pub const pthread_cond_t = extern struct {
320 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
321};
322pub const pthread_rwlock_t = switch (native_abi) {
323 .android => switch (@sizeOf(usize)) {
324 4 => extern struct {
325 size: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
326 },
327 8 => extern struct {
328 size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
329 },
330 else => @compileError("impossible pointer size"),
331 },
332 else => extern struct {
333 size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
334 },
335};
336pub const pthread_key_t = c_uint;314pub const pthread_key_t = c_uint;
337pub const sem_t = extern struct {315pub const sem_t = extern struct {
338 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),316 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
339};317};
340318
341const __SIZEOF_PTHREAD_COND_T = 48;
342const __SIZEOF_PTHREAD_MUTEX_T = switch (native_abi) {
343 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
344 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (native_arch) {
345 .aarch64 => 48,
346 .x86_64 => if (native_abi == .gnux32) 40 else 32,
347 .mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
348 else => if (@sizeOf(usize) == 8) 40 else 24,
349 },
350 .android => if (@sizeOf(usize) == 8) 40 else 4,
351 else => @compileError("unsupported ABI"),
352};
353const __SIZEOF_SEM_T = 4 * @sizeOf(usize);319const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
354320
355pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;321pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
...@@ -365,16 +331,16 @@ pub const RTLD = struct {...@@ -365,16 +331,16 @@ pub const RTLD = struct {
365};331};
366332
367pub const dirent = struct {333pub const dirent = struct {
368 d_ino: c_uint,334 ino: c_uint,
369 d_off: c_uint,335 off: c_uint,
370 d_reclen: c_ushort,336 reclen: c_ushort,
371 d_type: u8,337 type: u8,
372 d_name: [256]u8,338 name: [256]u8,
373};339};
374pub const dirent64 = struct {340pub const dirent64 = struct {
375 d_ino: c_ulong,341 ino: c_ulong,
376 d_off: c_ulong,342 off: c_ulong,
377 d_reclen: c_ushort,343 reclen: c_ushort,
378 d_type: u8,344 type: u8,
379 d_name: [256]u8,345 name: [256]u8,
380};346};
lib/std/c/minix.zig deleted-18
...@@ -1,18 +0,0 @@
1const builtin = @import("builtin");
2pub const pthread_mutex_t = extern struct {
3 size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
4};
5pub const pthread_cond_t = extern struct {
6 size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
7};
8const __SIZEOF_PTHREAD_COND_T = 48;
9const __SIZEOF_PTHREAD_MUTEX_T = switch (builtin.abi) {
10 .musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
11 .gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.cpu.arch) {
12 .aarch64 => 48,
13 .x86_64 => if (builtin.abi == .gnux32) 40 else 32,
14 .mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
15 else => if (@sizeOf(usize) == 8) 40 else 24,
16 },
17 else => unreachable,
18};
lib/std/c/netbsd.zig+5-109
...@@ -18,9 +18,6 @@ pub extern "c" fn _lwp_self() lwpid_t;...@@ -18,9 +18,6 @@ pub extern "c" fn _lwp_self() lwpid_t;
18pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;18pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
19pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;19pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
2020
21pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int;
22pub const fstat = __fstat50;
23
24pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int;21pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int;
25pub const stat = __stat50;22pub const stat = __stat50;
2623
...@@ -62,41 +59,6 @@ pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: u...@@ -62,41 +59,6 @@ pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: u
62pub extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;59pub extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;
63pub const msync = __msync13;60pub const msync = __msync13;
6461
65pub const pthread_mutex_t = extern struct {
66 magic: u32 = 0x33330003,
67 errorcheck: padded_pthread_spin_t = 0,
68 ceiling: padded_pthread_spin_t = 0,
69 owner: usize = 0,
70 waiters: ?*u8 = null,
71 recursed: u32 = 0,
72 spare2: ?*anyopaque = null,
73};
74
75pub const pthread_cond_t = extern struct {
76 magic: u32 = 0x55550005,
77 lock: pthread_spin_t = 0,
78 waiters_first: ?*u8 = null,
79 waiters_last: ?*u8 = null,
80 mutex: ?*pthread_mutex_t = null,
81 private: ?*anyopaque = null,
82};
83
84pub const pthread_rwlock_t = extern struct {
85 magic: c_uint = 0x99990009,
86 interlock: switch (builtin.cpu.arch) {
87 .aarch64, .sparc, .x86_64, .x86 => u8,
88 .arm, .powerpc => c_int,
89 else => unreachable,
90 } = 0,
91 rblocked_first: ?*u8 = null,
92 rblocked_last: ?*u8 = null,
93 wblocked_first: ?*u8 = null,
94 wblocked_last: ?*u8 = null,
95 nreaders: c_uint = 0,
96 owner: ?std.c.pthread_t = null,
97 private: ?*anyopaque = null,
98};
99
100const pthread_spin_t = switch (builtin.cpu.arch) {62const pthread_spin_t = switch (builtin.cpu.arch) {
101 .aarch64, .aarch64_be, .aarch64_32 => u8,63 .aarch64, .aarch64_be, .aarch64_32 => u8,
102 .mips, .mipsel, .mips64, .mips64el => u32,64 .mips, .mipsel, .mips64, .mips64el => u32,
...@@ -337,15 +299,11 @@ pub const timeval = extern struct {...@@ -337,15 +299,11 @@ pub const timeval = extern struct {
337pub const MAXNAMLEN = 511;299pub const MAXNAMLEN = 511;
338300
339pub const dirent = extern struct {301pub const dirent = extern struct {
340 d_fileno: ino_t,302 fileno: ino_t,
341 d_reclen: u16,303 reclen: u16,
342 d_namlen: u16,304 namlen: u16,
343 d_type: u8,305 type: u8,
344 d_name: [MAXNAMLEN + 1]u8,306 name: [MAXNAMLEN + 1]u8,
345
346 pub fn reclen(self: dirent) u16 {
347 return self.d_reclen;
348 }
349};307};
350308
351pub const SOCK = struct {309pub const SOCK = struct {
...@@ -630,53 +588,6 @@ pub const X_OK = 1; // test for execute or search permission...@@ -630,53 +588,6 @@ pub const X_OK = 1; // test for execute or search permission
630pub const W_OK = 2; // test for write permission588pub const W_OK = 2; // test for write permission
631pub const R_OK = 4; // test for read permission589pub const R_OK = 4; // test for read permission
632590
633pub const O = struct {
634 /// open for reading only
635 pub const RDONLY = 0x00000000;
636 /// open for writing only
637 pub const WRONLY = 0x00000001;
638 /// open for reading and writing
639 pub const RDWR = 0x00000002;
640 /// mask for above modes
641 pub const ACCMODE = 0x00000003;
642 /// no delay
643 pub const NONBLOCK = 0x00000004;
644 /// set append mode
645 pub const APPEND = 0x00000008;
646 /// open with shared file lock
647 pub const SHLOCK = 0x00000010;
648 /// open with exclusive file lock
649 pub const EXLOCK = 0x00000020;
650 /// signal pgrp when data ready
651 pub const ASYNC = 0x00000040;
652 /// synchronous writes
653 pub const SYNC = 0x00000080;
654 /// don't follow symlinks on the last
655 pub const NOFOLLOW = 0x00000100;
656 /// create if nonexistent
657 pub const CREAT = 0x00000200;
658 /// truncate to zero length
659 pub const TRUNC = 0x00000400;
660 /// error if already exists
661 pub const EXCL = 0x00000800;
662 /// don't assign controlling terminal
663 pub const NOCTTY = 0x00008000;
664 /// write: I/O data completion
665 pub const DSYNC = 0x00010000;
666 /// read: I/O completion as for write
667 pub const RSYNC = 0x00020000;
668 /// use alternate i/o semantics
669 pub const ALT_IO = 0x00040000;
670 /// direct I/O hint
671 pub const DIRECT = 0x00080000;
672 /// fail if not a directory
673 pub const DIRECTORY = 0x00200000;
674 /// set close on exec
675 pub const CLOEXEC = 0x00400000;
676 /// skip search permission checks
677 pub const SEARCH = 0x00800000;
678};
679
680pub const F = struct {591pub const F = struct {
681 pub const DUPFD = 0;592 pub const DUPFD = 0;
682 pub const GETFD = 1;593 pub const GETFD = 1;
...@@ -1466,21 +1377,6 @@ pub const S = struct {...@@ -1466,21 +1377,6 @@ pub const S = struct {
1466 }1377 }
1467};1378};
14681379
1469pub const AT = struct {
1470 /// Magic value that specify the use of the current working directory
1471 /// to determine the target of relative file paths in the openat() and
1472 /// similar syscalls.
1473 pub const FDCWD = -100;
1474 /// Check access using effective user and group ID
1475 pub const EACCESS = 0x0100;
1476 /// Do not follow symbolic links
1477 pub const SYMLINK_NOFOLLOW = 0x0200;
1478 /// Follow symbolic link
1479 pub const SYMLINK_FOLLOW = 0x0400;
1480 /// Remove directory instead of file
1481 pub const REMOVEDIR = 0x0800;
1482};
1483
1484pub const HOST_NAME_MAX = 255;1380pub const HOST_NAME_MAX = 255;
14851381
1486pub const IPPROTO = struct {1382pub const IPPROTO = struct {
lib/std/c/openbsd.zig+7-76
...@@ -19,15 +19,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;...@@ -19,15 +19,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
19pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;19pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
20pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;20pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
2121
22pub const pthread_mutex_t = extern struct {
23 inner: ?*anyopaque = null,
24};
25pub const pthread_cond_t = extern struct {
26 inner: ?*anyopaque = null,
27};
28pub const pthread_rwlock_t = extern struct {
29 ptr: ?*anyopaque = null,
30};
31pub const pthread_spinlock_t = extern struct {22pub const pthread_spinlock_t = extern struct {
32 inner: ?*anyopaque = null,23 inner: ?*anyopaque = null,
33};24};
...@@ -336,17 +327,13 @@ pub const timezone = extern struct {...@@ -336,17 +327,13 @@ pub const timezone = extern struct {
336pub const MAXNAMLEN = 255;327pub const MAXNAMLEN = 255;
337328
338pub const dirent = extern struct {329pub const dirent = extern struct {
339 d_fileno: ino_t,330 fileno: ino_t,
340 d_off: off_t,331 off: off_t,
341 d_reclen: u16,332 reclen: u16,
342 d_type: u8,333 type: u8,
343 d_namlen: u8,334 namlen: u8,
344 __d_padding: [4]u8,335 _: u32 align(1) = 0,
345 d_name: [MAXNAMLEN + 1]u8,336 name: [MAXNAMLEN + 1]u8,
346
347 pub fn reclen(self: dirent) u16 {
348 return self.d_reclen;
349 }
350};337};
351338
352pub const in_port_t = u16;339pub const in_port_t = u16;
...@@ -489,47 +476,6 @@ pub const X_OK = 1; // test for execute or search permission...@@ -489,47 +476,6 @@ pub const X_OK = 1; // test for execute or search permission
489pub const W_OK = 2; // test for write permission476pub const W_OK = 2; // test for write permission
490pub const R_OK = 4; // test for read permission477pub const R_OK = 4; // test for read permission
491478
492pub const O = struct {
493 /// open for reading only
494 pub const RDONLY = 0x00000000;
495 /// open for writing only
496 pub const WRONLY = 0x00000001;
497 /// open for reading and writing
498 pub const RDWR = 0x00000002;
499 /// mask for above modes
500 pub const ACCMODE = 0x00000003;
501 /// no delay
502 pub const NONBLOCK = 0x00000004;
503 /// set append mode
504 pub const APPEND = 0x00000008;
505 /// open with shared file lock
506 pub const SHLOCK = 0x00000010;
507 /// open with exclusive file lock
508 pub const EXLOCK = 0x00000020;
509 /// signal pgrp when data ready
510 pub const ASYNC = 0x00000040;
511 /// synchronous writes
512 pub const SYNC = 0x00000080;
513 /// don't follow symlinks on the last
514 pub const NOFOLLOW = 0x00000100;
515 /// create if nonexistent
516 pub const CREAT = 0x00000200;
517 /// truncate to zero length
518 pub const TRUNC = 0x00000400;
519 /// error if already exists
520 pub const EXCL = 0x00000800;
521 /// don't assign controlling terminal
522 pub const NOCTTY = 0x00008000;
523 /// write: I/O data completion
524 pub const DSYNC = SYNC;
525 /// read: I/O completion as for write
526 pub const RSYNC = SYNC;
527 /// fail if not a directory
528 pub const DIRECTORY = 0x20000;
529 /// set close on exec
530 pub const CLOEXEC = 0x10000;
531};
532
533pub const F = struct {479pub const F = struct {
534 pub const DUPFD = 0;480 pub const DUPFD = 0;
535 pub const GETFD = 1;481 pub const GETFD = 1;
...@@ -1312,21 +1258,6 @@ pub const S = struct {...@@ -1312,21 +1258,6 @@ pub const S = struct {
1312 }1258 }
1313};1259};
13141260
1315pub const AT = struct {
1316 /// Magic value that specify the use of the current working directory
1317 /// to determine the target of relative file paths in the openat() and
1318 /// similar syscalls.
1319 pub const FDCWD = -100;
1320 /// Check access using effective user and group ID
1321 pub const EACCESS = 0x01;
1322 /// Do not follow symbolic links
1323 pub const SYMLINK_NOFOLLOW = 0x02;
1324 /// Follow symbolic link
1325 pub const SYMLINK_FOLLOW = 0x04;
1326 /// Remove directory instead of file
1327 pub const REMOVEDIR = 0x08;
1328};
1329
1330pub const HOST_NAME_MAX = 255;1261pub const HOST_NAME_MAX = 255;
13311262
1332pub const IPPROTO = struct {1263pub const IPPROTO = struct {
lib/std/c/solaris.zig+4-74
...@@ -21,29 +21,6 @@ pub extern "c" fn sysconf(sc: c_int) i64;...@@ -21,29 +21,6 @@ pub extern "c" fn sysconf(sc: c_int) i64;
21pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;21pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;
22pub extern "c" fn madvise(address: [*]u8, len: usize, advise: u32) c_int;22pub extern "c" fn madvise(address: [*]u8, len: usize, advise: u32) c_int;
2323
24pub const pthread_mutex_t = extern struct {
25 flag1: u16 = 0,
26 flag2: u8 = 0,
27 ceiling: u8 = 0,
28 type: u16 = 0,
29 magic: u16 = 0x4d58,
30 lock: u64 = 0,
31 data: u64 = 0,
32};
33pub const pthread_cond_t = extern struct {
34 flag: [4]u8 = [_]u8{0} ** 4,
35 type: u16 = 0,
36 magic: u16 = 0x4356,
37 data: u64 = 0,
38};
39pub const pthread_rwlock_t = extern struct {
40 readers: i32 = 0,
41 type: u16 = 0,
42 magic: u16 = 0x5257,
43 mutex: pthread_mutex_t = .{},
44 readercv: pthread_cond_t = .{},
45 writercv: pthread_cond_t = .{},
46};
47pub const pthread_attr_t = extern struct {24pub const pthread_attr_t = extern struct {
48 mutexattr: ?*anyopaque = null,25 mutexattr: ?*anyopaque = null,
49};26};
...@@ -266,17 +243,13 @@ pub const MAXNAMLEN = 511;...@@ -266,17 +243,13 @@ pub const MAXNAMLEN = 511;
266243
267pub const dirent = extern struct {244pub const dirent = extern struct {
268 /// Inode number of entry.245 /// Inode number of entry.
269 d_ino: ino_t,246 ino: ino_t,
270 /// Offset of this entry on disk.247 /// Offset of this entry on disk.
271 d_off: off_t,248 off: off_t,
272 /// Length of this record.249 /// Length of this record.
273 d_reclen: u16,250 reclen: u16,
274 /// File name.251 /// File name.
275 d_name: [MAXNAMLEN:0]u8,252 name: [MAXNAMLEN:0]u8,
276
277 pub fn reclen(self: dirent) u16 {
278 return self.d_reclen;
279 }
280};253};
281254
282pub const SOCK = struct {255pub const SOCK = struct {
...@@ -708,32 +681,6 @@ pub const F = struct {...@@ -708,32 +681,6 @@ pub const F = struct {
708 pub const RMDNY = 0x4;681 pub const RMDNY = 0x4;
709};682};
710683
711pub const O = struct {
712 pub const RDONLY = 0;
713 pub const WRONLY = 1;
714 pub const RDWR = 2;
715 pub const SEARCH = 0x200000;
716 pub const EXEC = 0x400000;
717 pub const NDELAY = 0x04;
718 pub const APPEND = 0x08;
719 pub const SYNC = 0x10;
720 pub const DSYNC = 0x40;
721 pub const RSYNC = 0x8000;
722 pub const NONBLOCK = 0x80;
723 pub const LARGEFILE = 0x2000;
724
725 pub const CREAT = 0x100;
726 pub const TRUNC = 0x200;
727 pub const EXCL = 0x400;
728 pub const NOCTTY = 0x800;
729 pub const XATTR = 0x4000;
730 pub const NOFOLLOW = 0x20000;
731 pub const NOLINKS = 0x40000;
732 pub const CLOEXEC = 0x800000;
733 pub const DIRECTORY = 0x1000000;
734 pub const DIRECT = 0x2000000;
735};
736
737pub const LOCK = struct {684pub const LOCK = struct {
738 pub const SH = 1;685 pub const SH = 1;
739 pub const EX = 2;686 pub const EX = 2;
...@@ -1430,23 +1377,6 @@ pub const S = struct {...@@ -1430,23 +1377,6 @@ pub const S = struct {
1430 }1377 }
1431};1378};
14321379
1433pub const AT = struct {
1434 /// Magic value that specify the use of the current working directory
1435 /// to determine the target of relative file paths in the openat() and
1436 /// similar syscalls.
1437 pub const FDCWD = @as(fd_t, @bitCast(@as(u32, 0xffd19553)));
1438
1439 /// Do not follow symbolic links
1440 pub const SYMLINK_NOFOLLOW = 0x1000;
1441 /// Follow symbolic link
1442 pub const SYMLINK_FOLLOW = 0x2000;
1443 /// Remove directory instead of file
1444 pub const REMOVEDIR = 0x1;
1445 pub const TRIGGER = 0x2;
1446 /// Check access using effective user and group ID
1447 pub const EACCESS = 0x4;
1448};
1449
1450pub const POSIX_FADV = struct {1380pub const POSIX_FADV = struct {
1451 pub const NORMAL = 0;1381 pub const NORMAL = 0;
1452 pub const RANDOM = 1;1382 pub const RANDOM = 1;
lib/std/c/wasi.zig+90-45
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const builtin = @import("builtin");
1const std = @import("../std.zig");2const std = @import("../std.zig");
2const wasi = std.os.wasi;3const wasi = std.os.wasi;
3const FDFLAG = wasi.FDFLAG;
44
5extern threadlocal var errno: c_int;5extern threadlocal var errno: c_int;
66
...@@ -8,42 +8,82 @@ pub fn _errno() *c_int {...@@ -8,42 +8,82 @@ pub fn _errno() *c_int {
8 return &errno;8 return &errno;
9}9}
1010
11pub const AT = wasi.AT;11pub const mode_t = u32;
12pub const CLOCK = wasi.CLOCK;12pub const time_t = i64;
13pub const E = wasi.E;13
14pub const IOV_MAX = wasi.IOV_MAX;14pub const timespec = extern struct {
15pub const LOCK = wasi.LOCK;15 tv_sec: time_t,
16pub const S = wasi.S;16 tv_nsec: isize,
17pub const STDERR_FILENO = wasi.STDERR_FILENO;17
18pub const STDIN_FILENO = wasi.STDIN_FILENO;18 pub fn fromTimestamp(tm: wasi.timestamp_t) timespec {
19pub const STDOUT_FILENO = wasi.STDOUT_FILENO;19 const tv_sec: wasi.timestamp_t = tm / 1_000_000_000;
20 const tv_nsec = tm - tv_sec * 1_000_000_000;
21 return .{
22 .tv_sec = @as(time_t, @intCast(tv_sec)),
23 .tv_nsec = @as(isize, @intCast(tv_nsec)),
24 };
25 }
26
27 pub fn toTimestamp(ts: timespec) wasi.timestamp_t {
28 return @as(wasi.timestamp_t, @intCast(ts.tv_sec * 1_000_000_000)) +
29 @as(wasi.timestamp_t, @intCast(ts.tv_nsec));
30 }
31};
32
33pub const STDIN_FILENO = 0;
34pub const STDOUT_FILENO = 1;
35pub const STDERR_FILENO = 2;
36
37pub const E = wasi.errno_t;
38
39pub const CLOCK = wasi.clockid_t;
40pub const IOV_MAX = 1024;
41pub const LOCK = struct {
42 pub const SH = 0x1;
43 pub const EX = 0x2;
44 pub const NB = 0x4;
45 pub const UN = 0x8;
46};
47pub const S = struct {
48 pub const IEXEC = @compileError("TODO audit this");
49 pub const IFBLK = 0x6000;
50 pub const IFCHR = 0x2000;
51 pub const IFDIR = 0x4000;
52 pub const IFIFO = 0xc000;
53 pub const IFLNK = 0xa000;
54 pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
55 pub const IFREG = 0x8000;
56 /// There's no concept of UNIX domain socket but we define this value here
57 /// in order to line with other OSes.
58 pub const IFSOCK = 0x1;
59};
20pub const fd_t = wasi.fd_t;60pub const fd_t = wasi.fd_t;
21pub const pid_t = c_int;61pub const pid_t = c_int;
22pub const uid_t = u32;62pub const uid_t = u32;
23pub const gid_t = u32;63pub const gid_t = u32;
24pub const off_t = i64;64pub const off_t = i64;
25pub const ino_t = wasi.ino_t;65pub const ino_t = wasi.inode_t;
26pub const mode_t = wasi.mode_t;66pub const dev_t = wasi.device_t;
27pub const time_t = wasi.time_t;67pub const nlink_t = c_ulonglong;
28pub const timespec = wasi.timespec;68pub const blksize_t = c_long;
69pub const blkcnt_t = c_longlong;
2970
30pub const Stat = extern struct {71pub const Stat = extern struct {
31 dev: i32,72 dev: dev_t,
32 ino: ino_t,73 ino: ino_t,
33 nlink: u64,74 nlink: nlink_t,
34
35 mode: mode_t,75 mode: mode_t,
36 uid: uid_t,76 uid: uid_t,
37 gid: gid_t,77 gid: gid_t,
38 __pad0: isize,78 __pad0: c_uint = 0,
39 rdev: i32,79 rdev: dev_t,
40 size: off_t,80 size: off_t,
41 blksize: i32,81 blksize: blksize_t,
42 blocks: i64,82 blocks: blkcnt_t,
43
44 atim: timespec,83 atim: timespec,
45 mtim: timespec,84 mtim: timespec,
46 ctim: timespec,85 ctim: timespec,
86 __reserved: [3]c_longlong = [3]c_longlong{ 0, 0, 0 },
4787
48 pub fn atime(self: @This()) timespec {88 pub fn atime(self: @This()) timespec {
49 return self.atim;89 return self.atim;
...@@ -56,30 +96,35 @@ pub const Stat = extern struct {...@@ -56,30 +96,35 @@ pub const Stat = extern struct {
56 pub fn ctime(self: @This()) timespec {96 pub fn ctime(self: @This()) timespec {
57 return self.ctim;97 return self.ctim;
58 }98 }
59};
6099
61/// Derived from100 pub fn fromFilestat(stat: wasi.filestat_t) Stat {
62/// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt101 return .{
63pub const O = struct {102 .dev = stat.dev,
64 pub const ACCMODE = (EXEC | RDWR | SEARCH);103 .ino = stat.ino,
65 pub const APPEND = @as(u32, FDFLAG.APPEND);104 .mode = switch (stat.filetype) {
66 pub const CLOEXEC = (0);105 .UNKNOWN => 0,
67 pub const CREAT = ((1 << 0) << 12); // = __WASI_OFLAGS_CREAT << 12106 .BLOCK_DEVICE => S.IFBLK,
68 pub const DIRECTORY = ((1 << 1) << 12); // = __WASI_OFLAGS_DIRECTORY << 12107 .CHARACTER_DEVICE => S.IFCHR,
69 pub const DSYNC = @as(u32, FDFLAG.DSYNC);108 .DIRECTORY => S.IFDIR,
70 pub const EXCL = ((1 << 2) << 12); // = __WASI_OFLAGS_EXCL << 12109 .REGULAR_FILE => S.IFREG,
71 pub const EXEC = (0x02000000);110 .SOCKET_DGRAM => S.IFSOCK,
72 pub const NOCTTY = (0);111 .SOCKET_STREAM => S.IFIFO,
73 pub const NOFOLLOW = (0x01000000);112 .SYMBOLIC_LINK => S.IFLNK,
74 pub const NONBLOCK = @as(u32, FDFLAG.NONBLOCK);113 _ => 0,
75 pub const RDONLY = (0x04000000);114 },
76 pub const RDWR = (RDONLY | WRONLY);115 .nlink = stat.nlink,
77 pub const RSYNC = @as(u32, FDFLAG.RSYNC);116 .size = @intCast(stat.size),
78 pub const SEARCH = (0x08000000);117 .atim = timespec.fromTimestamp(stat.atim),
79 pub const SYNC = @as(u32, FDFLAG.SYNC);118 .mtim = timespec.fromTimestamp(stat.mtim),
80 pub const TRUNC = ((1 << 3) << 12); // = __WASI_OFLAGS_TRUNC << 12119 .ctim = timespec.fromTimestamp(stat.ctim),
81 pub const TTY_INIT = (0);120
82 pub const WRONLY = (0x10000000);121 .uid = 0,
122 .gid = 0,
123 .rdev = 0,
124 .blksize = 0,
125 .blocks = 0,
126 };
127 }
83};128};
84129
85pub const F = struct {130pub const F = struct {
lib/std/c/windows.zig-33
...@@ -11,7 +11,6 @@ pub extern "c" fn _msize(memblock: ?*anyopaque) usize;...@@ -11,7 +11,6 @@ pub extern "c" fn _msize(memblock: ?*anyopaque) usize;
11// need to verify which of these is actually supported on windows11// need to verify which of these is actually supported on windows
12pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;12pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
13pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;13pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
14pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
15pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;14pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
16pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;15pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
17pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;16pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
...@@ -200,11 +199,6 @@ pub const STRUNCATE = 80;...@@ -200,11 +199,6 @@ pub const STRUNCATE = 80;
200199
201pub const F_OK = 0;200pub const F_OK = 0;
202201
203/// Remove directory instead of unlinking file
204pub const AT = struct {
205 pub const REMOVEDIR = 0x200;
206};
207
208pub const in_port_t = u16;202pub const in_port_t = u16;
209pub const sa_family_t = ws2_32.ADDRESS_FAMILY;203pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
210pub const socklen_t = ws2_32.socklen_t;204pub const socklen_t = ws2_32.socklen_t;
...@@ -229,31 +223,4 @@ pub const SOL = ws2_32.SOL;...@@ -229,31 +223,4 @@ pub const SOL = ws2_32.SOL;
229pub const SO = ws2_32.SO;223pub const SO = ws2_32.SO;
230pub const PVD_CONFIG = ws2_32.PVD_CONFIG;224pub const PVD_CONFIG = ws2_32.PVD_CONFIG;
231225
232pub const O = struct {
233 pub const RDONLY = 0o0;
234 pub const WRONLY = 0o1;
235 pub const RDWR = 0o2;
236
237 pub const CREAT = 0o100;
238 pub const EXCL = 0o200;
239 pub const NOCTTY = 0o400;
240 pub const TRUNC = 0o1000;
241 pub const APPEND = 0o2000;
242 pub const NONBLOCK = 0o4000;
243 pub const DSYNC = 0o10000;
244 pub const SYNC = 0o4010000;
245 pub const RSYNC = 0o4010000;
246 pub const DIRECTORY = 0o200000;
247 pub const NOFOLLOW = 0o400000;
248 pub const CLOEXEC = 0o2000000;
249
250 pub const ASYNC = 0o20000;
251 pub const DIRECT = 0o40000;
252 pub const LARGEFILE = 0;
253 pub const NOATIME = 0o1000000;
254 pub const PATH = 0o10000000;
255 pub const TMPFILE = 0o20200000;
256 pub const NDELAY = NONBLOCK;
257};
258
259pub const IFNAMESIZE = 30;226pub const IFNAMESIZE = 30;
lib/std/child_process.zig+3-3
...@@ -495,7 +495,7 @@ pub const ChildProcess = struct {...@@ -495,7 +495,7 @@ pub const ChildProcess = struct {
495 }495 }
496496
497 fn spawnPosix(self: *ChildProcess) SpawnError!void {497 fn spawnPosix(self: *ChildProcess) SpawnError!void {
498 const pipe_flags = 0;498 const pipe_flags: os.O = .{};
499 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;499 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
500 errdefer if (self.stdin_behavior == StdIo.Pipe) {500 errdefer if (self.stdin_behavior == StdIo.Pipe) {
501 destroyPipe(stdin_pipe);501 destroyPipe(stdin_pipe);
...@@ -513,7 +513,7 @@ pub const ChildProcess = struct {...@@ -513,7 +513,7 @@ pub const ChildProcess = struct {
513513
514 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);514 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
515 const dev_null_fd = if (any_ignore)515 const dev_null_fd = if (any_ignore)
516 os.openZ("/dev/null", os.O.RDWR, 0) catch |err| switch (err) {516 os.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) {
517 error.PathAlreadyExists => unreachable,517 error.PathAlreadyExists => unreachable,
518 error.NoSpaceLeft => unreachable,518 error.NoSpaceLeft => unreachable,
519 error.FileTooBig => unreachable,519 error.FileTooBig => unreachable,
...@@ -572,7 +572,7 @@ pub const ChildProcess = struct {...@@ -572,7 +572,7 @@ pub const ChildProcess = struct {
572 // end with eventfd572 // end with eventfd
573 break :blk [2]os.fd_t{ fd, fd };573 break :blk [2]os.fd_t{ fd, fd };
574 } else {574 } else {
575 break :blk try os.pipe2(os.O.CLOEXEC);575 break :blk try os.pipe2(.{ .CLOEXEC = true });
576 }576 }
577 };577 };
578 errdefer destroyPipe(err_pipe);578 errdefer destroyPipe(err_pipe);
lib/std/compress/deflate/deflate_fast.zig+8
...@@ -354,6 +354,10 @@ pub const DeflateFast = struct {...@@ -354,6 +354,10 @@ pub const DeflateFast = struct {
354};354};
355355
356test "best speed match 1/3" {356test "best speed match 1/3" {
357 if (@import("builtin").os.tag == .wasi) {
358 // https://github.com/ziglang/zig/issues/18885
359 return error.SkipZigTest;
360 }
357 const expectEqual = std.testing.expectEqual;361 const expectEqual = std.testing.expectEqual;
358362
359 {363 {
...@@ -450,6 +454,10 @@ test "best speed match 1/3" {...@@ -450,6 +454,10 @@ test "best speed match 1/3" {
450}454}
451455
452test "best speed match 2/3" {456test "best speed match 2/3" {
457 if (@import("builtin").os.tag == .wasi) {
458 // https://github.com/ziglang/zig/issues/18885
459 return error.SkipZigTest;
460 }
453 const expectEqual = std.testing.expectEqual;461 const expectEqual = std.testing.expectEqual;
454462
455 {463 {
lib/std/dynamic_library.zig+1-1
...@@ -115,7 +115,7 @@ pub const ElfDynLib = struct {...@@ -115,7 +115,7 @@ pub const ElfDynLib = struct {
115115
116 /// Trusts the file. Malicious file will be able to execute arbitrary code.116 /// Trusts the file. Malicious file will be able to execute arbitrary code.
117 pub fn open(path: []const u8) !ElfDynLib {117 pub fn open(path: []const u8) !ElfDynLib {
118 const fd = try os.open(path, 0, os.O.RDONLY | os.O.CLOEXEC);118 const fd = try os.open(path, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
119 defer os.close(fd);119 defer os.close(fd);
120120
121 const stat = try os.fstat(fd);121 const stat = try os.fstat(fd);
lib/std/fs/Dir.zig+239-224
...@@ -62,16 +62,16 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -62,16 +62,16 @@ pub const Iterator = switch (builtin.os.tag) {
62 self.end_index = @as(usize, @intCast(rc));62 self.end_index = @as(usize, @intCast(rc));
63 }63 }
64 const darwin_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));64 const darwin_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
65 const next_index = self.index + darwin_entry.reclen();65 const next_index = self.index + darwin_entry.reclen;
66 self.index = next_index;66 self.index = next_index;
6767
68 const name = @as([*]u8, @ptrCast(&darwin_entry.d_name))[0..darwin_entry.d_namlen];68 const name = @as([*]u8, @ptrCast(&darwin_entry.name))[0..darwin_entry.namlen];
6969
70 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (darwin_entry.d_ino == 0)) {70 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (darwin_entry.ino == 0)) {
71 continue :start_over;71 continue :start_over;
72 }72 }
7373
74 const entry_kind: Entry.Kind = switch (darwin_entry.d_type) {74 const entry_kind: Entry.Kind = switch (darwin_entry.type) {
75 posix.DT.BLK => .block_device,75 posix.DT.BLK => .block_device,
76 posix.DT.CHR => .character_device,76 posix.DT.CHR => .character_device,
77 posix.DT.DIR => .directory,77 posix.DT.DIR => .directory,
...@@ -110,14 +110,14 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -110,14 +110,14 @@ pub const Iterator = switch (builtin.os.tag) {
110 self.end_index = @as(usize, @intCast(rc));110 self.end_index = @as(usize, @intCast(rc));
111 }111 }
112 const entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));112 const entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
113 const next_index = self.index + entry.reclen();113 const next_index = self.index + entry.reclen;
114 self.index = next_index;114 self.index = next_index;
115115
116 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&entry.d_name)), 0);116 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&entry.name)), 0);
117 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))117 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
118 continue :start_over;118 continue :start_over;
119119
120 // Solaris dirent doesn't expose d_type, so we have to call stat to get it.120 // Solaris dirent doesn't expose type, so we have to call stat to get it.
121 const stat_info = posix.fstatat(121 const stat_info = posix.fstatat(
122 self.dir.fd,122 self.dir.fd,
123 name,123 name,
...@@ -174,23 +174,23 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -174,23 +174,23 @@ pub const Iterator = switch (builtin.os.tag) {
174 self.end_index = @as(usize, @intCast(rc));174 self.end_index = @as(usize, @intCast(rc));
175 }175 }
176 const bsd_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));176 const bsd_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
177 const next_index = self.index + bsd_entry.reclen();177 const next_index = self.index + bsd_entry.reclen;
178 self.index = next_index;178 self.index = next_index;
179179
180 const name = @as([*]u8, @ptrCast(&bsd_entry.d_name))[0..bsd_entry.d_namlen];180 const name = @as([*]u8, @ptrCast(&bsd_entry.name))[0..bsd_entry.namlen];
181181
182 const skip_zero_fileno = switch (builtin.os.tag) {182 const skip_zero_fileno = switch (builtin.os.tag) {
183 // d_fileno=0 is used to mark invalid entries or deleted files.183 // fileno=0 is used to mark invalid entries or deleted files.
184 .openbsd, .netbsd => true,184 .openbsd, .netbsd => true,
185 else => false,185 else => false,
186 };186 };
187 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or187 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or
188 (skip_zero_fileno and bsd_entry.d_fileno == 0))188 (skip_zero_fileno and bsd_entry.fileno == 0))
189 {189 {
190 continue :start_over;190 continue :start_over;
191 }191 }
192192
193 const entry_kind: Entry.Kind = switch (bsd_entry.d_type) {193 const entry_kind: Entry.Kind = switch (bsd_entry.type) {
194 posix.DT.BLK => .block_device,194 posix.DT.BLK => .block_device,
195 posix.DT.CHR => .character_device,195 posix.DT.CHR => .character_device,
196 posix.DT.DIR => .directory,196 posix.DT.DIR => .directory,
...@@ -256,18 +256,18 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -256,18 +256,18 @@ pub const Iterator = switch (builtin.os.tag) {
256 self.end_index = @as(usize, @intCast(rc));256 self.end_index = @as(usize, @intCast(rc));
257 }257 }
258 const haiku_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));258 const haiku_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
259 const next_index = self.index + haiku_entry.reclen();259 const next_index = self.index + haiku_entry.reclen;
260 self.index = next_index;260 self.index = next_index;
261 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&haiku_entry.d_name)), 0);261 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&haiku_entry.name)), 0);
262262
263 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (haiku_entry.d_ino == 0)) {263 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (haiku_entry.ino == 0)) {
264 continue :start_over;264 continue :start_over;
265 }265 }
266266
267 var stat_info: posix.Stat = undefined;267 var stat_info: posix.Stat = undefined;
268 const rc = posix.system._kern_read_stat(268 const rc = posix.system._kern_read_stat(
269 self.dir.fd,269 self.dir.fd,
270 &haiku_entry.d_name,270 &haiku_entry.name,
271 false,271 false,
272 &stat_info,272 &stat_info,
273 0,273 0,
...@@ -359,17 +359,17 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -359,17 +359,17 @@ pub const Iterator = switch (builtin.os.tag) {
359 self.end_index = rc;359 self.end_index = rc;
360 }360 }
361 const linux_entry = @as(*align(1) linux.dirent64, @ptrCast(&self.buf[self.index]));361 const linux_entry = @as(*align(1) linux.dirent64, @ptrCast(&self.buf[self.index]));
362 const next_index = self.index + linux_entry.reclen();362 const next_index = self.index + linux_entry.reclen;
363 self.index = next_index;363 self.index = next_index;
364364
365 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&linux_entry.d_name)), 0);365 const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&linux_entry.name)), 0);
366366
367 // skip . and .. entries367 // skip . and .. entries
368 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {368 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
369 continue :start_over;369 continue :start_over;
370 }370 }
371371
372 const entry_kind: Entry.Kind = switch (linux_entry.d_type) {372 const entry_kind: Entry.Kind = switch (linux_entry.type) {
373 linux.DT.BLK => .block_device,373 linux.DT.BLK => .block_device,
374 linux.DT.CHR => .character_device,374 linux.DT.CHR => .character_device,
375 linux.DT.DIR => .directory,375 linux.DT.DIR => .directory,
...@@ -525,23 +525,23 @@ pub const Iterator = switch (builtin.os.tag) {...@@ -525,23 +525,23 @@ pub const Iterator = switch (builtin.os.tag) {
525 const entry = @as(*align(1) w.dirent_t, @ptrCast(&self.buf[self.index]));525 const entry = @as(*align(1) w.dirent_t, @ptrCast(&self.buf[self.index]));
526 const entry_size = @sizeOf(w.dirent_t);526 const entry_size = @sizeOf(w.dirent_t);
527 const name_index = self.index + entry_size;527 const name_index = self.index + entry_size;
528 if (name_index + entry.d_namlen > self.end_index) {528 if (name_index + entry.namlen > self.end_index) {
529 // This case, the name is truncated, so we need to call readdir to store the entire name.529 // This case, the name is truncated, so we need to call readdir to store the entire name.
530 self.end_index = self.index; // Force fd_readdir in the next loop.530 self.end_index = self.index; // Force fd_readdir in the next loop.
531 continue :start_over;531 continue :start_over;
532 }532 }
533 const name = self.buf[name_index .. name_index + entry.d_namlen];533 const name = self.buf[name_index .. name_index + entry.namlen];
534534
535 const next_index = name_index + entry.d_namlen;535 const next_index = name_index + entry.namlen;
536 self.index = next_index;536 self.index = next_index;
537 self.cookie = entry.d_next;537 self.cookie = entry.next;
538538
539 // skip . and .. entries539 // skip . and .. entries
540 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {540 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
541 continue :start_over;541 continue :start_over;
542 }542 }
543543
544 const entry_kind: Entry.Kind = switch (entry.d_type) {544 const entry_kind: Entry.Kind = switch (entry.type) {
545 .BLOCK_DEVICE => .block_device,545 .BLOCK_DEVICE => .block_device,
546 .CHARACTER_DEVICE => .character_device,546 .CHARACTER_DEVICE => .character_device,
547 .DIRECTORY => .directory,547 .DIRECTORY => .directory,
...@@ -764,81 +764,79 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope...@@ -764,81 +764,79 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
764 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);764 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
765 return self.openFileW(path_w.span(), flags);765 return self.openFileW(path_w.span(), flags);
766 }766 }
767 if (builtin.os.tag == .wasi and !builtin.link_libc) {767 if (builtin.os.tag == .wasi) {
768 return self.openFileWasi(sub_path, flags);768 var base: std.os.wasi.rights_t = .{};
769 if (flags.isRead()) {
770 base.FD_READ = true;
771 base.FD_TELL = true;
772 base.FD_SEEK = true;
773 base.FD_FILESTAT_GET = true;
774 }
775 if (flags.isWrite()) {
776 base.FD_WRITE = true;
777 base.FD_TELL = true;
778 base.FD_SEEK = true;
779 base.FD_DATASYNC = true;
780 base.FD_FDSTAT_SET_FLAGS = true;
781 base.FD_SYNC = true;
782 base.FD_ALLOCATE = true;
783 base.FD_ADVISE = true;
784 base.FD_FILESTAT_SET_TIMES = true;
785 base.FD_FILESTAT_SET_SIZE = true;
786 }
787 const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
788 return .{ .handle = fd };
769 }789 }
770 const path_c = try posix.toPosixPath(sub_path);790 const path_c = try posix.toPosixPath(sub_path);
771 return self.openFileZ(&path_c, flags);791 return self.openFileZ(&path_c, flags);
772}792}
773793
774/// Same as `openFile` but WASI only.
775pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
776 const w = std.os.wasi;
777 var fdflags: w.fdflags_t = 0x0;
778 var base: w.rights_t = 0x0;
779 if (flags.isRead()) {
780 base |= w.RIGHT.FD_READ | w.RIGHT.FD_TELL | w.RIGHT.FD_SEEK | w.RIGHT.FD_FILESTAT_GET;
781 }
782 if (flags.isWrite()) {
783 fdflags |= w.FDFLAG.APPEND;
784 base |= w.RIGHT.FD_WRITE |
785 w.RIGHT.FD_TELL |
786 w.RIGHT.FD_SEEK |
787 w.RIGHT.FD_DATASYNC |
788 w.RIGHT.FD_FDSTAT_SET_FLAGS |
789 w.RIGHT.FD_SYNC |
790 w.RIGHT.FD_ALLOCATE |
791 w.RIGHT.FD_ADVISE |
792 w.RIGHT.FD_FILESTAT_SET_TIMES |
793 w.RIGHT.FD_FILESTAT_SET_SIZE;
794 }
795 const fd = try posix.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0);
796 return File{ .handle = fd };
797}
798
799/// Same as `openFile` but the path parameter is null-terminated.794/// Same as `openFile` but the path parameter is null-terminated.
800pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {795pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
801 if (builtin.os.tag == .windows) {796 switch (builtin.os.tag) {
802 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);797 .windows => {
803 return self.openFileW(path_w.span(), flags);798 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);
799 return self.openFileW(path_w.span(), flags);
800 },
801 .wasi => {
802 return openFile(self, mem.sliceTo(sub_path, 0), flags);
803 },
804 else => {},
804 }805 }
805806
806 var os_flags: u32 = 0;807 var os_flags: posix.O = .{
807 if (@hasDecl(posix.O, "CLOEXEC")) os_flags = posix.O.CLOEXEC;808 .ACCMODE = switch (flags.mode) {
809 .read_only => .RDONLY,
810 .write_only => .WRONLY,
811 .read_write => .RDWR,
812 },
813 };
814 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
815 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
816 if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
808817
809 // Use the O locking flags if the os supports them to acquire the lock818 // Use the O locking flags if the os supports them to acquire the lock
810 // atomically.819 // atomically.
811 const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");820 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
812 if (has_flock_open_flags) {821 if (has_flock_open_flags) {
813 // Note that the O.NONBLOCK flag is removed after the openat() call822 // Note that the NONBLOCK flag is removed after the openat() call
814 // is successful.823 // is successful.
815 const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking)824 switch (flags.lock) {
816 posix.O.NONBLOCK825 .none => {},
817 else826 .shared => {
818 0;827 os_flags.SHLOCK = true;
819 os_flags |= switch (flags.lock) {828 os_flags.NONBLOCK = flags.lock_nonblocking;
820 .none => @as(u32, 0),829 },
821 .shared => posix.O.SHLOCK | nonblocking_lock_flag,830 .exclusive => {
822 .exclusive => posix.O.EXLOCK | nonblocking_lock_flag,831 os_flags.EXLOCK = true;
823 };832 os_flags.NONBLOCK = flags.lock_nonblocking;
824 }833 },
825 if (@hasDecl(posix.O, "LARGEFILE")) {834 }
826 os_flags |= posix.O.LARGEFILE;
827 }
828 if (@hasDecl(posix.O, "NOCTTY") and !flags.allow_ctty) {
829 os_flags |= posix.O.NOCTTY;
830 }835 }
831 os_flags |= switch (flags.mode) {
832 .read_only => @as(u32, posix.O.RDONLY),
833 .write_only => @as(u32, posix.O.WRONLY),
834 .read_write => @as(u32, posix.O.RDWR),
835 };
836 const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);836 const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
837 errdefer posix.close(fd);837 errdefer posix.close(fd);
838838
839 // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block839 if (@hasDecl(posix.system, "LOCK")) {
840 // since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
841 if (@hasDecl(posix.system, "LOCK") and builtin.target.os.tag != .wasi) {
842 if (!has_flock_open_flags and flags.lock != .none) {840 if (!has_flock_open_flags and flags.lock != .none) {
843 // TODO: integrate async I/O841 // TODO: integrate async I/O
844 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;842 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
...@@ -859,7 +857,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File...@@ -859,7 +857,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
859 error.LockedRegionLimitExceeded => unreachable,857 error.LockedRegionLimitExceeded => unreachable,
860 else => |e| return e,858 else => |e| return e,
861 };859 };
862 fl_flags &= ~@as(usize, posix.O.NONBLOCK);860 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
863 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {861 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
864 error.FileBusy => unreachable,862 error.FileBusy => unreachable,
865 error.Locked => unreachable,863 error.Locked => unreachable,
...@@ -870,7 +868,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File...@@ -870,7 +868,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
870 };868 };
871 }869 }
872870
873 return File{ .handle = fd };871 return .{ .handle = fd };
874}872}
875873
876/// Same as `openFile` but Windows-only and the path parameter is874/// Same as `openFile` but Windows-only and the path parameter is
...@@ -918,83 +916,81 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File...@@ -918,83 +916,81 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
918 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);916 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
919 return self.createFileW(path_w.span(), flags);917 return self.createFileW(path_w.span(), flags);
920 }918 }
921 if (builtin.os.tag == .wasi and !builtin.link_libc) {919 if (builtin.os.tag == .wasi) {
922 return self.createFileWasi(sub_path, flags);920 return .{
921 .handle = try posix.openatWasi(self.fd, sub_path, .{}, .{
922 .CREAT = true,
923 .TRUNC = flags.truncate,
924 .EXCL = flags.exclusive,
925 }, .{}, .{
926 .FD_READ = flags.read,
927 .FD_WRITE = true,
928 .FD_DATASYNC = true,
929 .FD_SEEK = true,
930 .FD_TELL = true,
931 .FD_FDSTAT_SET_FLAGS = true,
932 .FD_SYNC = true,
933 .FD_ALLOCATE = true,
934 .FD_ADVISE = true,
935 .FD_FILESTAT_SET_TIMES = true,
936 .FD_FILESTAT_SET_SIZE = true,
937 .FD_FILESTAT_GET = true,
938 }, .{}),
939 };
923 }940 }
924 const path_c = try posix.toPosixPath(sub_path);941 const path_c = try posix.toPosixPath(sub_path);
925 return self.createFileZ(&path_c, flags);942 return self.createFileZ(&path_c, flags);
926}943}
927944
928/// Same as `createFile` but WASI only.
929pub fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
930 const w = std.os.wasi;
931 var oflags = w.O.CREAT;
932 var base: w.rights_t = w.RIGHT.FD_WRITE |
933 w.RIGHT.FD_DATASYNC |
934 w.RIGHT.FD_SEEK |
935 w.RIGHT.FD_TELL |
936 w.RIGHT.FD_FDSTAT_SET_FLAGS |
937 w.RIGHT.FD_SYNC |
938 w.RIGHT.FD_ALLOCATE |
939 w.RIGHT.FD_ADVISE |
940 w.RIGHT.FD_FILESTAT_SET_TIMES |
941 w.RIGHT.FD_FILESTAT_SET_SIZE |
942 w.RIGHT.FD_FILESTAT_GET;
943 if (flags.read) {
944 base |= w.RIGHT.FD_READ;
945 }
946 if (flags.truncate) {
947 oflags |= w.O.TRUNC;
948 }
949 if (flags.exclusive) {
950 oflags |= w.O.EXCL;
951 }
952 const fd = try posix.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0);
953 return File{ .handle = fd };
954}
955
956/// Same as `createFile` but the path parameter is null-terminated.945/// Same as `createFile` but the path parameter is null-terminated.
957pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {946pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
958 if (builtin.os.tag == .windows) {947 switch (builtin.os.tag) {
959 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);948 .windows => {
960 return self.createFileW(path_w.span(), flags);949 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
950 return self.createFileW(path_w.span(), flags);
951 },
952 .wasi => {
953 return createFile(self, mem.sliceTo(sub_path_c, 0), flags);
954 },
955 else => {},
961 }956 }
962957
958 var os_flags: std.os.O = .{
959 .ACCMODE = if (flags.read) .RDWR else .WRONLY,
960 .CREAT = true,
961 .TRUNC = flags.truncate,
962 .EXCL = flags.exclusive,
963 };
964 if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
965 if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
966
963 // Use the O locking flags if the os supports them to acquire the lock967 // Use the O locking flags if the os supports them to acquire the lock
964 // atomically.968 // atomically. Note that the NONBLOCK flag is removed after the openat()
965 const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");969 // call is successful.
966 // Note that the O.NONBLOCK flag is removed after the openat() call970 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
967 // is successful.971 if (has_flock_open_flags) switch (flags.lock) {
968 const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking)972 .none => {},
969 posix.O.NONBLOCK973 .shared => {
970 else974 os_flags.SHLOCK = true;
971 0;975 os_flags.NONBLOCK = flags.lock_nonblocking;
972 const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) {976 },
973 .none => @as(u32, 0),977 .exclusive => {
974 .shared => posix.O.SHLOCK | nonblocking_lock_flag,978 os_flags.EXLOCK = true;
975 .exclusive => posix.O.EXLOCK | nonblocking_lock_flag,979 os_flags.NONBLOCK = flags.lock_nonblocking;
976 } else 0;980 },
977981 };
978 const O_LARGEFILE = if (@hasDecl(posix.O, "LARGEFILE")) posix.O.LARGEFILE else 0;982
979 const os_flags = lock_flag | O_LARGEFILE | posix.O.CREAT | posix.O.CLOEXEC |
980 (if (flags.truncate) @as(u32, posix.O.TRUNC) else 0) |
981 (if (flags.read) @as(u32, posix.O.RDWR) else posix.O.WRONLY) |
982 (if (flags.exclusive) @as(u32, posix.O.EXCL) else 0);
983 const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);983 const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
984 errdefer posix.close(fd);984 errdefer posix.close(fd);
985985
986 // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block986 if (!has_flock_open_flags and flags.lock != .none) {
987 // since it is not compiltime-known and we need to avoid undefined symbol in Wasm.987 // TODO: integrate async I/O
988 if (builtin.target.os.tag != .wasi) {988 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
989 if (!has_flock_open_flags and flags.lock != .none) {989 try posix.flock(fd, switch (flags.lock) {
990 // TODO: integrate async I/O990 .none => unreachable,
991 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;991 .shared => posix.LOCK.SH | lock_nonblocking,
992 try posix.flock(fd, switch (flags.lock) {992 .exclusive => posix.LOCK.EX | lock_nonblocking,
993 .none => unreachable,993 });
994 .shared => posix.LOCK.SH | lock_nonblocking,
995 .exclusive => posix.LOCK.EX | lock_nonblocking,
996 });
997 }
998 }994 }
999995
1000 if (has_flock_open_flags and flags.lock_nonblocking) {996 if (has_flock_open_flags and flags.lock_nonblocking) {
...@@ -1006,7 +1002,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags...@@ -1006,7 +1002,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
1006 error.LockedRegionLimitExceeded => unreachable,1002 error.LockedRegionLimitExceeded => unreachable,
1007 else => |e| return e,1003 else => |e| return e,
1008 };1004 };
1009 fl_flags &= ~@as(usize, posix.O.NONBLOCK);1005 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
1010 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {1006 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
1011 error.FileBusy => unreachable,1007 error.FileBusy => unreachable,
1012 error.Locked => unreachable,1008 error.Locked => unreachable,
...@@ -1017,7 +1013,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags...@@ -1017,7 +1013,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
1017 };1013 };
1018 }1014 }
10191015
1020 return File{ .handle = fd };1016 return .{ .handle = fd };
1021}1017}
10221018
1023/// Same as `createFile` but Windows-only and the path parameter is1019/// Same as `createFile` but Windows-only and the path parameter is
...@@ -1210,10 +1206,18 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {...@@ -1210,10 +1206,18 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {
1210 return self.realpathW(pathname_w.span(), out_buffer);1206 return self.realpathW(pathname_w.span(), out_buffer);
1211 }1207 }
12121208
1213 const flags = if (builtin.os.tag == .linux)1209 const flags: posix.O = switch (builtin.os.tag) {
1214 posix.O.PATH | posix.O.NONBLOCK | posix.O.CLOEXEC1210 .linux => .{
1215 else1211 .NONBLOCK = true,
1216 posix.O.NONBLOCK | posix.O.CLOEXEC;1212 .CLOEXEC = true,
1213 .PATH = true,
1214 },
1215 else => .{
1216 .NONBLOCK = true,
1217 .CLOEXEC = true,
1218 },
1219 };
1220
1217 const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) {1221 const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) {
1218 error.FileLocksNotSupported => unreachable,1222 error.FileLocksNotSupported => unreachable,
1219 else => |e| return e,1223 else => |e| return e,
...@@ -1334,76 +1338,85 @@ pub const OpenDirOptions = struct {...@@ -1334,76 +1338,85 @@ pub const OpenDirOptions = struct {
1334///1338///
1335/// Asserts that the path parameter has no null bytes.1339/// Asserts that the path parameter has no null bytes.
1336pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {1340pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
1337 if (builtin.os.tag == .windows) {1341 switch (builtin.os.tag) {
1338 const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);1342 .windows => {
1339 return self.openDirW(sub_path_w.span().ptr, args);1343 const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
1340 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1344 return self.openDirW(sub_path_w.span().ptr, args);
1341 return self.openDirWasi(sub_path, args);1345 },
1342 } else {1346 .wasi => {
1343 const sub_path_c = try posix.toPosixPath(sub_path);1347 var base: std.os.wasi.rights_t = .{
1344 return self.openDirZ(&sub_path_c, args);1348 .FD_FILESTAT_GET = true,
1345 }1349 .FD_FDSTAT_SET_FLAGS = true,
1346}1350 .FD_FILESTAT_SET_TIMES = true,
1351 };
1352 if (args.access_sub_paths) {
1353 base.FD_READDIR = true;
1354 base.PATH_CREATE_DIRECTORY = true;
1355 base.PATH_CREATE_FILE = true;
1356 base.PATH_LINK_SOURCE = true;
1357 base.PATH_LINK_TARGET = true;
1358 base.PATH_OPEN = true;
1359 base.PATH_READLINK = true;
1360 base.PATH_RENAME_SOURCE = true;
1361 base.PATH_RENAME_TARGET = true;
1362 base.PATH_FILESTAT_GET = true;
1363 base.PATH_FILESTAT_SET_SIZE = true;
1364 base.PATH_FILESTAT_SET_TIMES = true;
1365 base.PATH_SYMLINK = true;
1366 base.PATH_REMOVE_DIRECTORY = true;
1367 base.PATH_UNLINK_FILE = true;
1368 }
13471369
1348/// Same as `openDir` except only WASI.1370 const result = posix.openatWasi(
1349pub fn openDirWasi(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {1371 self.fd,
1350 const w = std.os.wasi;1372 sub_path,
1351 var base: w.rights_t = w.RIGHT.FD_FILESTAT_GET | w.RIGHT.FD_FDSTAT_SET_FLAGS | w.RIGHT.FD_FILESTAT_SET_TIMES;1373 .{ .SYMLINK_FOLLOW = !args.no_follow },
1352 if (args.access_sub_paths) {1374 .{ .DIRECTORY = true },
1353 base |= w.RIGHT.FD_READDIR |1375 .{},
1354 w.RIGHT.PATH_CREATE_DIRECTORY |1376 base,
1355 w.RIGHT.PATH_CREATE_FILE |1377 base,
1356 w.RIGHT.PATH_LINK_SOURCE |1378 );
1357 w.RIGHT.PATH_LINK_TARGET |1379 const fd = result catch |err| switch (err) {
1358 w.RIGHT.PATH_OPEN |1380 error.FileTooBig => unreachable, // can't happen for directories
1359 w.RIGHT.PATH_READLINK |1381 error.IsDir => unreachable, // we're setting DIRECTORY
1360 w.RIGHT.PATH_RENAME_SOURCE |1382 error.NoSpaceLeft => unreachable, // not setting CREAT
1361 w.RIGHT.PATH_RENAME_TARGET |1383 error.PathAlreadyExists => unreachable, // not setting CREAT
1362 w.RIGHT.PATH_FILESTAT_GET |1384 error.FileLocksNotSupported => unreachable, // locking folders is not supported
1363 w.RIGHT.PATH_FILESTAT_SET_SIZE |1385 error.WouldBlock => unreachable, // can't happen for directories
1364 w.RIGHT.PATH_FILESTAT_SET_TIMES |1386 error.FileBusy => unreachable, // can't happen for directories
1365 w.RIGHT.PATH_SYMLINK |1387 else => |e| return e,
1366 w.RIGHT.PATH_REMOVE_DIRECTORY |1388 };
1367 w.RIGHT.PATH_UNLINK_FILE;1389 return .{ .fd = fd };
1390 },
1391 else => {
1392 const sub_path_c = try posix.toPosixPath(sub_path);
1393 return self.openDirZ(&sub_path_c, args);
1394 },
1368 }1395 }
1369 const symlink_flags: w.lookupflags_t = if (args.no_follow) 0x0 else w.LOOKUP_SYMLINK_FOLLOW;
1370 // TODO do we really need all the rights here?
1371 const inheriting: w.rights_t = w.RIGHT.ALL ^ w.RIGHT.SOCK_SHUTDOWN;
1372
1373 const result = posix.openatWasi(
1374 self.fd,
1375 sub_path,
1376 symlink_flags,
1377 w.O.DIRECTORY,
1378 0x0,
1379 base,
1380 inheriting,
1381 );
1382 const fd = result catch |err| switch (err) {
1383 error.FileTooBig => unreachable, // can't happen for directories
1384 error.IsDir => unreachable, // we're providing O.DIRECTORY
1385 error.NoSpaceLeft => unreachable, // not providing O.CREAT
1386 error.PathAlreadyExists => unreachable, // not providing O.CREAT
1387 error.FileLocksNotSupported => unreachable, // locking folders is not supported
1388 error.WouldBlock => unreachable, // can't happen for directories
1389 error.FileBusy => unreachable, // can't happen for directories
1390 else => |e| return e,
1391 };
1392 return Dir{ .fd = fd };
1393}1396}
13941397
1395/// Same as `openDir` except the parameter is null-terminated.1398/// Same as `openDir` except the parameter is null-terminated.
1396pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {1399pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
1397 if (builtin.os.tag == .windows) {1400 switch (builtin.os.tag) {
1398 const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);1401 .windows => {
1399 return self.openDirW(sub_path_w.span().ptr, args);1402 const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1400 }1403 return self.openDirW(sub_path_w.span().ptr, args);
1401 const symlink_flags: u32 = if (args.no_follow) posix.O.NOFOLLOW else 0x0;1404 },
1402 if (!args.iterate) {1405 .wasi => {
1403 const O_PATH = if (@hasDecl(posix.O, "PATH")) posix.O.PATH else 0;1406 return openDir(self, mem.sliceTo(sub_path_c, 0), args);
1404 return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | O_PATH | symlink_flags);1407 },
1405 } else {1408 else => {
1406 return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | symlink_flags);1409 var symlink_flags: posix.O = .{
1410 .ACCMODE = .RDONLY,
1411 .NOFOLLOW = args.no_follow,
1412 .DIRECTORY = true,
1413 .CLOEXEC = true,
1414 };
1415 if (@hasField(posix.O, "PATH") and !args.iterate)
1416 symlink_flags.PATH = true;
1417
1418 return self.openDirFlagsZ(sub_path_c, symlink_flags);
1419 },
1407 }1420 }
1408}1421}
14091422
...@@ -1422,13 +1435,14 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope...@@ -1422,13 +1435,14 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope
1422 return dir;1435 return dir;
1423}1436}
14241437
1425/// `flags` must contain `posix.O.DIRECTORY`.1438/// Asserts `flags` has `DIRECTORY` set.
1426fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir {1439fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError!Dir {
1440 assert(flags.DIRECTORY);
1427 const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) {1441 const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) {
1428 error.FileTooBig => unreachable, // can't happen for directories1442 error.FileTooBig => unreachable, // can't happen for directories
1429 error.IsDir => unreachable, // we're providing O.DIRECTORY1443 error.IsDir => unreachable, // we're setting DIRECTORY
1430 error.NoSpaceLeft => unreachable, // not providing O.CREAT1444 error.NoSpaceLeft => unreachable, // not setting CREAT
1431 error.PathAlreadyExists => unreachable, // not providing O.CREAT1445 error.PathAlreadyExists => unreachable, // not setting CREAT
1432 error.FileLocksNotSupported => unreachable, // locking folders is not supported1446 error.FileLocksNotSupported => unreachable, // locking folders is not supported
1433 error.WouldBlock => unreachable, // can't happen for directories1447 error.WouldBlock => unreachable, // can't happen for directories
1434 error.FileBusy => unreachable, // can't happen for directories1448 error.FileBusy => unreachable, // can't happen for directories
...@@ -2446,8 +2460,8 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {...@@ -2446,8 +2460,8 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
2446 return file.stat();2460 return file.stat();
2447 }2461 }
2448 if (builtin.os.tag == .wasi and !builtin.link_libc) {2462 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2449 const st = try posix.fstatatWasi(self.fd, sub_path, posix.wasi.LOOKUP_SYMLINK_FOLLOW);2463 const st = try posix.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
2450 return Stat.fromSystem(st);2464 return Stat.fromWasi(st);
2451 }2465 }
2452 const st = try posix.fstatat(self.fd, sub_path, 0);2466 const st = try posix.fstatat(self.fd, sub_path, 0);
2453 return Stat.fromSystem(st);2467 return Stat.fromSystem(st);
...@@ -2507,3 +2521,4 @@ const posix = std.os;...@@ -2507,3 +2521,4 @@ const posix = std.os;
2507const mem = std.mem;2521const mem = std.mem;
2508const fs = std.fs;2522const fs = std.fs;
2509const Allocator = std.mem.Allocator;2523const Allocator = std.mem.Allocator;
2524const assert = std.debug.assert;
lib/std/fs/File.zig+95-47
...@@ -290,49 +290,59 @@ pub const Stat = struct {...@@ -290,49 +290,59 @@ pub const Stat = struct {
290 /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.290 /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
291 ctime: i128,291 ctime: i128,
292292
293 pub fn fromSystem(st: posix.system.Stat) Stat {293 pub fn fromSystem(st: posix.Stat) Stat {
294 const atime = st.atime();294 const atime = st.atime();
295 const mtime = st.mtime();295 const mtime = st.mtime();
296 const ctime = st.ctime();296 const ctime = st.ctime();
297 const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {297 return .{
298 .BLOCK_DEVICE => .block_device,
299 .CHARACTER_DEVICE => .character_device,
300 .DIRECTORY => .directory,
301 .SYMBOLIC_LINK => .sym_link,
302 .REGULAR_FILE => .file,
303 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
304 else => .unknown,
305 } else blk: {
306 const m = st.mode & posix.S.IFMT;
307 switch (m) {
308 posix.S.IFBLK => break :blk .block_device,
309 posix.S.IFCHR => break :blk .character_device,
310 posix.S.IFDIR => break :blk .directory,
311 posix.S.IFIFO => break :blk .named_pipe,
312 posix.S.IFLNK => break :blk .sym_link,
313 posix.S.IFREG => break :blk .file,
314 posix.S.IFSOCK => break :blk .unix_domain_socket,
315 else => {},
316 }
317 if (builtin.os.tag.isSolarish()) switch (m) {
318 posix.S.IFDOOR => break :blk .door,
319 posix.S.IFPORT => break :blk .event_port,
320 else => {},
321 };
322
323 break :blk .unknown;
324 };
325
326 return Stat{
327 .inode = st.ino,298 .inode = st.ino,
328 .size = @as(u64, @bitCast(st.size)),299 .size = @bitCast(st.size),
329 .mode = st.mode,300 .mode = st.mode,
330 .kind = kind,301 .kind = k: {
302 const m = st.mode & posix.S.IFMT;
303 switch (m) {
304 posix.S.IFBLK => break :k .block_device,
305 posix.S.IFCHR => break :k .character_device,
306 posix.S.IFDIR => break :k .directory,
307 posix.S.IFIFO => break :k .named_pipe,
308 posix.S.IFLNK => break :k .sym_link,
309 posix.S.IFREG => break :k .file,
310 posix.S.IFSOCK => break :k .unix_domain_socket,
311 else => {},
312 }
313 if (builtin.os.tag.isSolarish()) switch (m) {
314 posix.S.IFDOOR => break :k .door,
315 posix.S.IFPORT => break :k .event_port,
316 else => {},
317 };
318
319 break :k .unknown;
320 },
331 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,321 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
332 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,322 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
333 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,323 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
334 };324 };
335 }325 }
326
327 pub fn fromWasi(st: std.os.wasi.filestat_t) Stat {
328 return .{
329 .inode = st.ino,
330 .size = @bitCast(st.size),
331 .mode = 0,
332 .kind = switch (st.filetype) {
333 .BLOCK_DEVICE => .block_device,
334 .CHARACTER_DEVICE => .character_device,
335 .DIRECTORY => .directory,
336 .SYMBOLIC_LINK => .sym_link,
337 .REGULAR_FILE => .file,
338 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
339 else => .unknown,
340 },
341 .atime = st.atim,
342 .mtime = st.mtim,
343 .ctime = st.ctim,
344 };
345 }
336};346};
337347
338pub const StatError = posix.FStatError;348pub const StatError = posix.FStatError;
...@@ -355,7 +365,7 @@ pub fn stat(self: File) StatError!Stat {...@@ -355,7 +365,7 @@ pub fn stat(self: File) StatError!Stat {
355 .ACCESS_DENIED => return error.AccessDenied,365 .ACCESS_DENIED => return error.AccessDenied,
356 else => return windows.unexpectedStatus(rc),366 else => return windows.unexpectedStatus(rc),
357 }367 }
358 return Stat{368 return .{
359 .inode = info.InternalInformation.IndexNumber,369 .inode = info.InternalInformation.IndexNumber,
360 .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),370 .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
361 .mode = 0,371 .mode = 0,
...@@ -385,6 +395,11 @@ pub fn stat(self: File) StatError!Stat {...@@ -385,6 +395,11 @@ pub fn stat(self: File) StatError!Stat {
385 };395 };
386 }396 }
387397
398 if (builtin.os.tag == .wasi and !builtin.link_libc) {
399 const st = try posix.fstat_wasi(self.handle);
400 return Stat.fromWasi(st);
401 }
402
388 const st = try posix.fstat(self.handle);403 const st = try posix.fstat(self.handle);
389 return Stat.fromSystem(st);404 return Stat.fromSystem(st);
390}405}
...@@ -576,10 +591,11 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError!...@@ -576,10 +591,11 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError!
576/// Cross-platform representation of file metadata.591/// Cross-platform representation of file metadata.
577/// Platform-specific functionality is available through the `inner` field.592/// Platform-specific functionality is available through the `inner` field.
578pub const Metadata = struct {593pub const Metadata = struct {
579 /// You may use the `inner` field to use platform-specific functionality594 /// Exposes platform-specific functionality.
580 inner: switch (builtin.os.tag) {595 inner: switch (builtin.os.tag) {
581 .windows => MetadataWindows,596 .windows => MetadataWindows,
582 .linux => MetadataLinux,597 .linux => MetadataLinux,
598 .wasi => MetadataWasi,
583 else => MetadataUnix,599 else => MetadataUnix,
584 },600 },
585601
...@@ -628,12 +644,12 @@ pub const MetadataUnix = struct {...@@ -628,12 +644,12 @@ pub const MetadataUnix = struct {
628644
629 /// Returns the size of the file645 /// Returns the size of the file
630 pub fn size(self: Self) u64 {646 pub fn size(self: Self) u64 {
631 return @as(u64, @intCast(self.stat.size));647 return @intCast(self.stat.size);
632 }648 }
633649
634 /// Returns a `Permissions` struct, representing the permissions on the file650 /// Returns a `Permissions` struct, representing the permissions on the file
635 pub fn permissions(self: Self) Permissions {651 pub fn permissions(self: Self) Permissions {
636 return Permissions{ .inner = PermissionsUnix{ .mode = self.stat.mode } };652 return .{ .inner = .{ .mode = self.stat.mode } };
637 }653 }
638654
639 /// Returns the `Kind` of the file655 /// Returns the `Kind` of the file
...@@ -756,6 +772,42 @@ pub const MetadataLinux = struct {...@@ -756,6 +772,42 @@ pub const MetadataLinux = struct {
756 }772 }
757};773};
758774
775pub const MetadataWasi = struct {
776 stat: std.os.wasi.filestat_t,
777
778 pub fn size(self: @This()) u64 {
779 return self.stat.size;
780 }
781
782 pub fn permissions(self: @This()) Permissions {
783 return .{ .inner = .{ .mode = self.stat.mode } };
784 }
785
786 pub fn kind(self: @This()) Kind {
787 return switch (self.stat.filetype) {
788 .BLOCK_DEVICE => .block_device,
789 .CHARACTER_DEVICE => .character_device,
790 .DIRECTORY => .directory,
791 .SYMBOLIC_LINK => .sym_link,
792 .REGULAR_FILE => .file,
793 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
794 else => .unknown,
795 };
796 }
797
798 pub fn accessed(self: @This()) i128 {
799 return self.stat.atim;
800 }
801
802 pub fn modified(self: @This()) i128 {
803 return self.stat.mtim;
804 }
805
806 pub fn created(self: @This()) ?i128 {
807 return self.stat.ctim;
808 }
809};
810
759pub const MetadataWindows = struct {811pub const MetadataWindows = struct {
760 attributes: windows.DWORD,812 attributes: windows.DWORD,
761 reparse_tag: windows.DWORD,813 reparse_tag: windows.DWORD,
...@@ -773,7 +825,7 @@ pub const MetadataWindows = struct {...@@ -773,7 +825,7 @@ pub const MetadataWindows = struct {
773825
774 /// Returns a `Permissions` struct, representing the permissions on the file826 /// Returns a `Permissions` struct, representing the permissions on the file
775 pub fn permissions(self: Self) Permissions {827 pub fn permissions(self: Self) Permissions {
776 return Permissions{ .inner = PermissionsWindows{ .attributes = self.attributes } };828 return .{ .inner = .{ .attributes = self.attributes } };
777 }829 }
778830
779 /// Returns the `Kind` of the file.831 /// Returns the `Kind` of the file.
...@@ -811,7 +863,7 @@ pub const MetadataWindows = struct {...@@ -811,7 +863,7 @@ pub const MetadataWindows = struct {
811pub const MetadataError = posix.FStatError;863pub const MetadataError = posix.FStatError;
812864
813pub fn metadata(self: File) MetadataError!Metadata {865pub fn metadata(self: File) MetadataError!Metadata {
814 return Metadata{866 return .{
815 .inner = switch (builtin.os.tag) {867 .inner = switch (builtin.os.tag) {
816 .windows => blk: {868 .windows => blk: {
817 var io_status_block: windows.IO_STATUS_BLOCK = undefined;869 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
...@@ -846,7 +898,7 @@ pub fn metadata(self: File) MetadataError!Metadata {...@@ -846,7 +898,7 @@ pub fn metadata(self: File) MetadataError!Metadata {
846 break :reparse_blk 0;898 break :reparse_blk 0;
847 };899 };
848900
849 break :blk MetadataWindows{901 break :blk .{
850 .attributes = info.BasicInformation.FileAttributes,902 .attributes = info.BasicInformation.FileAttributes,
851 .reparse_tag = reparse_tag,903 .reparse_tag = reparse_tag,
852 ._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),904 ._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
...@@ -887,16 +939,12 @@ pub fn metadata(self: File) MetadataError!Metadata {...@@ -887,16 +939,12 @@ pub fn metadata(self: File) MetadataError!Metadata {
887 else => |err| return posix.unexpectedErrno(err),939 else => |err| return posix.unexpectedErrno(err),
888 }940 }
889941
890 break :blk MetadataLinux{942 break :blk .{
891 .statx = stx,943 .statx = stx,
892 };944 };
893 },945 },
894 else => blk: {946 .wasi => .{ .stat = try posix.fstat_wasi(self.handle) },
895 const st = try posix.fstat(self.handle);947 else => .{ .stat = try posix.fstat(self.handle) },
896 break :blk MetadataUnix{
897 .stat = st,
898 };
899 },
900 },948 },
901 };949 };
902}950}
lib/std/fs/test.zig+6-1
...@@ -242,7 +242,12 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {...@@ -242,7 +242,12 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
242 const sub_path_c = try os.toPosixPath("symlink");242 const sub_path_c = try os.toPosixPath("symlink");
243 // the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink243 // the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
244 // note that if O_DIRECTORY is set, then this will error with ENOTDIR244 // note that if O_DIRECTORY is set, then this will error with ENOTDIR
245 const flags = os.O.NOFOLLOW | os.O.PATH | os.O.RDONLY | os.O.CLOEXEC;245 const flags: os.O = .{
246 .NOFOLLOW = true,
247 .PATH = true,
248 .ACCMODE = .RDONLY,
249 .CLOEXEC = true,
250 };
246 const fd = try os.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);251 const fd = try os.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
247 break :linux_symlink Dir{ .fd = fd };252 break :linux_symlink Dir{ .fd = fd };
248 },253 },
lib/std/os.zig+214-220
...@@ -24,7 +24,6 @@ const elf = std.elf;...@@ -24,7 +24,6 @@ const elf = std.elf;
24const fs = std.fs;24const fs = std.fs;
25const dl = @import("dynamic_library.zig");25const dl = @import("dynamic_library.zig");
26const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;26const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
27const is_windows = builtin.os.tag == .windows;
2827
29pub const darwin = std.c;28pub const darwin = std.c;
30pub const dragonfly = std.c;29pub const dragonfly = std.c;
...@@ -62,16 +61,21 @@ test {...@@ -62,16 +61,21 @@ test {
62/// When not linking libc, it is the OS-specific system interface.61/// When not linking libc, it is the OS-specific system interface.
63pub const system = if (@hasDecl(root, "os") and root.os != @This())62pub const system = if (@hasDecl(root, "os") and root.os != @This())
64 root.os.system63 root.os.system
65else if (builtin.link_libc or is_windows)64else if (use_libc)
66 std.c65 std.c
67else switch (builtin.os.tag) {66else switch (builtin.os.tag) {
68 .linux => linux,67 .linux => linux,
69 .plan9 => plan9,68 .plan9 => plan9,
70 .wasi => wasi,
71 .uefi => uefi,69 .uefi => uefi,
72 else => struct {},70 else => struct {},
73};71};
7472
73/// Whether to use libc for the POSIX API layer.
74const use_libc = builtin.link_libc or switch (builtin.os.tag) {
75 .windows, .wasi => true,
76 else => false,
77};
78
75pub const AF = system.AF;79pub const AF = system.AF;
76pub const AF_SUN = system.AF_SUN;80pub const AF_SUN = system.AF_SUN;
77pub const ARCH = system.ARCH;81pub const ARCH = system.ARCH;
...@@ -87,10 +91,7 @@ pub const F = system.F;...@@ -87,10 +91,7 @@ pub const F = system.F;
87pub const FD_CLOEXEC = system.FD_CLOEXEC;91pub const FD_CLOEXEC = system.FD_CLOEXEC;
88pub const Flock = system.Flock;92pub const Flock = system.Flock;
89pub const HOST_NAME_MAX = system.HOST_NAME_MAX;93pub const HOST_NAME_MAX = system.HOST_NAME_MAX;
90pub const HW = switch (builtin.os.tag) {94pub const HW = system.HW;
91 .openbsd => system.HW,
92 else => .{},
93};
94pub const IFNAMESIZE = system.IFNAMESIZE;95pub const IFNAMESIZE = system.IFNAMESIZE;
95pub const IOV_MAX = system.IOV_MAX;96pub const IOV_MAX = system.IOV_MAX;
96pub const IPPROTO = system.IPPROTO;97pub const IPPROTO = system.IPPROTO;
...@@ -105,19 +106,13 @@ pub const MFD = system.MFD;...@@ -105,19 +106,13 @@ pub const MFD = system.MFD;
105pub const MMAP2_UNIT = system.MMAP2_UNIT;106pub const MMAP2_UNIT = system.MMAP2_UNIT;
106pub const MSG = system.MSG;107pub const MSG = system.MSG;
107pub const NAME_MAX = system.NAME_MAX;108pub const NAME_MAX = system.NAME_MAX;
108pub const O = switch (builtin.os.tag) {109pub const O = system.O;
109 // We want to expose the POSIX-like OFLAGS, so we use std.c.wasi.O instead
110 // of std.os.wasi.O, which is for non-POSIX-like `wasi.path_open`, etc.
111 .wasi => std.c.O,
112 else => system.O,
113};
114pub const PATH_MAX = system.PATH_MAX;110pub const PATH_MAX = system.PATH_MAX;
115pub const POLL = system.POLL;111pub const POLL = system.POLL;
116pub const POSIX_FADV = system.POSIX_FADV;112pub const POSIX_FADV = system.POSIX_FADV;
117pub const PR = system.PR;113pub const PR = system.PR;
118pub const PROT = system.PROT;114pub const PROT = system.PROT;
119pub const REG = system.REG;115pub const REG = system.REG;
120pub const RIGHT = system.RIGHT;
121pub const RLIM = system.RLIM;116pub const RLIM = system.RLIM;
122pub const RR = system.RR;117pub const RR = system.RR;
123pub const S = system.S;118pub const S = system.S;
...@@ -151,12 +146,9 @@ pub const dl_phdr_info = system.dl_phdr_info;...@@ -151,12 +146,9 @@ pub const dl_phdr_info = system.dl_phdr_info;
151pub const empty_sigset = system.empty_sigset;146pub const empty_sigset = system.empty_sigset;
152pub const filled_sigset = system.filled_sigset;147pub const filled_sigset = system.filled_sigset;
153pub const fd_t = system.fd_t;148pub const fd_t = system.fd_t;
154pub const fdflags_t = system.fdflags_t;
155pub const fdstat_t = system.fdstat_t;
156pub const gid_t = system.gid_t;149pub const gid_t = system.gid_t;
157pub const ifreq = system.ifreq;150pub const ifreq = system.ifreq;
158pub const ino_t = system.ino_t;151pub const ino_t = system.ino_t;
159pub const lookupflags_t = system.lookupflags_t;
160pub const mcontext_t = system.mcontext_t;152pub const mcontext_t = system.mcontext_t;
161pub const mode_t = system.mode_t;153pub const mode_t = system.mode_t;
162pub const msghdr = system.msghdr;154pub const msghdr = system.msghdr;
...@@ -164,14 +156,12 @@ pub const msghdr_const = system.msghdr_const;...@@ -164,14 +156,12 @@ pub const msghdr_const = system.msghdr_const;
164pub const nfds_t = system.nfds_t;156pub const nfds_t = system.nfds_t;
165pub const nlink_t = system.nlink_t;157pub const nlink_t = system.nlink_t;
166pub const off_t = system.off_t;158pub const off_t = system.off_t;
167pub const oflags_t = system.oflags_t;
168pub const pid_t = system.pid_t;159pub const pid_t = system.pid_t;
169pub const pollfd = system.pollfd;160pub const pollfd = system.pollfd;
170pub const port_t = system.port_t;161pub const port_t = system.port_t;
171pub const port_event = system.port_event;162pub const port_event = system.port_event;
172pub const port_notify = system.port_notify;163pub const port_notify = system.port_notify;
173pub const file_obj = system.file_obj;164pub const file_obj = system.file_obj;
174pub const rights_t = system.rights_t;
175pub const rlim_t = system.rlim_t;165pub const rlim_t = system.rlim_t;
176pub const rlimit = system.rlimit;166pub const rlimit = system.rlimit;
177pub const rlimit_resource = system.rlimit_resource;167pub const rlimit_resource = system.rlimit_resource;
...@@ -209,6 +199,12 @@ pub const iovec_const = extern struct {...@@ -209,6 +199,12 @@ pub const iovec_const = extern struct {
209 iov_len: usize,199 iov_len: usize,
210};200};
211201
202pub const ACCMODE = enum(u2) {
203 RDONLY = 0,
204 WRONLY = 1,
205 RDWR = 2,
206};
207
212pub const LOG = struct {208pub const LOG = struct {
213 /// system is unusable209 /// system is unusable
214 pub const EMERG = 0;210 pub const EMERG = 0;
...@@ -460,13 +456,13 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr...@@ -460,13 +456,13 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
460456
461 // Fallback to changing permissions using procfs:457 // Fallback to changing permissions using procfs:
462 //458 //
463 // 1. Open `path` as an `O.PATH` descriptor.459 // 1. Open `path` as a `PATH` descriptor.
464 // 2. Stat the fd and check if it isn't a symbolic link.460 // 2. Stat the fd and check if it isn't a symbolic link.
465 // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`.461 // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`.
466 // 4. Pass the procfs path to `chmod` with the `mode`.462 // 4. Pass the procfs path to `chmod` with the `mode`.
467 var pathfd: fd_t = undefined;463 var pathfd: fd_t = undefined;
468 while (true) {464 while (true) {
469 const rc = system.openat(dirfd, &path_c, O.PATH | O.NOFOLLOW | O.CLOEXEC, @as(mode_t, 0));465 const rc = system.openat(dirfd, &path_c, .{ .PATH = true, .NOFOLLOW = true, .CLOEXEC = true }, @as(mode_t, 0));
470 switch (system.getErrno(rc)) {466 switch (system.getErrno(rc)) {
471 .SUCCESS => {467 .SUCCESS => {
472 pathfd = @as(fd_t, @intCast(rc));468 pathfd = @as(fd_t, @intCast(rc));
...@@ -536,8 +532,10 @@ pub const FChownError = error{...@@ -536,8 +532,10 @@ pub const FChownError = error{
536/// any group of which the owner is a member. If the owner or group is532/// any group of which the owner is a member. If the owner or group is
537/// specified as `null`, the ID is not changed.533/// specified as `null`, the ID is not changed.
538pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {534pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
539 if (builtin.os.tag == .windows or builtin.os.tag == .wasi)535 switch (builtin.os.tag) {
540 @compileError("Unsupported OS");536 .windows, .wasi => @compileError("Unsupported OS"),
537 else => {},
538 }
541539
542 while (true) {540 while (true) {
543 const res = system.fchown(fd, owner orelse @as(u32, 0) -% 1, group orelse @as(u32, 0) -% 1);541 const res = system.fchown(fd, owner orelse @as(u32, 0) -% 1, group orelse @as(u32, 0) -% 1);
...@@ -675,7 +673,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {...@@ -675,7 +673,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
675}673}
676674
677fn getRandomBytesDevURandom(buf: []u8) !void {675fn getRandomBytesDevURandom(buf: []u8) !void {
678 const fd = try openZ("/dev/urandom", O.RDONLY | O.CLOEXEC, 0);676 const fd = try openZ("/dev/urandom", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
679 defer close(fd);677 defer close(fd);
680678
681 const st = try fstat(fd);679 const st = try fstat(fd);
...@@ -1590,18 +1588,18 @@ pub const OpenError = error{...@@ -1590,18 +1588,18 @@ pub const OpenError = error{
1590 /// for 64-bit targets, as well as when opening directories.1588 /// for 64-bit targets, as well as when opening directories.
1591 FileTooBig,1589 FileTooBig,
15921590
1593 /// The path refers to directory but the `O.DIRECTORY` flag was not provided.1591 /// The path refers to directory but the `DIRECTORY` flag was not provided.
1594 IsDir,1592 IsDir,
15951593
1596 /// A new path cannot be created because the device has no room for the new file.1594 /// A new path cannot be created because the device has no room for the new file.
1597 /// This error is only reachable when the `O.CREAT` flag is provided.1595 /// This error is only reachable when the `CREAT` flag is provided.
1598 NoSpaceLeft,1596 NoSpaceLeft,
15991597
1600 /// A component used as a directory in the path was not, in fact, a directory, or1598 /// A component used as a directory in the path was not, in fact, a directory, or
1601 /// `O.DIRECTORY` was specified and the path was not a directory.1599 /// `DIRECTORY` was specified and the path was not a directory.
1602 NotDir,1600 NotDir,
16031601
1604 /// The path already exists and the `O.CREAT` and `O.EXCL` flags were provided.1602 /// The path already exists and the `CREAT` and `EXCL` flags were provided.
1605 PathAlreadyExists,1603 PathAlreadyExists,
1606 DeviceBusy,1604 DeviceBusy,
16071605
...@@ -1629,12 +1627,11 @@ pub const OpenError = error{...@@ -1629,12 +1627,11 @@ pub const OpenError = error{
16291627
1630/// Open and possibly create a file. Keeps trying if it gets interrupted.1628/// Open and possibly create a file. Keeps trying if it gets interrupted.
1631/// See also `openZ`.1629/// See also `openZ`.
1632pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {1630pub fn open(file_path: []const u8, flags: O, perm: mode_t) OpenError!fd_t {
1633 if (builtin.os.tag == .windows) {1631 if (builtin.os.tag == .windows) {
1634 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);1632 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
1635 return openW(file_path_w.span(), flags, perm);
1636 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1633 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1637 return openat(wasi.AT.FDCWD, file_path, flags, perm);1634 return openat(AT.FDCWD, file_path, flags, perm);
1638 }1635 }
1639 const file_path_c = try toPosixPath(file_path);1636 const file_path_c = try toPosixPath(file_path);
1640 return openZ(&file_path_c, flags, perm);1637 return openZ(&file_path_c, flags, perm);
...@@ -1642,10 +1639,9 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {...@@ -1642,10 +1639,9 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
16421639
1643/// Open and possibly create a file. Keeps trying if it gets interrupted.1640/// Open and possibly create a file. Keeps trying if it gets interrupted.
1644/// See also `open`.1641/// See also `open`.
1645pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t {1642pub fn openZ(file_path: [*:0]const u8, flags: O, perm: mode_t) OpenError!fd_t {
1646 if (builtin.os.tag == .windows) {1643 if (builtin.os.tag == .windows) {
1647 const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);1644 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
1648 return openW(file_path_w.span(), flags, perm);
1649 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1645 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1650 return open(mem.sliceTo(file_path, 0), flags, perm);1646 return open(mem.sliceTo(file_path, 0), flags, perm);
1651 }1647 }
...@@ -1681,64 +1677,15 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t...@@ -1681,64 +1677,15 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
1681 }1677 }
1682}1678}
16831679
1684fn openOptionsFromFlagsWindows(flags: u32) windows.OpenFileOptions {
1685 const w = windows;
1686
1687 var access_mask: w.ULONG = w.READ_CONTROL | w.FILE_WRITE_ATTRIBUTES | w.SYNCHRONIZE;
1688 if (flags & O.RDWR != 0) {
1689 access_mask |= w.GENERIC_READ | w.GENERIC_WRITE;
1690 } else if (flags & O.WRONLY != 0) {
1691 access_mask |= w.GENERIC_WRITE;
1692 } else {
1693 access_mask |= w.GENERIC_READ | w.GENERIC_WRITE;
1694 }
1695
1696 const filter: windows.OpenFileOptions.Filter = if (flags & O.DIRECTORY != 0) .dir_only else .file_only;
1697 const follow_symlinks: bool = flags & O.NOFOLLOW == 0;
1698
1699 const creation: w.ULONG = blk: {
1700 if (flags & O.CREAT != 0) {
1701 if (flags & O.EXCL != 0) {
1702 break :blk w.FILE_CREATE;
1703 }
1704 }
1705 break :blk w.FILE_OPEN;
1706 };
1707
1708 return .{
1709 .access_mask = access_mask,
1710 .creation = creation,
1711 .filter = filter,
1712 .follow_symlinks = follow_symlinks,
1713 };
1714}
1715
1716/// Windows-only. The path parameter is
1717/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
1718/// Translates the POSIX open API call to a Windows API call.
1719/// TODO currently, this function does not handle all flag combinations
1720/// or makes use of perm argument.
1721pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t {
1722 _ = perm;
1723 var options = openOptionsFromFlagsWindows(flags);
1724 options.dir = std.fs.cwd().fd;
1725 return windows.OpenFile(file_path_w, options) catch |err| switch (err) {
1726 error.WouldBlock => unreachable,
1727 error.PipeBusy => unreachable,
1728 else => |e| return e,
1729 };
1730}
1731
1732/// Open and possibly create a file. Keeps trying if it gets interrupted.1680/// Open and possibly create a file. Keeps trying if it gets interrupted.
1733/// `file_path` is relative to the open directory handle `dir_fd`.1681/// `file_path` is relative to the open directory handle `dir_fd`.
1734/// See also `openatZ`.1682/// See also `openatZ`.
1735pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {1683pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: O, mode: mode_t) OpenError!fd_t {
1736 if (builtin.os.tag == .windows) {1684 if (builtin.os.tag == .windows) {
1737 const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path);1685 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
1738 return openatW(dir_fd, file_path_w.span(), flags, mode);
1739 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1686 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1740 // `mode` is ignored on WASI, which does not support unix-style file permissions1687 // `mode` is ignored on WASI, which does not support unix-style file permissions
1741 const opts = try openOptionsFromFlagsWasi(dir_fd, flags);1688 const opts = try openOptionsFromFlagsWasi(flags);
1742 const fd = try openatWasi(1689 const fd = try openatWasi(
1743 dir_fd,1690 dir_fd,
1744 file_path,1691 file_path,
...@@ -1750,8 +1697,8 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope...@@ -1750,8 +1697,8 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
1750 );1697 );
1751 errdefer close(fd);1698 errdefer close(fd);
17521699
1753 if (flags & O.WRONLY != 0) {1700 if (flags.write) {
1754 const info = try fstat(fd);1701 const info = try fstat_wasi(fd);
1755 if (info.filetype == .DIRECTORY)1702 if (info.filetype == .DIRECTORY)
1756 return error.IsDir;1703 return error.IsDir;
1757 }1704 }
...@@ -1762,6 +1709,37 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope...@@ -1762,6 +1709,37 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
1762 return openatZ(dir_fd, &file_path_c, flags, mode);1709 return openatZ(dir_fd, &file_path_c, flags, mode);
1763}1710}
17641711
1712pub const CommonOpenFlags = packed struct {
1713 ACCMODE: ACCMODE = .RDONLY,
1714 CREAT: bool = false,
1715 EXCL: bool = false,
1716 LARGEFILE: bool = false,
1717 DIRECTORY: bool = false,
1718 CLOEXEC: bool = false,
1719 NONBLOCK: bool = false,
1720
1721 pub fn lower(cof: CommonOpenFlags) O {
1722 if (builtin.os.tag == .wasi) return .{
1723 .read = cof.ACCMODE != .WRONLY,
1724 .write = cof.ACCMODE != .RDONLY,
1725 .CREAT = cof.CREAT,
1726 .EXCL = cof.EXCL,
1727 .DIRECTORY = cof.DIRECTORY,
1728 .NONBLOCK = cof.NONBLOCK,
1729 };
1730 var result: O = .{
1731 .ACCMODE = cof.ACCMODE,
1732 .CREAT = cof.CREAT,
1733 .EXCL = cof.EXCL,
1734 .DIRECTORY = cof.DIRECTORY,
1735 .NONBLOCK = cof.NONBLOCK,
1736 .CLOEXEC = cof.CLOEXEC,
1737 };
1738 if (@hasField(O, "LARGEFILE")) result.LARGEFILE = cof.LARGEFILE;
1739 return result;
1740 }
1741};
1742
1765/// A struct to contain all lookup/rights flags accepted by `wasi.path_open`1743/// A struct to contain all lookup/rights flags accepted by `wasi.path_open`
1766const WasiOpenOptions = struct {1744const WasiOpenOptions = struct {
1767 oflags: wasi.oflags_t,1745 oflags: wasi.oflags_t,
...@@ -1772,42 +1750,38 @@ const WasiOpenOptions = struct {...@@ -1772,42 +1750,38 @@ const WasiOpenOptions = struct {
1772};1750};
17731751
1774/// Compute rights + flags corresponding to the provided POSIX access mode.1752/// Compute rights + flags corresponding to the provided POSIX access mode.
1775fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {1753fn openOptionsFromFlagsWasi(oflag: O) OpenError!WasiOpenOptions {
1776 const w = std.os.wasi;1754 const w = std.os.wasi;
17771755
1778 // First, discover the rights that we can derive from `fd`
1779 var fsb_cur: wasi.fdstat_t = undefined;
1780 _ = switch (w.fd_fdstat_get(fd, &fsb_cur)) {
1781 .SUCCESS => .{},
1782 .BADF => return error.InvalidHandle,
1783 else => |err| return unexpectedErrno(err),
1784 };
1785
1786 // Next, calculate the read/write rights to request, depending on the1756 // Next, calculate the read/write rights to request, depending on the
1787 // provided POSIX access mode1757 // provided POSIX access mode
1788 var rights: w.rights_t = 0;1758 var rights: w.rights_t = .{};
1789 if (oflag & O.RDONLY != 0) {1759 if (oflag.read) {
1790 rights |= w.RIGHT.FD_READ | w.RIGHT.FD_READDIR;1760 rights.FD_READ = true;
1761 rights.FD_READDIR = true;
1791 }1762 }
1792 if (oflag & O.WRONLY != 0) {1763 if (oflag.write) {
1793 rights |= w.RIGHT.FD_DATASYNC | w.RIGHT.FD_WRITE |1764 rights.FD_DATASYNC = true;
1794 w.RIGHT.FD_ALLOCATE | w.RIGHT.FD_FILESTAT_SET_SIZE;1765 rights.FD_WRITE = true;
1766 rights.FD_ALLOCATE = true;
1767 rights.FD_FILESTAT_SET_SIZE = true;
1795 }1768 }
17961769
1797 // Request all other rights unconditionally1770 // https://github.com/ziglang/zig/issues/18882
1798 rights |= ~(w.RIGHT.FD_DATASYNC | w.RIGHT.FD_READ |1771 const flag_bits: u32 = @bitCast(oflag);
1799 w.RIGHT.FD_WRITE | w.RIGHT.FD_ALLOCATE |1772 const oflags_int: u16 = @as(u12, @truncate(flag_bits >> 12));
1800 w.RIGHT.FD_READDIR | w.RIGHT.FD_FILESTAT_SET_SIZE);1773 const fs_flags_int: u16 = @as(u12, @truncate(flag_bits));
1801
1802 // But only take rights that we can actually inherit
1803 rights &= fsb_cur.fs_rights_inheriting;
18041774
1805 return WasiOpenOptions{1775 return .{
1806 .oflags = @as(w.oflags_t, @truncate((oflag >> 12))) & 0xfff,1776 // https://github.com/ziglang/zig/issues/18882
1807 .lookup_flags = if (oflag & O.NOFOLLOW == 0) w.LOOKUP_SYMLINK_FOLLOW else 0,1777 .oflags = @bitCast(oflags_int),
1778 .lookup_flags = .{
1779 .SYMLINK_FOLLOW = !oflag.NOFOLLOW,
1780 },
1808 .fs_rights_base = rights,1781 .fs_rights_base = rights,
1809 .fs_rights_inheriting = fsb_cur.fs_rights_inheriting,1782 .fs_rights_inheriting = rights,
1810 .fs_flags = @as(w.fdflags_t, @truncate(oflag & 0xfff)),1783 // https://github.com/ziglang/zig/issues/18882
1784 .fs_flags = @bitCast(fs_flags_int),
1811 };1785 };
1812}1786}
18131787
...@@ -1815,11 +1789,11 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {...@@ -1815,11 +1789,11 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {
1815pub fn openatWasi(1789pub fn openatWasi(
1816 dir_fd: fd_t,1790 dir_fd: fd_t,
1817 file_path: []const u8,1791 file_path: []const u8,
1818 lookup_flags: lookupflags_t,1792 lookup_flags: wasi.lookupflags_t,
1819 oflags: oflags_t,1793 oflags: wasi.oflags_t,
1820 fdflags: fdflags_t,1794 fdflags: wasi.fdflags_t,
1821 base: rights_t,1795 base: wasi.rights_t,
1822 inheriting: rights_t,1796 inheriting: wasi.rights_t,
1823) OpenError!fd_t {1797) OpenError!fd_t {
1824 while (true) {1798 while (true) {
1825 var fd: fd_t = undefined;1799 var fd: fd_t = undefined;
...@@ -1829,6 +1803,7 @@ pub fn openatWasi(...@@ -1829,6 +1803,7 @@ pub fn openatWasi(
18291803
1830 .FAULT => unreachable,1804 .FAULT => unreachable,
1831 .INVAL => unreachable,1805 .INVAL => unreachable,
1806 .BADF => unreachable,
1832 .ACCES => return error.AccessDenied,1807 .ACCES => return error.AccessDenied,
1833 .FBIG => return error.FileTooBig,1808 .FBIG => return error.FileTooBig,
1834 .OVERFLOW => return error.FileTooBig,1809 .OVERFLOW => return error.FileTooBig,
...@@ -1854,10 +1829,9 @@ pub fn openatWasi(...@@ -1854,10 +1829,9 @@ pub fn openatWasi(
1854/// Open and possibly create a file. Keeps trying if it gets interrupted.1829/// Open and possibly create a file. Keeps trying if it gets interrupted.
1855/// `file_path` is relative to the open directory handle `dir_fd`.1830/// `file_path` is relative to the open directory handle `dir_fd`.
1856/// See also `openat`.1831/// See also `openat`.
1857pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {1832pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: O, mode: mode_t) OpenError!fd_t {
1858 if (builtin.os.tag == .windows) {1833 if (builtin.os.tag == .windows) {
1859 const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path);1834 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
1860 return openatW(dir_fd, file_path_w.span(), flags, mode);
1861 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {1835 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1862 return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);1836 return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);
1863 }1837 }
...@@ -1897,21 +1871,6 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)...@@ -1897,21 +1871,6 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
1897 }1871 }
1898}1872}
18991873
1900/// Windows-only. Similar to `openat` but with pathname argument null-terminated
1901/// WTF16 encoded.
1902/// TODO currently, this function does not handle all flag combinations
1903/// or makes use of perm argument.
1904pub fn openatW(dir_fd: fd_t, file_path_w: []const u16, flags: u32, mode: mode_t) OpenError!fd_t {
1905 _ = mode;
1906 var options = openOptionsFromFlagsWindows(flags);
1907 options.dir = dir_fd;
1908 return windows.OpenFile(file_path_w, options) catch |err| switch (err) {
1909 error.WouldBlock => unreachable,
1910 error.PipeBusy => unreachable,
1911 else => |e| return e,
1912 };
1913}
1914
1915pub fn dup(old_fd: fd_t) !fd_t {1874pub fn dup(old_fd: fd_t) !fd_t {
1916 const rc = system.dup(old_fd);1875 const rc = system.dup(old_fd);
1917 return switch (errno(rc)) {1876 return switch (errno(rc)) {
...@@ -2403,42 +2362,43 @@ pub fn linkat(...@@ -2403,42 +2362,43 @@ pub fn linkat(
2403 if (builtin.os.tag == .wasi and !builtin.link_libc) {2362 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2404 const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };2363 const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };
2405 const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath };2364 const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath };
2406 return linkatWasi(old, new, flags);2365 const old_flags: wasi.lookupflags_t = .{
2366 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_FOLLOW) != 0,
2367 };
2368 switch (wasi.path_link(
2369 old.dir_fd,
2370 old_flags,
2371 old.relative_path.ptr,
2372 old.relative_path.len,
2373 new.dir_fd,
2374 new.relative_path.ptr,
2375 new.relative_path.len,
2376 )) {
2377 .SUCCESS => return,
2378 .ACCES => return error.AccessDenied,
2379 .DQUOT => return error.DiskQuota,
2380 .EXIST => return error.PathAlreadyExists,
2381 .FAULT => unreachable,
2382 .IO => return error.FileSystem,
2383 .LOOP => return error.SymLinkLoop,
2384 .MLINK => return error.LinkQuotaExceeded,
2385 .NAMETOOLONG => return error.NameTooLong,
2386 .NOENT => return error.FileNotFound,
2387 .NOMEM => return error.SystemResources,
2388 .NOSPC => return error.NoSpaceLeft,
2389 .NOTDIR => return error.NotDir,
2390 .PERM => return error.AccessDenied,
2391 .ROFS => return error.ReadOnlyFileSystem,
2392 .XDEV => return error.NotSameFileSystem,
2393 .INVAL => unreachable,
2394 else => |err| return unexpectedErrno(err),
2395 }
2407 }2396 }
2408 const old = try toPosixPath(oldpath);2397 const old = try toPosixPath(oldpath);
2409 const new = try toPosixPath(newpath);2398 const new = try toPosixPath(newpath);
2410 return try linkatZ(olddir, &old, newdir, &new, flags);2399 return try linkatZ(olddir, &old, newdir, &new, flags);
2411}2400}
24122401
2413/// WASI-only. The same as `linkat` but targeting WASI.
2414/// See also `linkat`.
2415pub fn linkatWasi(old: RelativePathWasi, new: RelativePathWasi, flags: i32) LinkatError!void {
2416 var old_flags: wasi.lookupflags_t = 0;
2417 // TODO: Why is this not defined in wasi-libc?
2418 if (flags & linux.AT.SYMLINK_FOLLOW != 0) old_flags |= wasi.LOOKUP_SYMLINK_FOLLOW;
2419
2420 switch (wasi.path_link(old.dir_fd, old_flags, old.relative_path.ptr, old.relative_path.len, new.dir_fd, new.relative_path.ptr, new.relative_path.len)) {
2421 .SUCCESS => return,
2422 .ACCES => return error.AccessDenied,
2423 .DQUOT => return error.DiskQuota,
2424 .EXIST => return error.PathAlreadyExists,
2425 .FAULT => unreachable,
2426 .IO => return error.FileSystem,
2427 .LOOP => return error.SymLinkLoop,
2428 .MLINK => return error.LinkQuotaExceeded,
2429 .NAMETOOLONG => return error.NameTooLong,
2430 .NOENT => return error.FileNotFound,
2431 .NOMEM => return error.SystemResources,
2432 .NOSPC => return error.NoSpaceLeft,
2433 .NOTDIR => return error.NotDir,
2434 .PERM => return error.AccessDenied,
2435 .ROFS => return error.ReadOnlyFileSystem,
2436 .XDEV => return error.NotSameFileSystem,
2437 .INVAL => unreachable,
2438 else => |err| return unexpectedErrno(err),
2439 }
2440}
2441
2442pub const UnlinkError = error{2402pub const UnlinkError = error{
2443 FileNotFound,2403 FileNotFound,
24442404
...@@ -3404,20 +3364,16 @@ pub fn isatty(handle: fd_t) bool {...@@ -3404,20 +3364,16 @@ pub fn isatty(handle: fd_t) bool {
3404 return system.isatty(handle) != 0;3364 return system.isatty(handle) != 0;
3405 }3365 }
3406 if (builtin.os.tag == .wasi) {3366 if (builtin.os.tag == .wasi) {
3407 var statbuf: fdstat_t = undefined;3367 var statbuf: wasi.fdstat_t = undefined;
3408 const err = system.fd_fdstat_get(handle, &statbuf);3368 const err = wasi.fd_fdstat_get(handle, &statbuf);
3409 if (err != .SUCCESS) {3369 if (err != .SUCCESS)
3410 // errno = err;
3411 return false;3370 return false;
3412 }
34133371
3414 // A tty is a character device that we can't seek or tell on.3372 // A tty is a character device that we can't seek or tell on.
3415 if (statbuf.fs_filetype != .CHARACTER_DEVICE or3373 if (statbuf.fs_filetype != .CHARACTER_DEVICE)
3416 (statbuf.fs_rights_base & (RIGHT.FD_SEEK | RIGHT.FD_TELL)) != 0)3374 return false;
3417 {3375 if (statbuf.fs_rights_base.FD_SEEK or statbuf.fs_rights_base.FD_TELL)
3418 // errno = ENOTTY;
3419 return false;3376 return false;
3420 }
34213377
3422 return true;3378 return true;
3423 }3379 }
...@@ -3838,11 +3794,11 @@ pub fn accept(...@@ -3838,11 +3794,11 @@ pub fn accept(
3838 /// will return a value greater than was supplied to the call.3794 /// will return a value greater than was supplied to the call.
3839 addr_size: ?*socklen_t,3795 addr_size: ?*socklen_t,
3840 /// The following values can be bitwise ORed in flags to obtain different behavior:3796 /// The following values can be bitwise ORed in flags to obtain different behavior:
3841 /// * `SOCK.NONBLOCK` - Set the `O.NONBLOCK` file status flag on the open file description (see `open`)3797 /// * `SOCK.NONBLOCK` - Set the `NONBLOCK` file status flag on the open file description (see `open`)
3842 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve3798 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
3843 /// the same result.3799 /// the same result.
3844 /// * `SOCK.CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the3800 /// * `SOCK.CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
3845 /// description of the `O.CLOEXEC` flag in `open` for reasons why this may be useful.3801 /// description of the `CLOEXEC` flag in `open` for reasons why this may be useful.
3846 flags: u32,3802 flags: u32,
3847) AcceptError!socket_t {3803) AcceptError!socket_t {
3848 const have_accept4 = comptime !(builtin.target.isDarwin() or builtin.os.tag == .windows);3804 const have_accept4 = comptime !(builtin.target.isDarwin() or builtin.os.tag == .windows);
...@@ -4278,16 +4234,7 @@ pub const FStatError = error{...@@ -4278,16 +4234,7 @@ pub const FStatError = error{
4278/// Return information about a file descriptor.4234/// Return information about a file descriptor.
4279pub fn fstat(fd: fd_t) FStatError!Stat {4235pub fn fstat(fd: fd_t) FStatError!Stat {
4280 if (builtin.os.tag == .wasi and !builtin.link_libc) {4236 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4281 var stat: wasi.filestat_t = undefined;4237 return Stat.fromFilestat(try fstat_wasi(fd));
4282 switch (wasi.fd_filestat_get(fd, &stat)) {
4283 .SUCCESS => return Stat.fromFilestat(stat),
4284 .INVAL => unreachable,
4285 .BADF => unreachable, // Always a race condition.
4286 .NOMEM => return error.SystemResources,
4287 .ACCES => return error.AccessDenied,
4288 .NOTCAPABLE => return error.AccessDenied,
4289 else => |err| return unexpectedErrno(err),
4290 }
4291 }4238 }
4292 if (builtin.os.tag == .windows) {4239 if (builtin.os.tag == .windows) {
4293 @compileError("fstat is not yet implemented on Windows");4240 @compileError("fstat is not yet implemented on Windows");
...@@ -4306,15 +4253,30 @@ pub fn fstat(fd: fd_t) FStatError!Stat {...@@ -4306,15 +4253,30 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
4306 }4253 }
4307}4254}
43084255
4256pub fn fstat_wasi(fd: fd_t) FStatError!wasi.filestat_t {
4257 var stat: wasi.filestat_t = undefined;
4258 switch (wasi.fd_filestat_get(fd, &stat)) {
4259 .SUCCESS => return stat,
4260 .INVAL => unreachable,
4261 .BADF => unreachable, // Always a race condition.
4262 .NOMEM => return error.SystemResources,
4263 .ACCES => return error.AccessDenied,
4264 .NOTCAPABLE => return error.AccessDenied,
4265 else => |err| return unexpectedErrno(err),
4266 }
4267}
4268
4309pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLinkLoop };4269pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLinkLoop };
43104270
4311/// Similar to `fstat`, but returns stat of a resource pointed to by `pathname`4271/// Similar to `fstat`, but returns stat of a resource pointed to by `pathname`
4312/// which is relative to `dirfd` handle.4272/// which is relative to `dirfd` handle.
4313/// See also `fstatatZ` and `fstatatWasi`.4273/// See also `fstatatZ` and `fstatat_wasi`.
4314pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {4274pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
4315 if (builtin.os.tag == .wasi and !builtin.link_libc) {4275 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4316 const wasi_flags = if (flags & linux.AT.SYMLINK_NOFOLLOW == 0) wasi.LOOKUP_SYMLINK_FOLLOW else 0;4276 const filestat = try fstatat_wasi(dirfd, pathname, .{
4317 return fstatatWasi(dirfd, pathname, wasi_flags);4277 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
4278 });
4279 return Stat.fromFilestat(filestat);
4318 } else if (builtin.os.tag == .windows) {4280 } else if (builtin.os.tag == .windows) {
4319 @compileError("fstatat is not yet implemented on Windows");4281 @compileError("fstatat is not yet implemented on Windows");
4320 } else {4282 } else {
...@@ -4325,10 +4287,10 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat...@@ -4325,10 +4287,10 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat
43254287
4326/// WASI-only. Same as `fstatat` but targeting WASI.4288/// WASI-only. Same as `fstatat` but targeting WASI.
4327/// See also `fstatat`.4289/// See also `fstatat`.
4328pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {4290pub fn fstatat_wasi(dirfd: fd_t, pathname: []const u8, flags: wasi.lookupflags_t) FStatAtError!wasi.filestat_t {
4329 var stat: wasi.filestat_t = undefined;4291 var stat: wasi.filestat_t = undefined;
4330 switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) {4292 switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) {
4331 .SUCCESS => return Stat.fromFilestat(stat),4293 .SUCCESS => return stat,
4332 .INVAL => unreachable,4294 .INVAL => unreachable,
4333 .BADF => unreachable, // Always a race condition.4295 .BADF => unreachable, // Always a race condition.
4334 .NOMEM => return error.SystemResources,4296 .NOMEM => return error.SystemResources,
...@@ -4346,7 +4308,10 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S...@@ -4346,7 +4308,10 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
4346/// See also `fstatat`.4308/// See also `fstatat`.
4347pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {4309pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
4348 if (builtin.os.tag == .wasi and !builtin.link_libc) {4310 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4349 return fstatatWasi(dirfd, mem.sliceTo(pathname), flags);4311 const filestat = try fstatat_wasi(dirfd, mem.sliceTo(pathname, 0), .{
4312 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
4313 });
4314 return Stat.fromFilestat(filestat);
4350 }4315 }
43514316
4352 const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;4317 const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
...@@ -4627,7 +4592,7 @@ pub const MMapError = error{...@@ -4627,7 +4592,7 @@ pub const MMapError = error{
46274592
4628 /// A file descriptor refers to a non-regular file. Or a file mapping was requested,4593 /// A file descriptor refers to a non-regular file. Or a file mapping was requested,
4629 /// but the file descriptor is not open for reading. Or `MAP.SHARED` was requested4594 /// but the file descriptor is not open for reading. Or `MAP.SHARED` was requested
4630 /// and `PROT_WRITE` is set, but the file descriptor is not open in `O.RDWR` mode.4595 /// and `PROT_WRITE` is set, but the file descriptor is not open in `RDWR` mode.
4631 /// Or `PROT_WRITE` is set, but the file is append-only.4596 /// Or `PROT_WRITE` is set, but the file is append-only.
4632 AccessDenied,4597 AccessDenied,
46334598
...@@ -4795,10 +4760,12 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr...@@ -4795,10 +4760,12 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
4795 const path_w = try windows.sliceToPrefixedFileW(dirfd, path);4760 const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
4796 return faccessatW(dirfd, path_w.span().ptr, mode, flags);4761 return faccessatW(dirfd, path_w.span().ptr, mode, flags);
4797 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {4762 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
4798 const resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path };4763 const resolved: RelativePathWasi = .{ .dir_fd = dirfd, .relative_path = path };
47994764
4800 const file = blk: {4765 const st = blk: {
4801 break :blk fstatat(dirfd, path, flags);4766 break :blk fstatat_wasi(dirfd, path, .{
4767 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
4768 });
4802 } catch |err| switch (err) {4769 } catch |err| switch (err) {
4803 error.AccessDenied => return error.PermissionDenied,4770 error.AccessDenied => return error.PermissionDenied,
4804 else => |e| return e,4771 else => |e| return e,
...@@ -4810,19 +4777,23 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr...@@ -4810,19 +4777,23 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
4810 return error.PermissionDenied;4777 return error.PermissionDenied;
4811 }4778 }
48124779
4813 var rights: wasi.rights_t = 0;4780 var rights: wasi.rights_t = .{};
4814 if (mode & R_OK != 0) {4781 if (mode & R_OK != 0) {
4815 rights |= if (file.filetype == .DIRECTORY)4782 if (st.filetype == .DIRECTORY) {
4816 wasi.RIGHT.FD_READDIR4783 rights.FD_READDIR = true;
4817 else4784 } else {
4818 wasi.RIGHT.FD_READ;4785 rights.FD_READ = true;
4786 }
4819 }4787 }
4820 if (mode & W_OK != 0) {4788 if (mode & W_OK != 0) {
4821 rights |= wasi.RIGHT.FD_WRITE;4789 rights.FD_WRITE = true;
4822 }4790 }
4823 // No validation for X_OK4791 // No validation for X_OK
48244792
4825 if ((rights & directory.fs_rights_inheriting) != rights) {4793 // https://github.com/ziglang/zig/issues/18882
4794 const rights_int: u64 = @bitCast(rights);
4795 const inheriting_int: u64 = @bitCast(directory.fs_rights_inheriting);
4796 if ((rights_int & inheriting_int) != rights_int) {
4826 return error.PermissionDenied;4797 return error.PermissionDenied;
4827 }4798 }
4828 }4799 }
...@@ -4915,7 +4886,7 @@ pub fn pipe() PipeError![2]fd_t {...@@ -4915,7 +4886,7 @@ pub fn pipe() PipeError![2]fd_t {
4915 }4886 }
4916}4887}
49174888
4918pub fn pipe2(flags: u32) PipeError![2]fd_t {4889pub fn pipe2(flags: O) PipeError![2]fd_t {
4919 if (@hasDecl(system, "pipe2")) {4890 if (@hasDecl(system, "pipe2")) {
4920 var fds: [2]fd_t = undefined;4891 var fds: [2]fd_t = undefined;
4921 switch (errno(system.pipe2(&fds, flags))) {4892 switch (errno(system.pipe2(&fds, flags))) {
...@@ -4934,12 +4905,13 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {...@@ -4934,12 +4905,13 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
4934 close(fds[1]);4905 close(fds[1]);
4935 }4906 }
49364907
4937 if (flags == 0)4908 // https://github.com/ziglang/zig/issues/18882
4909 if (@as(u32, @bitCast(flags)) == 0)
4938 return fds;4910 return fds;
49394911
4940 // O.CLOEXEC is special, it's a file descriptor flag and must be set using4912 // CLOEXEC is special, it's a file descriptor flag and must be set using
4941 // F.SETFD.4913 // F.SETFD.
4942 if (flags & O.CLOEXEC != 0) {4914 if (flags.CLOEXEC) {
4943 for (fds) |fd| {4915 for (fds) |fd| {
4944 switch (errno(system.fcntl(fd, F.SETFD, @as(u32, FD_CLOEXEC)))) {4916 switch (errno(system.fcntl(fd, F.SETFD, @as(u32, FD_CLOEXEC)))) {
4945 .SUCCESS => {},4917 .SUCCESS => {},
...@@ -4950,7 +4922,11 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {...@@ -4950,7 +4922,11 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
4950 }4922 }
4951 }4923 }
49524924
4953 const new_flags = flags & ~@as(u32, O.CLOEXEC);4925 const new_flags: u32 = f: {
4926 var new_flags = flags;
4927 new_flags.CLOEXEC = false;
4928 break :f @bitCast(new_flags);
4929 };
4954 // Set every other flag affecting the file status using F.SETFL.4930 // Set every other flag affecting the file status using F.SETFL.
4955 if (new_flags != 0) {4931 if (new_flags != 0) {
4956 for (fds) |fd| {4932 for (fds) |fd| {
...@@ -5289,7 +5265,7 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {...@@ -5289,7 +5265,7 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
5289 error.LockedRegionLimitExceeded => unreachable,5265 error.LockedRegionLimitExceeded => unreachable,
5290 else => |e| return e,5266 else => |e| return e,
5291 };5267 };
5292 fl_flags |= O.NONBLOCK;5268 fl_flags |= 1 << @bitOffsetOf(O, "NONBLOCK");
5293 _ = fcntl(sock, F.SETFL, fl_flags) catch |err| switch (err) {5269 _ = fcntl(sock, F.SETFL, fl_flags) catch |err| switch (err) {
5294 error.FileBusy => unreachable,5270 error.FileBusy => unreachable,
5295 error.Locked => unreachable,5271 error.Locked => unreachable,
...@@ -5389,7 +5365,17 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP...@@ -5389,7 +5365,17 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
5389 return realpath(mem.sliceTo(pathname, 0), out_buffer);5365 return realpath(mem.sliceTo(pathname, 0), out_buffer);
5390 }5366 }
5391 if (!builtin.link_libc) {5367 if (!builtin.link_libc) {
5392 const flags = if (builtin.os.tag == .linux) O.PATH | O.NONBLOCK | O.CLOEXEC else O.NONBLOCK | O.CLOEXEC;5368 const flags: O = switch (builtin.os.tag) {
5369 .linux => .{
5370 .NONBLOCK = true,
5371 .CLOEXEC = true,
5372 .PATH = true,
5373 },
5374 else => .{
5375 .NONBLOCK = true,
5376 .CLOEXEC = true,
5377 },
5378 };
5393 const fd = openZ(pathname, flags, 0) catch |err| switch (err) {5379 const fd = openZ(pathname, flags, 0) catch |err| switch (err) {
5394 error.FileLocksNotSupported => unreachable,5380 error.FileLocksNotSupported => unreachable,
5395 error.WouldBlock => unreachable,5381 error.WouldBlock => unreachable,
...@@ -5893,7 +5879,10 @@ pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {...@@ -5893,7 +5879,10 @@ pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {
5893 // this here, but we should really handle it somehow.5879 // this here, but we should really handle it somehow.
5894 const atim = times[0].toTimestamp();5880 const atim = times[0].toTimestamp();
5895 const mtim = times[1].toTimestamp();5881 const mtim = times[1].toTimestamp();
5896 switch (wasi.fd_filestat_set_times(fd, atim, mtim, wasi.FILESTAT_SET_ATIM | wasi.FILESTAT_SET_MTIM)) {5882 switch (wasi.fd_filestat_set_times(fd, atim, mtim, .{
5883 .ATIM = true,
5884 .MTIM = true,
5885 })) {
5897 .SUCCESS => return,5886 .SUCCESS => return,
5898 .ACCES => return error.AccessDenied,5887 .ACCES => return error.AccessDenied,
5899 .PERM => return error.PermissionDenied,5888 .PERM => return error.PermissionDenied,
...@@ -6390,7 +6379,7 @@ pub fn sendfile(...@@ -6390,7 +6379,7 @@ pub fn sendfile(
6390 // * Descriptor is not valid or locked6379 // * Descriptor is not valid or locked
6391 // * an mmap(2)-like operation is not available for in_fd6380 // * an mmap(2)-like operation is not available for in_fd
6392 // * count is negative6381 // * count is negative
6393 // * out_fd has the O.APPEND flag set6382 // * out_fd has the APPEND flag set
6394 // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write6383 // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write
6395 // manually, the same as ENOSYS.6384 // manually, the same as ENOSYS.
6396 break :sf;6385 break :sf;
...@@ -6588,7 +6577,7 @@ pub const CopyFileRangeError = error{...@@ -6588,7 +6577,7 @@ pub const CopyFileRangeError = error{
6588 FileTooBig,6577 FileTooBig,
6589 InputOutput,6578 InputOutput,
6590 /// `fd_in` is not open for reading; or `fd_out` is not open for writing;6579 /// `fd_in` is not open for reading; or `fd_out` is not open for writing;
6591 /// or the `O.APPEND` flag is set for `fd_out`.6580 /// or the `APPEND` flag is set for `fd_out`.
6592 FilesOpenedWithWrongFlags,6581 FilesOpenedWithWrongFlags,
6593 IsDir,6582 IsDir,
6594 OutOfMemory,6583 OutOfMemory,
...@@ -7425,7 +7414,7 @@ pub const TimerFdCreateError = error{...@@ -7425,7 +7414,7 @@ pub const TimerFdCreateError = error{
7425pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;7414pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
7426pub const TimerFdSetError = TimerFdGetError || error{Canceled};7415pub const TimerFdSetError = TimerFdGetError || error{Canceled};
74277416
7428pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {7417pub fn timerfd_create(clokid: i32, flags: linux.TFD) TimerFdCreateError!fd_t {
7429 const rc = linux.timerfd_create(clokid, flags);7418 const rc = linux.timerfd_create(clokid, flags);
7430 return switch (errno(rc)) {7419 return switch (errno(rc)) {
7431 .SUCCESS => @as(fd_t, @intCast(rc)),7420 .SUCCESS => @as(fd_t, @intCast(rc)),
...@@ -7439,7 +7428,12 @@ pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {...@@ -7439,7 +7428,12 @@ pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {
7439 };7428 };
7440}7429}
74417430
7442pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const linux.itimerspec, old_value: ?*linux.itimerspec) TimerFdSetError!void {7431pub fn timerfd_settime(
7432 fd: i32,
7433 flags: linux.TFD.TIMER,
7434 new_value: *const linux.itimerspec,
7435 old_value: ?*linux.itimerspec,
7436) TimerFdSetError!void {
7443 const rc = linux.timerfd_settime(fd, flags, new_value, old_value);7437 const rc = linux.timerfd_settime(fd, flags, new_value, old_value);
7444 return switch (errno(rc)) {7438 return switch (errno(rc)) {
7445 .SUCCESS => {},7439 .SUCCESS => {},
lib/std/os/emscripten.zig-41
...@@ -127,20 +127,6 @@ pub const AF = struct {...@@ -127,20 +127,6 @@ pub const AF = struct {
127 pub const MAX = PF.MAX;127 pub const MAX = PF.MAX;
128};128};
129129
130pub const AT = struct {
131 pub const FDCWD = -100;
132 pub const SYMLINK_NOFOLLOW = 0x100;
133 pub const REMOVEDIR = 0x200;
134 pub const SYMLINK_FOLLOW = 0x400;
135 pub const NO_AUTOMOUNT = 0x800;
136 pub const EMPTY_PATH = 0x1000;
137 pub const STATX_SYNC_TYPE = 0x6000;
138 pub const STATX_SYNC_AS_STAT = 0x0000;
139 pub const STATX_FORCE_SYNC = 0x2000;
140 pub const STATX_DONT_SYNC = 0x4000;
141 pub const RECURSIVE = 0x8000;
142};
143
144pub const CLOCK = struct {130pub const CLOCK = struct {
145 pub const REALTIME = 0;131 pub const REALTIME = 0;
146 pub const MONOTONIC = 1;132 pub const MONOTONIC = 1;
...@@ -479,33 +465,6 @@ pub const MSG = struct {...@@ -479,33 +465,6 @@ pub const MSG = struct {
479 pub const CMSG_CLOEXEC = 0x40000000;465 pub const CMSG_CLOEXEC = 0x40000000;
480};466};
481467
482pub const O = struct {
483 pub const RDONLY = 0o0;
484 pub const WRONLY = 0o1;
485 pub const RDWR = 0o2;
486
487 pub const CREAT = 0o100;
488 pub const EXCL = 0o200;
489 pub const NOCTTY = 0o400;
490 pub const TRUNC = 0o1000;
491 pub const APPEND = 0o2000;
492 pub const NONBLOCK = 0o4000;
493 pub const DSYNC = 0o10000;
494 pub const SYNC = 0o4010000;
495 pub const RSYNC = 0o4010000;
496 pub const DIRECTORY = 0o200000;
497 pub const NOFOLLOW = 0o400000;
498 pub const CLOEXEC = 0o2000000;
499
500 pub const ASYNC = 0o20000;
501 pub const DIRECT = 0o40000;
502 pub const LARGEFILE = 0o100000;
503 pub const NOATIME = 0o1000000;
504 pub const PATH = 0o10000000;
505 pub const TMPFILE = 0o20200000;
506 pub const NDELAY = NONBLOCK;
507};
508
509pub const POLL = struct {468pub const POLL = struct {
510 pub const IN = 0x001;469 pub const IN = 0x001;
511 pub const PRI = 0x002;470 pub const PRI = 0x002;
lib/std/os/linux.zig+206-57
...@@ -20,6 +20,7 @@ const is_ppc64 = native_arch.isPPC64();...@@ -20,6 +20,7 @@ const is_ppc64 = native_arch.isPPC64();
20const is_sparc = native_arch.isSPARC();20const is_sparc = native_arch.isSPARC();
21const iovec = std.os.iovec;21const iovec = std.os.iovec;
22const iovec_const = std.os.iovec_const;22const iovec_const = std.os.iovec_const;
23const ACCMODE = std.os.ACCMODE;
2324
24test {25test {
25 if (builtin.os.tag == .linux) {26 if (builtin.os.tag == .linux) {
...@@ -241,12 +242,145 @@ pub const MAP = switch (native_arch) {...@@ -241,12 +242,145 @@ pub const MAP = switch (native_arch) {
241 else => @compileError("missing std.os.linux.MAP constants for this architecture"),242 else => @compileError("missing std.os.linux.MAP constants for this architecture"),
242};243};
243244
244pub const O = struct {245pub const O = switch (native_arch) {
245 pub usingnamespace arch_bits.O;246 .x86_64 => packed struct(u32) {
246247 ACCMODE: ACCMODE = .RDONLY,
247 pub const RDONLY = 0o0;248 _2: u4 = 0,
248 pub const WRONLY = 0o1;249 CREAT: bool = false,
249 pub const RDWR = 0o2;250 EXCL: bool = false,
251 NOCTTY: bool = false,
252 TRUNC: bool = false,
253 APPEND: bool = false,
254 NONBLOCK: bool = false,
255 DSYNC: bool = false,
256 ASYNC: bool = false,
257 DIRECT: bool = false,
258 _15: u1 = 0,
259 DIRECTORY: bool = false,
260 NOFOLLOW: bool = false,
261 NOATIME: bool = false,
262 CLOEXEC: bool = false,
263 SYNC: bool = false,
264 PATH: bool = false,
265 TMPFILE: bool = false,
266 _: u9 = 0,
267 },
268 .x86, .riscv64 => packed struct(u32) {
269 ACCMODE: ACCMODE = .RDONLY,
270 _2: u4 = 0,
271 CREAT: bool = false,
272 EXCL: bool = false,
273 NOCTTY: bool = false,
274 TRUNC: bool = false,
275 APPEND: bool = false,
276 NONBLOCK: bool = false,
277 DSYNC: bool = false,
278 ASYNC: bool = false,
279 DIRECT: bool = false,
280 LARGEFILE: bool = false,
281 DIRECTORY: bool = false,
282 NOFOLLOW: bool = false,
283 NOATIME: bool = false,
284 CLOEXEC: bool = false,
285 SYNC: bool = false,
286 PATH: bool = false,
287 TMPFILE: bool = false,
288 _: u9 = 0,
289 },
290 .aarch64, .aarch64_be, .arm, .thumb => packed struct(u32) {
291 ACCMODE: ACCMODE = .RDONLY,
292 _2: u4 = 0,
293 CREAT: bool = false,
294 EXCL: bool = false,
295 NOCTTY: bool = false,
296 TRUNC: bool = false,
297 APPEND: bool = false,
298 NONBLOCK: bool = false,
299 DSYNC: bool = false,
300 ASYNC: bool = false,
301 DIRECTORY: bool = false,
302 NOFOLLOW: bool = false,
303 DIRECT: bool = false,
304 LARGEFILE: bool = false,
305 NOATIME: bool = false,
306 CLOEXEC: bool = false,
307 SYNC: bool = false,
308 PATH: bool = false,
309 TMPFILE: bool = false,
310 _: u9 = 0,
311 },
312 .sparc64 => packed struct(u32) {
313 ACCMODE: ACCMODE = .RDONLY,
314 _2: u1 = 0,
315 APPEND: bool = false,
316 _4: u2 = 0,
317 ASYNC: bool = false,
318 _7: u2 = 0,
319 CREAT: bool = false,
320 TRUNC: bool = false,
321 EXCL: bool = false,
322 _12: u1 = 0,
323 DSYNC: bool = false,
324 NONBLOCK: bool = false,
325 NOCTTY: bool = false,
326 DIRECTORY: bool = false,
327 NOFOLLOW: bool = false,
328 _18: u2 = 0,
329 DIRECT: bool = false,
330 NOATIME: bool = false,
331 CLOEXEC: bool = false,
332 SYNC: bool = false,
333 PATH: bool = false,
334 TMPFILE: bool = false,
335 _: u6 = 0,
336 },
337 .mips, .mipsel, .mips64, .mips64el => packed struct(u32) {
338 ACCMODE: ACCMODE = .RDONLY,
339 _2: u1 = 0,
340 APPEND: bool = false,
341 DSYNC: bool = false,
342 _5: u2 = 0,
343 NONBLOCK: bool = false,
344 CREAT: bool = false,
345 TRUNC: bool = false,
346 EXCL: bool = false,
347 NOCTTY: bool = false,
348 ASYNC: bool = false,
349 LARGEFILE: bool = false,
350 SYNC: bool = false,
351 DIRECT: bool = false,
352 DIRECTORY: bool = false,
353 NOFOLLOW: bool = false,
354 NOATIME: bool = false,
355 CLOEXEC: bool = false,
356 _20: u1 = 0,
357 PATH: bool = false,
358 TMPFILE: bool = false,
359 _: u9 = 0,
360 },
361 .powerpc, .powerpcle, .powerpc64, .powerpc64le => packed struct(u32) {
362 ACCMODE: ACCMODE = .RDONLY,
363 _2: u4 = 0,
364 CREAT: bool = false,
365 EXCL: bool = false,
366 NOCTTY: bool = false,
367 TRUNC: bool = false,
368 APPEND: bool = false,
369 NONBLOCK: bool = false,
370 DSYNC: bool = false,
371 ASYNC: bool = false,
372 DIRECTORY: bool = false,
373 NOFOLLOW: bool = false,
374 LARGEFILE: bool = false,
375 DIRECT: bool = false,
376 NOATIME: bool = false,
377 CLOEXEC: bool = false,
378 SYNC: bool = false,
379 PATH: bool = false,
380 TMPFILE: bool = false,
381 _: u9 = 0,
382 },
383 else => @compileError("missing std.os.linux.O constants for this architecture"),
250};384};
251385
252pub usingnamespace @import("linux/io_uring.zig");386pub usingnamespace @import("linux/io_uring.zig");
...@@ -620,20 +754,20 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {...@@ -620,20 +754,20 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {
620 return syscall2(.umount2, @intFromPtr(special), flags);754 return syscall2(.umount2, @intFromPtr(special), flags);
621}755}
622756
623pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: i64) usize {757pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: MAP, fd: i32, offset: i64) usize {
624 if (@hasField(SYS, "mmap2")) {758 if (@hasField(SYS, "mmap2")) {
625 // Make sure the offset is also specified in multiples of page size759 // Make sure the offset is also specified in multiples of page size
626 if ((offset & (MMAP2_UNIT - 1)) != 0)760 if ((offset & (MMAP2_UNIT - 1)) != 0)
627 return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL))));761 return @bitCast(-@as(isize, @intFromEnum(E.INVAL)));
628762
629 return syscall6(763 return syscall6(
630 .mmap2,764 .mmap2,
631 @intFromPtr(address),765 @intFromPtr(address),
632 length,766 length,
633 prot,767 prot,
634 flags,768 @as(u32, @bitCast(flags)),
635 @as(usize, @bitCast(@as(isize, fd))),769 @bitCast(@as(isize, fd)),
636 @as(usize, @truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT)),770 @truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT),
637 );771 );
638 } else {772 } else {
639 return syscall6(773 return syscall6(
...@@ -641,8 +775,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of...@@ -641,8 +775,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
641 @intFromPtr(address),775 @intFromPtr(address),
642 length,776 length,
643 prot,777 prot,
644 flags,778 @as(u32, @bitCast(flags)),
645 @as(usize, @bitCast(@as(isize, fd))),779 @bitCast(@as(isize, fd)),
646 @as(u64, @bitCast(offset)),780 @as(u64, @bitCast(offset)),
647 );781 );
648 }782 }
...@@ -840,12 +974,12 @@ pub fn pipe(fd: *[2]i32) usize {...@@ -840,12 +974,12 @@ pub fn pipe(fd: *[2]i32) usize {
840 }974 }
841}975}
842976
843pub fn pipe2(fd: *[2]i32, flags: u32) usize {977pub fn pipe2(fd: *[2]i32, flags: O) usize {
844 return syscall2(.pipe2, @intFromPtr(fd), flags);978 return syscall2(.pipe2, @intFromPtr(fd), @as(u32, @bitCast(flags)));
845}979}
846980
847pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {981pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
848 return syscall3(.write, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(buf), count);982 return syscall3(.write, @bitCast(@as(isize, fd)), @intFromPtr(buf), count);
849}983}
850984
851pub fn ftruncate(fd: i32, length: i64) usize {985pub fn ftruncate(fd: i32, length: i64) usize {
...@@ -958,15 +1092,15 @@ pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]c...@@ -958,15 +1092,15 @@ pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]c
958 );1092 );
959}1093}
9601094
961pub fn open(path: [*:0]const u8, flags: u32, perm: mode_t) usize {1095pub fn open(path: [*:0]const u8, flags: O, perm: mode_t) usize {
962 if (@hasField(SYS, "open")) {1096 if (@hasField(SYS, "open")) {
963 return syscall3(.open, @intFromPtr(path), flags, perm);1097 return syscall3(.open, @intFromPtr(path), @as(u32, @bitCast(flags)), perm);
964 } else {1098 } else {
965 return syscall4(1099 return syscall4(
966 .openat,1100 .openat,
967 @as(usize, @bitCast(@as(isize, AT.FDCWD))),1101 @bitCast(@as(isize, AT.FDCWD)),
968 @intFromPtr(path),1102 @intFromPtr(path),
969 flags,1103 @as(u32, @bitCast(flags)),
970 perm,1104 perm,
971 );1105 );
972 }1106 }
...@@ -976,9 +1110,9 @@ pub fn create(path: [*:0]const u8, perm: mode_t) usize {...@@ -976,9 +1110,9 @@ pub fn create(path: [*:0]const u8, perm: mode_t) usize {
976 return syscall2(.creat, @intFromPtr(path), perm);1110 return syscall2(.creat, @intFromPtr(path), perm);
977}1111}
9781112
979pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, mode: mode_t) usize {1113pub fn openat(dirfd: i32, path: [*:0]const u8, flags: O, mode: mode_t) usize {
980 // dirfd could be negative, for example AT.FDCWD is -1001114 // dirfd could be negative, for example AT.FDCWD is -100
981 return syscall4(.openat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), flags, mode);1115 return syscall4(.openat, @bitCast(@as(isize, dirfd)), @intFromPtr(path), @as(u32, @bitCast(flags)), mode);
982}1116}
9831117
984/// See also `clone` (from the arch-specific include)1118/// See also `clone` (from the arch-specific include)
...@@ -1800,8 +1934,8 @@ pub fn eventfd(count: u32, flags: u32) usize {...@@ -1800,8 +1934,8 @@ pub fn eventfd(count: u32, flags: u32) usize {
1800 return syscall2(.eventfd2, count, flags);1934 return syscall2(.eventfd2, count, flags);
1801}1935}
18021936
1803pub fn timerfd_create(clockid: i32, flags: u32) usize {1937pub fn timerfd_create(clockid: i32, flags: TFD) usize {
1804 return syscall2(.timerfd_create, @as(usize, @bitCast(@as(isize, clockid))), flags);1938 return syscall2(.timerfd_create, @bitCast(@as(isize, clockid)), @as(u32, @bitCast(flags)));
1805}1939}
18061940
1807pub const itimerspec = extern struct {1941pub const itimerspec = extern struct {
...@@ -1810,11 +1944,11 @@ pub const itimerspec = extern struct {...@@ -1810,11 +1944,11 @@ pub const itimerspec = extern struct {
1810};1944};
18111945
1812pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {1946pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
1813 return syscall2(.timerfd_gettime, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(curr_value));1947 return syscall2(.timerfd_gettime, @bitCast(@as(isize, fd)), @intFromPtr(curr_value));
1814}1948}
18151949
1816pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {1950pub fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
1817 return syscall4(.timerfd_settime, @as(usize, @bitCast(@as(isize, fd))), flags, @intFromPtr(new_value), @intFromPtr(old_value));1951 return syscall4(.timerfd_settime, @bitCast(@as(isize, fd)), @as(u32, @bitCast(flags)), @intFromPtr(new_value), @intFromPtr(old_value));
1818}1952}
18191953
1820// Flags for the 'setitimer' system call1954// Flags for the 'setitimer' system call
...@@ -2478,19 +2612,10 @@ pub const SIG = if (is_mips) struct {...@@ -2478,19 +2612,10 @@ pub const SIG = if (is_mips) struct {
2478pub const kernel_rwf = u32;2612pub const kernel_rwf = u32;
24792613
2480pub const RWF = struct {2614pub const RWF = struct {
2481 /// high priority request, poll if possible
2482 pub const HIPRI: kernel_rwf = 0x00000001;2615 pub const HIPRI: kernel_rwf = 0x00000001;
2483
2484 /// per-IO O.DSYNC
2485 pub const DSYNC: kernel_rwf = 0x00000002;2616 pub const DSYNC: kernel_rwf = 0x00000002;
2486
2487 /// per-IO O.SYNC
2488 pub const SYNC: kernel_rwf = 0x00000004;2617 pub const SYNC: kernel_rwf = 0x00000004;
2489
2490 /// per-IO, return -EAGAIN if operation would block
2491 pub const NOWAIT: kernel_rwf = 0x00000008;2618 pub const NOWAIT: kernel_rwf = 0x00000008;
2492
2493 /// per-IO O.APPEND
2494 pub const APPEND: kernel_rwf = 0x00000010;2619 pub const APPEND: kernel_rwf = 0x00000010;
2495};2620};
24962621
...@@ -3257,7 +3382,7 @@ pub const T = struct {...@@ -3257,7 +3382,7 @@ pub const T = struct {
3257};3382};
32583383
3259pub const EPOLL = struct {3384pub const EPOLL = struct {
3260 pub const CLOEXEC = O.CLOEXEC;3385 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
32613386
3262 pub const CTL_ADD = 1;3387 pub const CTL_ADD = 1;
3263 pub const CTL_DEL = 2;3388 pub const CTL_DEL = 2;
...@@ -3338,8 +3463,8 @@ pub const CLONE = struct {...@@ -3338,8 +3463,8 @@ pub const CLONE = struct {
33383463
3339pub const EFD = struct {3464pub const EFD = struct {
3340 pub const SEMAPHORE = 1;3465 pub const SEMAPHORE = 1;
3341 pub const CLOEXEC = O.CLOEXEC;3466 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3342 pub const NONBLOCK = O.NONBLOCK;3467 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
3343};3468};
33443469
3345pub const MS = struct {3470pub const MS = struct {
...@@ -3388,8 +3513,8 @@ pub const MNT = struct {...@@ -3388,8 +3513,8 @@ pub const MNT = struct {
3388pub const UMOUNT_NOFOLLOW = 8;3513pub const UMOUNT_NOFOLLOW = 8;
33893514
3390pub const IN = struct {3515pub const IN = struct {
3391 pub const CLOEXEC = O.CLOEXEC;3516 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3392 pub const NONBLOCK = O.NONBLOCK;3517 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
33933518
3394 pub const ACCESS = 0x00000001;3519 pub const ACCESS = 0x00000001;
3395 pub const MODIFY = 0x00000002;3520 pub const MODIFY = 0x00000002;
...@@ -3534,12 +3659,40 @@ pub const UTIME = struct {...@@ -3534,12 +3659,40 @@ pub const UTIME = struct {
3534 pub const OMIT = 0x3ffffffe;3659 pub const OMIT = 0x3ffffffe;
3535};3660};
35363661
3537pub const TFD = struct {3662const TFD_TIMER = packed struct(u32) {
3538 pub const NONBLOCK = O.NONBLOCK;3663 ABSTIME: bool = false,
3539 pub const CLOEXEC = O.CLOEXEC;3664 CANCEL_ON_SET: bool = false,
3665 _: u30 = 0,
3666};
3667
3668pub const TFD = switch (native_arch) {
3669 .sparc64 => packed struct(u32) {
3670 _0: u14 = 0,
3671 NONBLOCK: bool = false,
3672 _15: u7 = 0,
3673 CLOEXEC: bool = false,
3674 _: u9 = 0,
3675
3676 pub const TIMER = TFD_TIMER;
3677 },
3678 .mips, .mipsel, .mips64, .mips64el => packed struct(u32) {
3679 _0: u7 = 0,
3680 NONBLOCK: bool = false,
3681 _8: u11 = 0,
3682 CLOEXEC: bool = false,
3683 _: u12 = 0,
3684
3685 pub const TIMER = TFD_TIMER;
3686 },
3687 else => packed struct(u32) {
3688 _0: u11 = 0,
3689 NONBLOCK: bool = false,
3690 _12: u7 = 0,
3691 CLOEXEC: bool = false,
3692 _: u12 = 0,
35403693
3541 pub const TIMER_ABSTIME = 1;3694 pub const TIMER = TFD_TIMER;
3542 pub const TIMER_CANCEL_ON_SET = (1 << 1);3695 },
3543};3696};
35443697
3545pub const winsize = extern struct {3698pub const winsize = extern struct {
...@@ -3603,8 +3756,8 @@ pub const empty_sigset = [_]u32{0} ** sigset_len;...@@ -3603,8 +3756,8 @@ pub const empty_sigset = [_]u32{0} ** sigset_len;
3603pub const filled_sigset = [_]u32{(1 << (31 & (usize_bits - 1))) - 1} ++ [_]u32{0} ** (sigset_len - 1);3756pub const filled_sigset = [_]u32{(1 << (31 & (usize_bits - 1))) - 1} ++ [_]u32{0} ** (sigset_len - 1);
36043757
3605pub const SFD = struct {3758pub const SFD = struct {
3606 pub const CLOEXEC = O.CLOEXEC;3759 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3607 pub const NONBLOCK = O.NONBLOCK;3760 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
3608};3761};
36093762
3610pub const signalfd_siginfo = extern struct {3763pub const signalfd_siginfo = extern struct {
...@@ -3865,15 +4018,11 @@ pub const inotify_event = extern struct {...@@ -3865,15 +4018,11 @@ pub const inotify_event = extern struct {
3865};4018};
38664019
3867pub const dirent64 = extern struct {4020pub const dirent64 = extern struct {
3868 d_ino: u64,4021 ino: u64,
3869 d_off: u64,4022 off: u64,
3870 d_reclen: u16,4023 reclen: u16,
3871 d_type: u8,4024 type: u8,
3872 d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/1734025 name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
3873
3874 pub fn reclen(self: dirent64) u16 {
3875 return self.d_reclen;
3876 }
3877};4026};
38784027
3879pub const dl_phdr_info = extern struct {4028pub const dl_phdr_info = extern struct {
lib/std/os/linux/arm-eabi.zig-23
...@@ -141,29 +141,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -141,29 +141,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
141141
142pub const MMAP2_UNIT = 4096;142pub const MMAP2_UNIT = 4096;
143143
144pub const O = struct {
145 pub const CREAT = 0o100;
146 pub const EXCL = 0o200;
147 pub const NOCTTY = 0o400;
148 pub const TRUNC = 0o1000;
149 pub const APPEND = 0o2000;
150 pub const NONBLOCK = 0o4000;
151 pub const DSYNC = 0o10000;
152 pub const SYNC = 0o4010000;
153 pub const RSYNC = 0o4010000;
154 pub const DIRECTORY = 0o40000;
155 pub const NOFOLLOW = 0o100000;
156 pub const CLOEXEC = 0o2000000;
157
158 pub const ASYNC = 0o20000;
159 pub const DIRECT = 0o200000;
160 pub const LARGEFILE = 0o400000;
161 pub const NOATIME = 0o1000000;
162 pub const PATH = 0o10000000;
163 pub const TMPFILE = 0o20040000;
164 pub const NDELAY = NONBLOCK;
165};
166
167pub const F = struct {144pub const F = struct {
168 pub const DUPFD = 0;145 pub const DUPFD = 0;
169 pub const GETFD = 1;146 pub const GETFD = 1;
lib/std/os/linux/arm64.zig-23
...@@ -123,29 +123,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -123,29 +123,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
123 }123 }
124}124}
125125
126pub const O = struct {
127 pub const CREAT = 0o100;
128 pub const EXCL = 0o200;
129 pub const NOCTTY = 0o400;
130 pub const TRUNC = 0o1000;
131 pub const APPEND = 0o2000;
132 pub const NONBLOCK = 0o4000;
133 pub const DSYNC = 0o10000;
134 pub const SYNC = 0o4010000;
135 pub const RSYNC = 0o4010000;
136 pub const DIRECTORY = 0o40000;
137 pub const NOFOLLOW = 0o100000;
138 pub const CLOEXEC = 0o2000000;
139
140 pub const ASYNC = 0o20000;
141 pub const DIRECT = 0o200000;
142 pub const LARGEFILE = 0o400000;
143 pub const NOATIME = 0o1000000;
144 pub const PATH = 0o10000000;
145 pub const TMPFILE = 0o20040000;
146 pub const NDELAY = NONBLOCK;
147};
148
149pub const F = struct {126pub const F = struct {
150 pub const DUPFD = 0;127 pub const DUPFD = 0;
151 pub const GETFD = 1;128 pub const GETFD = 1;
lib/std/os/linux/io_uring.zig+13-13
...@@ -760,7 +760,7 @@ pub const IO_Uring = struct {...@@ -760,7 +760,7 @@ pub const IO_Uring = struct {
760 user_data: u64,760 user_data: u64,
761 fd: os.fd_t,761 fd: os.fd_t,
762 path: [*:0]const u8,762 path: [*:0]const u8,
763 flags: u32,763 flags: linux.O,
764 mode: os.mode_t,764 mode: os.mode_t,
765 ) !*linux.io_uring_sqe {765 ) !*linux.io_uring_sqe {
766 const sqe = try self.get_sqe();766 const sqe = try self.get_sqe();
...@@ -785,7 +785,7 @@ pub const IO_Uring = struct {...@@ -785,7 +785,7 @@ pub const IO_Uring = struct {
785 user_data: u64,785 user_data: u64,
786 fd: os.fd_t,786 fd: os.fd_t,
787 path: [*:0]const u8,787 path: [*:0]const u8,
788 flags: u32,788 flags: linux.O,
789 mode: os.mode_t,789 mode: os.mode_t,
790 file_index: u32,790 file_index: u32,
791 ) !*linux.io_uring_sqe {791 ) !*linux.io_uring_sqe {
...@@ -1658,18 +1658,18 @@ pub fn io_uring_prep_openat(...@@ -1658,18 +1658,18 @@ pub fn io_uring_prep_openat(
1658 sqe: *linux.io_uring_sqe,1658 sqe: *linux.io_uring_sqe,
1659 fd: os.fd_t,1659 fd: os.fd_t,
1660 path: [*:0]const u8,1660 path: [*:0]const u8,
1661 flags: u32,1661 flags: linux.O,
1662 mode: os.mode_t,1662 mode: os.mode_t,
1663) void {1663) void {
1664 io_uring_prep_rw(.OPENAT, sqe, fd, @intFromPtr(path), mode, 0);1664 io_uring_prep_rw(.OPENAT, sqe, fd, @intFromPtr(path), mode, 0);
1665 sqe.rw_flags = flags;1665 sqe.rw_flags = @bitCast(flags);
1666}1666}
16671667
1668pub fn io_uring_prep_openat_direct(1668pub fn io_uring_prep_openat_direct(
1669 sqe: *linux.io_uring_sqe,1669 sqe: *linux.io_uring_sqe,
1670 fd: os.fd_t,1670 fd: os.fd_t,
1671 path: [*:0]const u8,1671 path: [*:0]const u8,
1672 flags: u32,1672 flags: linux.O,
1673 mode: os.mode_t,1673 mode: os.mode_t,
1674 file_index: u32,1674 file_index: u32,
1675) void {1675) void {
...@@ -2054,7 +2054,7 @@ test "readv" {...@@ -2054,7 +2054,7 @@ test "readv" {
2054 };2054 };
2055 defer ring.deinit();2055 defer ring.deinit();
20562056
2057 const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);2057 const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
2058 defer os.close(fd);2058 defer os.close(fd);
20592059
2060 // Linux Kernel 5.4 supports IORING_REGISTER_FILES but not sparse fd sets (i.e. an fd of -1).2060 // Linux Kernel 5.4 supports IORING_REGISTER_FILES but not sparse fd sets (i.e. an fd of -1).
...@@ -2361,7 +2361,7 @@ test "openat" {...@@ -2361,7 +2361,7 @@ test "openat" {
2361 break :p @intFromPtr(workaround);2361 break :p @intFromPtr(workaround);
2362 } else @intFromPtr(path);2362 } else @intFromPtr(path);
23632363
2364 const flags: u32 = os.O.CLOEXEC | os.O.RDWR | os.O.CREAT;2364 const flags: linux.O = .{ .CLOEXEC = true, .ACCMODE = .RDWR, .CREAT = true };
2365 const mode: os.mode_t = 0o666;2365 const mode: os.mode_t = 0o666;
2366 const sqe_openat = try ring.openat(0x33333333, tmp.dir.fd, path, flags, mode);2366 const sqe_openat = try ring.openat(0x33333333, tmp.dir.fd, path, flags, mode);
2367 try testing.expectEqual(linux.io_uring_sqe{2367 try testing.expectEqual(linux.io_uring_sqe{
...@@ -2372,7 +2372,7 @@ test "openat" {...@@ -2372,7 +2372,7 @@ test "openat" {
2372 .off = 0,2372 .off = 0,
2373 .addr = path_addr,2373 .addr = path_addr,
2374 .len = mode,2374 .len = mode,
2375 .rw_flags = flags,2375 .rw_flags = @bitCast(flags),
2376 .user_data = 0x33333333,2376 .user_data = 0x33333333,
2377 .buf_index = 0,2377 .buf_index = 0,
2378 .personality = 0,2378 .personality = 0,
...@@ -2888,7 +2888,7 @@ test "register_files_update" {...@@ -2888,7 +2888,7 @@ test "register_files_update" {
2888 };2888 };
2889 defer ring.deinit();2889 defer ring.deinit();
28902890
2891 const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);2891 const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
2892 defer os.close(fd);2892 defer os.close(fd);
28932893
2894 var registered_fds = [_]os.fd_t{0} ** 2;2894 var registered_fds = [_]os.fd_t{0} ** 2;
...@@ -2906,7 +2906,7 @@ test "register_files_update" {...@@ -2906,7 +2906,7 @@ test "register_files_update" {
2906 // Test IORING_REGISTER_FILES_UPDATE2906 // Test IORING_REGISTER_FILES_UPDATE
2907 // Only available since Linux 5.52907 // Only available since Linux 5.5
29082908
2909 const fd2 = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);2909 const fd2 = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
2910 defer os.close(fd2);2910 defer os.close(fd2);
29112911
2912 registered_fds[fd_index] = fd2;2912 registered_fds[fd_index] = fd2;
...@@ -3311,7 +3311,7 @@ test "provide_buffers: read" {...@@ -3311,7 +3311,7 @@ test "provide_buffers: read" {
3311 };3311 };
3312 defer ring.deinit();3312 defer ring.deinit();
33133313
3314 const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);3314 const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
3315 defer os.close(fd);3315 defer os.close(fd);
33163316
3317 const group_id = 1337;3317 const group_id = 1337;
...@@ -3443,7 +3443,7 @@ test "remove_buffers" {...@@ -3443,7 +3443,7 @@ test "remove_buffers" {
3443 };3443 };
3444 defer ring.deinit();3444 defer ring.deinit();
34453445
3446 const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);3446 const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
3447 defer os.close(fd);3447 defer os.close(fd);
34483448
3449 const group_id = 1337;3449 const group_id = 1337;
...@@ -4113,7 +4113,7 @@ test "openat_direct/close_direct" {...@@ -4113,7 +4113,7 @@ test "openat_direct/close_direct" {
4113 var tmp = std.testing.tmpDir(.{});4113 var tmp = std.testing.tmpDir(.{});
4114 defer tmp.cleanup();4114 defer tmp.cleanup();
4115 const path = "test_io_uring_close_direct";4115 const path = "test_io_uring_close_direct";
4116 const flags: u32 = os.O.RDWR | os.O.CREAT;4116 const flags: linux.O = .{ .ACCMODE = .RDWR, .CREAT = true };
4117 const mode: os.mode_t = 0o666;4117 const mode: os.mode_t = 0o666;
4118 const user_data: u64 = 0;4118 const user_data: u64 = 0;
41194119
lib/std/os/linux/mips.zig-23
...@@ -213,29 +213,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -213,29 +213,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
213 );213 );
214}214}
215215
216pub const O = struct {
217 pub const CREAT = 0o0400;
218 pub const EXCL = 0o02000;
219 pub const NOCTTY = 0o04000;
220 pub const TRUNC = 0o01000;
221 pub const APPEND = 0o0010;
222 pub const NONBLOCK = 0o0200;
223 pub const DSYNC = 0o0020;
224 pub const SYNC = 0o040020;
225 pub const RSYNC = 0o040020;
226 pub const DIRECTORY = 0o0200000;
227 pub const NOFOLLOW = 0o0400000;
228 pub const CLOEXEC = 0o02000000;
229
230 pub const ASYNC = 0o010000;
231 pub const DIRECT = 0o0100000;
232 pub const LARGEFILE = 0o020000;
233 pub const NOATIME = 0o01000000;
234 pub const PATH = 0o010000000;
235 pub const TMPFILE = 0o020200000;
236 pub const NDELAY = NONBLOCK;
237};
238
239pub const F = struct {216pub const F = struct {
240 pub const DUPFD = 0;217 pub const DUPFD = 0;
241 pub const GETFD = 1;218 pub const GETFD = 1;
lib/std/os/linux/mips64.zig-23
...@@ -198,29 +198,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -198,29 +198,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
198 );198 );
199}199}
200200
201pub const O = struct {
202 pub const CREAT = 0o0400;
203 pub const EXCL = 0o02000;
204 pub const NOCTTY = 0o04000;
205 pub const TRUNC = 0o01000;
206 pub const APPEND = 0o0010;
207 pub const NONBLOCK = 0o0200;
208 pub const DSYNC = 0o0020;
209 pub const SYNC = 0o040020;
210 pub const RSYNC = 0o040020;
211 pub const DIRECTORY = 0o0200000;
212 pub const NOFOLLOW = 0o0400000;
213 pub const CLOEXEC = 0o02000000;
214
215 pub const ASYNC = 0o010000;
216 pub const DIRECT = 0o0100000;
217 pub const LARGEFILE = 0o020000;
218 pub const NOATIME = 0o01000000;
219 pub const PATH = 0o010000000;
220 pub const TMPFILE = 0o020200000;
221 pub const NDELAY = NONBLOCK;
222};
223
224pub const F = struct {201pub const F = struct {
225 pub const DUPFD = 0;202 pub const DUPFD = 0;
226 pub const GETFD = 1;203 pub const GETFD = 1;
lib/std/os/linux/powerpc.zig-23
...@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
142 );142 );
143}143}
144144
145pub const O = struct {
146 pub const CREAT = 0o100;
147 pub const EXCL = 0o200;
148 pub const NOCTTY = 0o400;
149 pub const TRUNC = 0o1000;
150 pub const APPEND = 0o2000;
151 pub const NONBLOCK = 0o4000;
152 pub const DSYNC = 0o10000;
153 pub const SYNC = 0o4010000;
154 pub const RSYNC = 0o4010000;
155 pub const DIRECTORY = 0o40000;
156 pub const NOFOLLOW = 0o100000;
157 pub const CLOEXEC = 0o2000000;
158
159 pub const ASYNC = 0o20000;
160 pub const DIRECT = 0o400000;
161 pub const LARGEFILE = 0o200000;
162 pub const NOATIME = 0o1000000;
163 pub const PATH = 0o10000000;
164 pub const TMPFILE = 0o20040000;
165 pub const NDELAY = NONBLOCK;
166};
167
168pub const F = struct {145pub const F = struct {
169 pub const DUPFD = 0;146 pub const DUPFD = 0;
170 pub const GETFD = 1;147 pub const GETFD = 1;
lib/std/os/linux/powerpc64.zig-23
...@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
142 );142 );
143}143}
144144
145pub const O = struct {
146 pub const CREAT = 0o100;
147 pub const EXCL = 0o200;
148 pub const NOCTTY = 0o400;
149 pub const TRUNC = 0o1000;
150 pub const APPEND = 0o2000;
151 pub const NONBLOCK = 0o4000;
152 pub const DSYNC = 0o10000;
153 pub const SYNC = 0o4010000;
154 pub const RSYNC = 0o4010000;
155 pub const DIRECTORY = 0o40000;
156 pub const NOFOLLOW = 0o100000;
157 pub const CLOEXEC = 0o2000000;
158
159 pub const ASYNC = 0o20000;
160 pub const DIRECT = 0o400000;
161 pub const LARGEFILE = 0o200000;
162 pub const NOATIME = 0o1000000;
163 pub const PATH = 0o10000000;
164 pub const TMPFILE = 0o20200000;
165 pub const NDELAY = NONBLOCK;
166};
167
168pub const F = struct {145pub const F = struct {
169 pub const DUPFD = 0;146 pub const DUPFD = 0;
170 pub const GETFD = 1;147 pub const GETFD = 1;
lib/std/os/linux/riscv64.zig-23
...@@ -110,29 +110,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -110,29 +110,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
110 );110 );
111}111}
112112
113pub const O = struct {
114 pub const CREAT = 0o100;
115 pub const EXCL = 0o200;
116 pub const NOCTTY = 0o400;
117 pub const TRUNC = 0o1000;
118 pub const APPEND = 0o2000;
119 pub const NONBLOCK = 0o4000;
120 pub const DSYNC = 0o10000;
121 pub const SYNC = 0o4010000;
122 pub const RSYNC = 0o4010000;
123 pub const DIRECTORY = 0o200000;
124 pub const NOFOLLOW = 0o400000;
125 pub const CLOEXEC = 0o2000000;
126
127 pub const ASYNC = 0o20000;
128 pub const DIRECT = 0o40000;
129 pub const LARGEFILE = 0o100000;
130 pub const NOATIME = 0o1000000;
131 pub const PATH = 0o10000000;
132 pub const TMPFILE = 0o20200000;
133 pub const NDELAY = NONBLOCK;
134};
135
136pub const F = struct {113pub const F = struct {
137 pub const DUPFD = 0;114 pub const DUPFD = 0;
138 pub const GETFD = 1;115 pub const GETFD = 1;
lib/std/os/linux/sparc64.zig-23
...@@ -195,29 +195,6 @@ pub fn restore_rt() callconv(.C) void {...@@ -195,29 +195,6 @@ pub fn restore_rt() callconv(.C) void {
195 );195 );
196}196}
197197
198pub const O = struct {
199 pub const CREAT = 0x200;
200 pub const EXCL = 0x800;
201 pub const NOCTTY = 0x8000;
202 pub const TRUNC = 0x400;
203 pub const APPEND = 0x8;
204 pub const NONBLOCK = 0x4000;
205 pub const SYNC = 0x802000;
206 pub const DSYNC = 0x2000;
207 pub const RSYNC = SYNC;
208 pub const DIRECTORY = 0x10000;
209 pub const NOFOLLOW = 0x20000;
210 pub const CLOEXEC = 0x400000;
211
212 pub const ASYNC = 0x40;
213 pub const DIRECT = 0x100000;
214 pub const LARGEFILE = 0;
215 pub const NOATIME = 0x200000;
216 pub const PATH = 0x1000000;
217 pub const TMPFILE = 0x2010000;
218 pub const NDELAY = NONBLOCK | 0x4;
219};
220
221pub const F = struct {198pub const F = struct {
222 pub const DUPFD = 0;199 pub const DUPFD = 0;
223 pub const GETFD = 1;200 pub const GETFD = 1;
lib/std/os/linux/test.zig+2-2
...@@ -37,7 +37,7 @@ test "timer" {...@@ -37,7 +37,7 @@ test "timer" {
37 var err: linux.E = linux.getErrno(epoll_fd);37 var err: linux.E = linux.getErrno(epoll_fd);
38 try expect(err == .SUCCESS);38 try expect(err == .SUCCESS);
3939
40 const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, 0);40 const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{});
41 try expect(linux.getErrno(timer_fd) == .SUCCESS);41 try expect(linux.getErrno(timer_fd) == .SUCCESS);
4242
43 const time_interval = linux.timespec{43 const time_interval = linux.timespec{
...@@ -50,7 +50,7 @@ test "timer" {...@@ -50,7 +50,7 @@ test "timer" {
50 .it_value = time_interval,50 .it_value = time_interval,
51 };51 };
5252
53 err = linux.getErrno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), 0, &new_time, null));53 err = linux.getErrno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
54 try expect(err == .SUCCESS);54 try expect(err == .SUCCESS);
5555
56 var event = linux.epoll_event{56 var event = linux.epoll_event{
lib/std/os/linux/x86.zig-23
...@@ -159,29 +159,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {...@@ -159,29 +159,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
159 }159 }
160}160}
161161
162pub const O = struct {
163 pub const CREAT = 0o100;
164 pub const EXCL = 0o200;
165 pub const NOCTTY = 0o400;
166 pub const TRUNC = 0o1000;
167 pub const APPEND = 0o2000;
168 pub const NONBLOCK = 0o4000;
169 pub const DSYNC = 0o10000;
170 pub const SYNC = 0o4010000;
171 pub const RSYNC = 0o4010000;
172 pub const DIRECTORY = 0o200000;
173 pub const NOFOLLOW = 0o400000;
174 pub const CLOEXEC = 0o2000000;
175
176 pub const ASYNC = 0o20000;
177 pub const DIRECT = 0o40000;
178 pub const LARGEFILE = 0o100000;
179 pub const NOATIME = 0o1000000;
180 pub const PATH = 0o10000000;
181 pub const TMPFILE = 0o20200000;
182 pub const NDELAY = NONBLOCK;
183};
184
185pub const F = struct {162pub const F = struct {
186 pub const DUPFD = 0;163 pub const DUPFD = 0;
187 pub const GETFD = 1;164 pub const GETFD = 1;
lib/std/os/linux/x86_64.zig-23
...@@ -131,29 +131,6 @@ pub const nlink_t = usize;...@@ -131,29 +131,6 @@ pub const nlink_t = usize;
131pub const blksize_t = isize;131pub const blksize_t = isize;
132pub const blkcnt_t = isize;132pub const blkcnt_t = isize;
133133
134pub const O = struct {
135 pub const CREAT = 0o100;
136 pub const EXCL = 0o200;
137 pub const NOCTTY = 0o400;
138 pub const TRUNC = 0o1000;
139 pub const APPEND = 0o2000;
140 pub const NONBLOCK = 0o4000;
141 pub const DSYNC = 0o10000;
142 pub const SYNC = 0o4010000;
143 pub const RSYNC = 0o4010000;
144 pub const DIRECTORY = 0o200000;
145 pub const NOFOLLOW = 0o400000;
146 pub const CLOEXEC = 0o2000000;
147
148 pub const ASYNC = 0o20000;
149 pub const DIRECT = 0o40000;
150 pub const LARGEFILE = 0;
151 pub const NOATIME = 0o1000000;
152 pub const PATH = 0o10000000;
153 pub const TMPFILE = 0o20200000;
154 pub const NDELAY = NONBLOCK;
155};
156
157pub const F = struct {134pub const F = struct {
158 pub const DUPFD = 0;135 pub const DUPFD = 0;
159 pub const GETFD = 1;136 pub const GETFD = 1;
lib/std/os/plan9.zig+17-11
...@@ -242,17 +242,23 @@ pub fn close(fd: i32) usize {...@@ -242,17 +242,23 @@ pub fn close(fd: i32) usize {
242 return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));242 return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
243}243}
244pub const mode_t = i32;244pub const mode_t = i32;
245pub const O = struct {245
246 pub const READ = 0; // open for read246pub const AccessMode = enum(u2) {
247 pub const RDONLY = 0;247 RDONLY,
248 pub const WRITE = 1; // write248 WRONLY,
249 pub const WRONLY = 1;249 RDWR,
250 pub const RDWR = 2; // read and write250 EXEC,
251 pub const EXEC = 3; // execute, == read but check execute permission251};
252 pub const TRUNC = 16; // or'ed in (except for exec), truncate file first252
253 pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec253pub const O = packed struct(u32) {
254 pub const RCLOSE = 64; // or'ed in, remove on close254 access: AccessMode,
255 pub const EXCL = 0x1000; // or'ed in, exclusive create255 _2: u2 = 0,
256 TRUNC: bool = false,
257 CEXEC: bool = false,
258 RCLOSE: bool = false,
259 _7: u5 = 0,
260 EXCL: bool = false,
261 _: u19 = 0,
256};262};
257263
258pub const ExecData = struct {264pub const ExecData = struct {
lib/std/os/test.zig+49-27
...@@ -87,6 +87,7 @@ test "chdir smoke test" {...@@ -87,6 +87,7 @@ test "chdir smoke test" {
8787
88test "open smoke test" {88test "open smoke test" {
89 if (native_os == .wasi) return error.SkipZigTest;89 if (native_os == .wasi) return error.SkipZigTest;
90 if (native_os == .windows) return error.SkipZigTest;
9091
91 // TODO verify file attributes using `fstat`92 // TODO verify file attributes using `fstat`
9293
...@@ -109,21 +110,21 @@ test "open smoke test" {...@@ -109,21 +110,21 @@ test "open smoke test" {
109110
110 // Create some file using `open`.111 // Create some file using `open`.
111 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });112 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
112 fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);113 fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
113 os.close(fd);114 os.close(fd);
114115
115 // Try this again with the same flags. This op should fail with error.PathAlreadyExists.116 // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
116 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });117 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
117 try expectError(error.PathAlreadyExists, os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode));118 try expectError(error.PathAlreadyExists, os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
118119
119 // Try opening without `O.EXCL` flag.120 // Try opening without `EXCL` flag.
120 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });121 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
121 fd = try os.open(file_path, os.O.RDWR | os.O.CREAT, mode);122 fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
122 os.close(fd);123 os.close(fd);
123124
124 // Try opening as a directory which should fail.125 // Try opening as a directory which should fail.
125 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });126 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
126 try expectError(error.NotDir, os.open(file_path, os.O.RDWR | os.O.DIRECTORY, mode));127 try expectError(error.NotDir, os.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
127128
128 // Create some directory129 // Create some directory
129 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });130 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
...@@ -131,16 +132,17 @@ test "open smoke test" {...@@ -131,16 +132,17 @@ test "open smoke test" {
131132
132 // Open dir using `open`133 // Open dir using `open`
133 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });134 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
134 fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);135 fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
135 os.close(fd);136 os.close(fd);
136137
137 // Try opening as file which should fail.138 // Try opening as file which should fail.
138 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });139 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
139 try expectError(error.IsDir, os.open(file_path, os.O.RDWR, mode));140 try expectError(error.IsDir, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
140}141}
141142
142test "openat smoke test" {143test "openat smoke test" {
143 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;144 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
145 if (native_os == .windows) return error.SkipZigTest;
144146
145 // TODO verify file attributes using `fstatat`147 // TODO verify file attributes using `fstatat`
146148
...@@ -151,28 +153,47 @@ test "openat smoke test" {...@@ -151,28 +153,47 @@ test "openat smoke test" {
151 const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;153 const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
152154
153 // Create some file using `openat`.155 // Create some file using `openat`.
154 fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);156 fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
157 .ACCMODE = .RDWR,
158 .CREAT = true,
159 .EXCL = true,
160 }), mode);
155 os.close(fd);161 os.close(fd);
156162
157 // Try this again with the same flags. This op should fail with error.PathAlreadyExists.163 // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
158 try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT | os.O.EXCL, mode));164 try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
159165 .ACCMODE = .RDWR,
160 // Try opening without `O.EXCL` flag.166 .CREAT = true,
161 fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT, mode);167 .EXCL = true,
168 }), mode));
169
170 // Try opening without `EXCL` flag.
171 fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
172 .ACCMODE = .RDWR,
173 .CREAT = true,
174 }), mode);
162 os.close(fd);175 os.close(fd);
163176
164 // Try opening as a directory which should fail.177 // Try opening as a directory which should fail.
165 try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.DIRECTORY, mode));178 try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
179 .ACCMODE = .RDWR,
180 .DIRECTORY = true,
181 }), mode));
166182
167 // Create some directory183 // Create some directory
168 try os.mkdirat(tmp.dir.fd, "some_dir", mode);184 try os.mkdirat(tmp.dir.fd, "some_dir", mode);
169185
170 // Open dir using `open`186 // Open dir using `open`
171 fd = try os.openat(tmp.dir.fd, "some_dir", os.O.RDONLY | os.O.DIRECTORY, mode);187 fd = try os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
188 .ACCMODE = .RDONLY,
189 .DIRECTORY = true,
190 }), mode);
172 os.close(fd);191 os.close(fd);
173192
174 // Try opening as file which should fail.193 // Try opening as file which should fail.
175 try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.O.RDWR, mode));194 try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
195 .ACCMODE = .RDWR,
196 }), mode));
176}197}
177198
178test "symlink with relative paths" {199test "symlink with relative paths" {
...@@ -688,7 +709,7 @@ test "fcntl" {...@@ -688,7 +709,7 @@ test "fcntl" {
688 tmp.dir.deleteFile(test_out_file) catch {};709 tmp.dir.deleteFile(test_out_file) catch {};
689 }710 }
690711
691 // Note: The test assumes createFile opens the file with O.CLOEXEC712 // Note: The test assumes createFile opens the file with CLOEXEC
692 {713 {
693 const flags = try os.fcntl(file.handle, os.F.GETFD, 0);714 const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
694 try expect((flags & os.FD_CLOEXEC) != 0);715 try expect((flags & os.FD_CLOEXEC) != 0);
...@@ -987,6 +1008,7 @@ test "POSIX file locking with fcntl" {...@@ -987,6 +1008,7 @@ test "POSIX file locking with fcntl" {
9871008
988test "rename smoke test" {1009test "rename smoke test" {
989 if (native_os == .wasi) return error.SkipZigTest;1010 if (native_os == .wasi) return error.SkipZigTest;
1011 if (native_os == .windows) return error.SkipZigTest;
9901012
991 var tmp = tmpDir(.{});1013 var tmp = tmpDir(.{});
992 defer tmp.cleanup();1014 defer tmp.cleanup();
...@@ -1007,7 +1029,7 @@ test "rename smoke test" {...@@ -1007,7 +1029,7 @@ test "rename smoke test" {
10071029
1008 // Create some file using `open`.1030 // Create some file using `open`.
1009 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });1031 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
1010 fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);1032 fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
1011 os.close(fd);1033 os.close(fd);
10121034
1013 // Rename the file1035 // Rename the file
...@@ -1016,12 +1038,12 @@ test "rename smoke test" {...@@ -1016,12 +1038,12 @@ test "rename smoke test" {
10161038
1017 // Try opening renamed file1039 // Try opening renamed file
1018 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });1040 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
1019 fd = try os.open(file_path, os.O.RDWR, mode);1041 fd = try os.open(file_path, .{ .ACCMODE = .RDWR }, mode);
1020 os.close(fd);1042 os.close(fd);
10211043
1022 // Try opening original file - should fail with error.FileNotFound1044 // Try opening original file - should fail with error.FileNotFound
1023 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });1045 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
1024 try expectError(error.FileNotFound, os.open(file_path, os.O.RDWR, mode));1046 try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
10251047
1026 // Create some directory1048 // Create some directory
1027 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });1049 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
...@@ -1033,16 +1055,17 @@ test "rename smoke test" {...@@ -1033,16 +1055,17 @@ test "rename smoke test" {
10331055
1034 // Try opening renamed directory1056 // Try opening renamed directory
1035 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });1057 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
1036 fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);1058 fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
1037 os.close(fd);1059 os.close(fd);
10381060
1039 // Try opening original directory - should fail with error.FileNotFound1061 // Try opening original directory - should fail with error.FileNotFound
1040 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });1062 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
1041 try expectError(error.FileNotFound, os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode));1063 try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
1042}1064}
10431065
1044test "access smoke test" {1066test "access smoke test" {
1045 if (native_os == .wasi) return error.SkipZigTest;1067 if (native_os == .wasi) return error.SkipZigTest;
1068 if (native_os == .windows) return error.SkipZigTest;
10461069
1047 var tmp = tmpDir(.{});1070 var tmp = tmpDir(.{});
1048 defer tmp.cleanup();1071 defer tmp.cleanup();
...@@ -1063,7 +1086,7 @@ test "access smoke test" {...@@ -1063,7 +1086,7 @@ test "access smoke test" {
10631086
1064 // Create some file using `open`.1087 // Create some file using `open`.
1065 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });1088 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
1066 fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);1089 fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
1067 os.close(fd);1090 os.close(fd);
10681091
1069 // Try to access() the file1092 // Try to access() the file
...@@ -1088,16 +1111,15 @@ test "access smoke test" {...@@ -1088,16 +1111,15 @@ test "access smoke test" {
1088}1111}
10891112
1090test "timerfd" {1113test "timerfd" {
1091 if (native_os != .linux)1114 if (native_os != .linux) return error.SkipZigTest;
1092 return error.SkipZigTest;
10931115
1094 const linux = os.linux;1116 const linux = os.linux;
1095 const tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, linux.TFD.CLOEXEC);1117 const tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, .{ .CLOEXEC = true });
1096 defer os.close(tfd);1118 defer os.close(tfd);
10971119
1098 // Fire event 10_000_000ns = 10ms after the os.timerfd_settime call.1120 // Fire event 10_000_000ns = 10ms after the os.timerfd_settime call.
1099 var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };1121 var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };
1100 try os.timerfd_settime(tfd, 0, &sit, null);1122 try os.timerfd_settime(tfd, .{}, &sit, null);
11011123
1102 var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};1124 var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
1103 try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting1125 try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting
...@@ -1232,7 +1254,7 @@ test "fchmodat smoke test" {...@@ -1232,7 +1254,7 @@ test "fchmodat smoke test" {
1232 const fd = try os.openat(1254 const fd = try os.openat(
1233 tmp.dir.fd,1255 tmp.dir.fd,
1234 "regfile",1256 "regfile",
1235 os.O.WRONLY | os.O.CREAT | os.O.EXCL | os.O.TRUNC,1257 .{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
1236 0o644,1258 0o644,
1237 );1259 );
1238 os.close(fd);1260 os.close(fd);
lib/std/os/wasi.zig+121-268
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1// wasi_snapshot_preview1 spec available (in witx format) here:1//! wasi_snapshot_preview1 spec available (in witx format) here:
2// * typenames -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/typenames.witx2//! * typenames -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/typenames.witx
3// * module -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/wasi_snapshot_preview1.witx3//! * module -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/wasi_snapshot_preview1.witx
4//! Note that libc API does *not* go in this file. wasi libc API goes into std/c/wasi.zig instead.
4const builtin = @import("builtin");5const builtin = @import("builtin");
5const std = @import("std");6const std = @import("std");
6const assert = std.debug.assert;7const assert = std.debug.assert;
...@@ -16,11 +17,6 @@ comptime {...@@ -16,11 +17,6 @@ comptime {
16 // assert(@alignOf(u64) == 8);17 // assert(@alignOf(u64) == 8);
17}18}
1819
19pub const F_OK = 0;
20pub const X_OK = 1;
21pub const W_OK = 2;
22pub const R_OK = 4;
23
24pub const iovec_t = std.os.iovec;20pub const iovec_t = std.os.iovec;
25pub const ciovec_t = std.os.iovec_const;21pub const ciovec_t = std.os.iovec_const;
2622
...@@ -82,106 +78,22 @@ pub extern "wasi_snapshot_preview1" fn sock_recv(sock: fd_t, ri_data: [*]iovec_t...@@ -82,106 +78,22 @@ pub extern "wasi_snapshot_preview1" fn sock_recv(sock: fd_t, ri_data: [*]iovec_t
82pub extern "wasi_snapshot_preview1" fn sock_send(sock: fd_t, si_data: [*]const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;78pub extern "wasi_snapshot_preview1" fn sock_send(sock: fd_t, si_data: [*]const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
83pub extern "wasi_snapshot_preview1" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;79pub extern "wasi_snapshot_preview1" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
8480
85/// Get the errno from a syscall return value, or 0 for no error.
86pub fn getErrno(r: errno_t) errno_t {
87 return r;
88}
89
90pub const STDIN_FILENO = 0;
91pub const STDOUT_FILENO = 1;
92pub const STDERR_FILENO = 2;
93
94pub const mode_t = u32;
95
96pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc
97
98pub const timespec = extern struct {
99 tv_sec: time_t,
100 tv_nsec: isize,
101
102 pub fn fromTimestamp(tm: timestamp_t) timespec {
103 const tv_sec: timestamp_t = tm / 1_000_000_000;
104 const tv_nsec = tm - tv_sec * 1_000_000_000;
105 return timespec{
106 .tv_sec = @as(time_t, @intCast(tv_sec)),
107 .tv_nsec = @as(isize, @intCast(tv_nsec)),
108 };
109 }
110
111 pub fn toTimestamp(ts: timespec) timestamp_t {
112 const tm = @as(timestamp_t, @intCast(ts.tv_sec * 1_000_000_000)) + @as(timestamp_t, @intCast(ts.tv_nsec));
113 return tm;
114 }
115};
116
117pub const Stat = struct {
118 dev: device_t,
119 ino: inode_t,
120 mode: mode_t,
121 filetype: filetype_t,
122 nlink: linkcount_t,
123 size: filesize_t,
124 atim: timespec,
125 mtim: timespec,
126 ctim: timespec,
127
128 const Self = @This();
129
130 pub fn fromFilestat(stat: filestat_t) Self {
131 return Self{
132 .dev = stat.dev,
133 .ino = stat.ino,
134 .mode = 0,
135 .filetype = stat.filetype,
136 .nlink = stat.nlink,
137 .size = stat.size,
138 .atim = stat.atime(),
139 .mtim = stat.mtime(),
140 .ctim = stat.ctime(),
141 };
142 }
143
144 pub fn atime(self: Self) timespec {
145 return self.atim;
146 }
147
148 pub fn mtime(self: Self) timespec {
149 return self.mtim;
150 }
151
152 pub fn ctime(self: Self) timespec {
153 return self.ctim;
154 }
155};
156
157pub const IOV_MAX = 1024;
158
159pub const AT = struct {
160 pub const REMOVEDIR: u32 = 0x4;
161 /// When linking libc, we follow their convention and use -2 for current working directory.
162 /// However, without libc, Zig does a different convention: it assumes the
163 /// current working directory is the first preopen. This behavior can be
164 /// overridden with a public function called `wasi_cwd` in the root source
165 /// file.
166 pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3;
167};
168
169// As defined in the wasi_snapshot_preview1 spec file:81// As defined in the wasi_snapshot_preview1 spec file:
170// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx82// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
171pub const advice_t = u8;83pub const advice_t = enum(u8) {
172pub const ADVICE_NORMAL: advice_t = 0;84 NORMAL = 0,
173pub const ADVICE_SEQUENTIAL: advice_t = 1;85 SEQUENTIAL = 1,
174pub const ADVICE_RANDOM: advice_t = 2;86 RANDOM = 2,
175pub const ADVICE_WILLNEED: advice_t = 3;87 WILLNEED = 3,
176pub const ADVICE_DONTNEED: advice_t = 4;88 DONTNEED = 4,
177pub const ADVICE_NOREUSE: advice_t = 5;89 NOREUSE = 5,
17890};
179pub const clockid_t = u32;91
180pub const CLOCK = struct {92pub const clockid_t = enum(u32) {
181 pub const REALTIME: clockid_t = 0;93 REALTIME = 0,
182 pub const MONOTONIC: clockid_t = 1;94 MONOTONIC = 1,
183 pub const PROCESS_CPUTIME_ID: clockid_t = 2;95 PROCESS_CPUTIME_ID = 2,
184 pub const THREAD_CPUTIME_ID: clockid_t = 3;96 THREAD_CPUTIME_ID = 3,
185};97};
18698
187pub const device_t = u64;99pub const device_t = u64;
...@@ -192,10 +104,10 @@ pub const DIRCOOKIE_START: dircookie_t = 0;...@@ -192,10 +104,10 @@ pub const DIRCOOKIE_START: dircookie_t = 0;
192pub const dirnamlen_t = u32;104pub const dirnamlen_t = u32;
193105
194pub const dirent_t = extern struct {106pub const dirent_t = extern struct {
195 d_next: dircookie_t,107 next: dircookie_t,
196 d_ino: inode_t,108 ino: inode_t,
197 d_namlen: dirnamlen_t,109 namlen: dirnamlen_t,
198 d_type: filetype_t,110 type: filetype_t,
199};111};
200112
201pub const errno_t = enum(u16) {113pub const errno_t = enum(u16) {
...@@ -280,7 +192,6 @@ pub const errno_t = enum(u16) {...@@ -280,7 +192,6 @@ pub const errno_t = enum(u16) {
280 NOTCAPABLE = 76,192 NOTCAPABLE = 76,
281 _,193 _,
282};194};
283pub const E = errno_t;
284195
285pub const event_t = extern struct {196pub const event_t = extern struct {
286 userdata: userdata_t,197 userdata: userdata_t,
...@@ -297,22 +208,23 @@ pub const eventfdreadwrite_t = extern struct {...@@ -297,22 +208,23 @@ pub const eventfdreadwrite_t = extern struct {
297pub const eventrwflags_t = u16;208pub const eventrwflags_t = u16;
298pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;209pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
299210
300pub const eventtype_t = u8;211pub const eventtype_t = enum(u8) {
301pub const EVENTTYPE_CLOCK: eventtype_t = 0;212 CLOCK = 0,
302pub const EVENTTYPE_FD_READ: eventtype_t = 1;213 FD_READ = 1,
303pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;214 FD_WRITE = 2,
215};
304216
305pub const exitcode_t = u32;217pub const exitcode_t = u32;
306218
307pub const fd_t = i32;219pub const fd_t = i32;
308220
309pub const fdflags_t = u16;221pub const fdflags_t = packed struct(u16) {
310pub const FDFLAG = struct {222 APPEND: bool = false,
311 pub const APPEND: fdflags_t = 0x0001;223 DSYNC: bool = false,
312 pub const DSYNC: fdflags_t = 0x0002;224 NONBLOCK: bool = false,
313 pub const NONBLOCK: fdflags_t = 0x0004;225 RSYNC: bool = false,
314 pub const RSYNC: fdflags_t = 0x0008;226 SYNC: bool = false,
315 pub const SYNC: fdflags_t = 0x0010;227 _: u11 = 0,
316};228};
317229
318pub const fdstat_t = extern struct {230pub const fdstat_t = extern struct {
...@@ -335,21 +247,8 @@ pub const filestat_t = extern struct {...@@ -335,21 +247,8 @@ pub const filestat_t = extern struct {
335 atim: timestamp_t,247 atim: timestamp_t,
336 mtim: timestamp_t,248 mtim: timestamp_t,
337 ctim: timestamp_t,249 ctim: timestamp_t,
338
339 pub fn atime(self: filestat_t) timespec {
340 return timespec.fromTimestamp(self.atim);
341 }
342
343 pub fn mtime(self: filestat_t) timespec {
344 return timespec.fromTimestamp(self.mtim);
345 }
346
347 pub fn ctime(self: filestat_t) timespec {
348 return timespec.fromTimestamp(self.ctim);
349 }
350};250};
351251
352/// Also known as `FILETYPE`.
353pub const filetype_t = enum(u8) {252pub const filetype_t = enum(u8) {
354 UNKNOWN,253 UNKNOWN,
355 BLOCK_DEVICE,254 BLOCK_DEVICE,
...@@ -362,26 +261,29 @@ pub const filetype_t = enum(u8) {...@@ -362,26 +261,29 @@ pub const filetype_t = enum(u8) {
362 _,261 _,
363};262};
364263
365pub const fstflags_t = u16;264pub const fstflags_t = packed struct(u16) {
366pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;265 ATIM: bool = false,
367pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;266 ATIM_NOW: bool = false,
368pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;267 MTIM: bool = false,
369pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;268 MTIM_NOW: bool = false,
269 _: u12 = 0,
270};
370271
371pub const inode_t = u64;272pub const inode_t = u64;
372pub const ino_t = inode_t;
373273
374pub const linkcount_t = u64;274pub const linkcount_t = u64;
375275
376pub const lookupflags_t = u32;276pub const lookupflags_t = packed struct(u32) {
377pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;277 SYMLINK_FOLLOW: bool = false,
278 _: u31 = 0,
279};
378280
379pub const oflags_t = u16;281pub const oflags_t = packed struct(u16) {
380pub const O = struct {282 CREAT: bool = false,
381 pub const CREAT: oflags_t = 0x0001;283 DIRECTORY: bool = false,
382 pub const DIRECTORY: oflags_t = 0x0002;284 EXCL: bool = false,
383 pub const EXCL: oflags_t = 0x0004;285 TRUNC: bool = false,
384 pub const TRUNC: oflags_t = 0x0008;286 _: u12 = 0,
385};287};
386288
387pub const preopentype_t = u8;289pub const preopentype_t = u8;
...@@ -410,110 +312,81 @@ pub const SOCK = struct {...@@ -410,110 +312,81 @@ pub const SOCK = struct {
410 pub const RECV_DATA_TRUNCATED: roflags_t = 0x0001;312 pub const RECV_DATA_TRUNCATED: roflags_t = 0x0001;
411};313};
412314
413pub const rights_t = u64;315pub const rights_t = packed struct(u64) {
414pub const RIGHT = struct {316 FD_DATASYNC: bool = false,
415 pub const FD_DATASYNC: rights_t = 0x0000000000000001;317 FD_READ: bool = false,
416 pub const FD_READ: rights_t = 0x0000000000000002;318 FD_SEEK: bool = false,
417 pub const FD_SEEK: rights_t = 0x0000000000000004;319 FD_FDSTAT_SET_FLAGS: bool = false,
418 pub const FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;320 FD_SYNC: bool = false,
419 pub const FD_SYNC: rights_t = 0x0000000000000010;321 FD_TELL: bool = false,
420 pub const FD_TELL: rights_t = 0x0000000000000020;322 FD_WRITE: bool = false,
421 pub const FD_WRITE: rights_t = 0x0000000000000040;323 FD_ADVISE: bool = false,
422 pub const FD_ADVISE: rights_t = 0x0000000000000080;324 FD_ALLOCATE: bool = false,
423 pub const FD_ALLOCATE: rights_t = 0x0000000000000100;325 PATH_CREATE_DIRECTORY: bool = false,
424 pub const PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;326 PATH_CREATE_FILE: bool = false,
425 pub const PATH_CREATE_FILE: rights_t = 0x0000000000000400;327 PATH_LINK_SOURCE: bool = false,
426 pub const PATH_LINK_SOURCE: rights_t = 0x0000000000000800;328 PATH_LINK_TARGET: bool = false,
427 pub const PATH_LINK_TARGET: rights_t = 0x0000000000001000;329 PATH_OPEN: bool = false,
428 pub const PATH_OPEN: rights_t = 0x0000000000002000;330 FD_READDIR: bool = false,
429 pub const FD_READDIR: rights_t = 0x0000000000004000;331 PATH_READLINK: bool = false,
430 pub const PATH_READLINK: rights_t = 0x0000000000008000;332 PATH_RENAME_SOURCE: bool = false,
431 pub const PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;333 PATH_RENAME_TARGET: bool = false,
432 pub const PATH_RENAME_TARGET: rights_t = 0x0000000000020000;334 PATH_FILESTAT_GET: bool = false,
433 pub const PATH_FILESTAT_GET: rights_t = 0x0000000000040000;335 PATH_FILESTAT_SET_SIZE: bool = false,
434 pub const PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;336 PATH_FILESTAT_SET_TIMES: bool = false,
435 pub const PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;337 FD_FILESTAT_GET: bool = false,
436 pub const FD_FILESTAT_GET: rights_t = 0x0000000000200000;338 FD_FILESTAT_SET_SIZE: bool = false,
437 pub const FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;339 FD_FILESTAT_SET_TIMES: bool = false,
438 pub const FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;340 PATH_SYMLINK: bool = false,
439 pub const PATH_SYMLINK: rights_t = 0x0000000001000000;341 PATH_REMOVE_DIRECTORY: bool = false,
440 pub const PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;342 PATH_UNLINK_FILE: bool = false,
441 pub const PATH_UNLINK_FILE: rights_t = 0x0000000004000000;343 POLL_FD_READWRITE: bool = false,
442 pub const POLL_FD_READWRITE: rights_t = 0x0000000008000000;344 SOCK_SHUTDOWN: bool = false,
443 pub const SOCK_SHUTDOWN: rights_t = 0x0000000010000000;345 SOCK_ACCEPT: bool = false,
444 pub const SOCK_ACCEPT: rights_t = 0x0000000020000000;346 _: u34 = 0,
445 pub const ALL: rights_t = FD_DATASYNC |
446 FD_READ |
447 FD_SEEK |
448 FD_FDSTAT_SET_FLAGS |
449 FD_SYNC |
450 FD_TELL |
451 FD_WRITE |
452 FD_ADVISE |
453 FD_ALLOCATE |
454 PATH_CREATE_DIRECTORY |
455 PATH_CREATE_FILE |
456 PATH_LINK_SOURCE |
457 PATH_LINK_TARGET |
458 PATH_OPEN |
459 FD_READDIR |
460 PATH_READLINK |
461 PATH_RENAME_SOURCE |
462 PATH_RENAME_TARGET |
463 PATH_FILESTAT_GET |
464 PATH_FILESTAT_SET_SIZE |
465 PATH_FILESTAT_SET_TIMES |
466 FD_FILESTAT_GET |
467 FD_FILESTAT_SET_SIZE |
468 FD_FILESTAT_SET_TIMES |
469 PATH_SYMLINK |
470 PATH_REMOVE_DIRECTORY |
471 PATH_UNLINK_FILE |
472 POLL_FD_READWRITE |
473 SOCK_SHUTDOWN |
474 SOCK_ACCEPT;
475};347};
476348
477pub const sdflags_t = u8;349pub const sdflags_t = packed struct(u8) {
478pub const SHUT = struct {350 RD: bool = false,
479 pub const RD: sdflags_t = 0x01;351 WR: bool = false,
480 pub const WR: sdflags_t = 0x02;352 _: u6 = 0,
481};353};
482354
483pub const siflags_t = u16;355pub const siflags_t = u16;
484356
485pub const signal_t = u8;357pub const signal_t = enum(u8) {
486pub const SIGNONE: signal_t = 0;358 NONE = 0,
487pub const SIGHUP: signal_t = 1;359 HUP = 1,
488pub const SIGINT: signal_t = 2;360 INT = 2,
489pub const SIGQUIT: signal_t = 3;361 QUIT = 3,
490pub const SIGILL: signal_t = 4;362 ILL = 4,
491pub const SIGTRAP: signal_t = 5;363 TRAP = 5,
492pub const SIGABRT: signal_t = 6;364 ABRT = 6,
493pub const SIGBUS: signal_t = 7;365 BUS = 7,
494pub const SIGFPE: signal_t = 8;366 FPE = 8,
495pub const SIGKILL: signal_t = 9;367 KILL = 9,
496pub const SIGUSR1: signal_t = 10;368 USR1 = 10,
497pub const SIGSEGV: signal_t = 11;369 SEGV = 11,
498pub const SIGUSR2: signal_t = 12;370 USR2 = 12,
499pub const SIGPIPE: signal_t = 13;371 PIPE = 13,
500pub const SIGALRM: signal_t = 14;372 ALRM = 14,
501pub const SIGTERM: signal_t = 15;373 TERM = 15,
502pub const SIGCHLD: signal_t = 16;374 CHLD = 16,
503pub const SIGCONT: signal_t = 17;375 CONT = 17,
504pub const SIGSTOP: signal_t = 18;376 STOP = 18,
505pub const SIGTSTP: signal_t = 19;377 TSTP = 19,
506pub const SIGTTIN: signal_t = 20;378 TTIN = 20,
507pub const SIGTTOU: signal_t = 21;379 TTOU = 21,
508pub const SIGURG: signal_t = 22;380 URG = 22,
509pub const SIGXCPU: signal_t = 23;381 XCPU = 23,
510pub const SIGXFSZ: signal_t = 24;382 XFSZ = 24,
511pub const SIGVTALRM: signal_t = 25;383 VTALRM = 25,
512pub const SIGPROF: signal_t = 26;384 PROF = 26,
513pub const SIGWINCH: signal_t = 27;385 WINCH = 27,
514pub const SIGPOLL: signal_t = 28;386 POLL = 28,
515pub const SIGPWR: signal_t = 29;387 PWR = 29,
516pub const SIGSYS: signal_t = 30;388 SYS = 30,
389};
517390
518pub const subclockflags_t = u16;391pub const subclockflags_t = u16;
519pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;392pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
...@@ -545,29 +418,9 @@ pub const subscription_u_u_t = extern union {...@@ -545,29 +418,9 @@ pub const subscription_u_u_t = extern union {
545 fd_write: subscription_fd_readwrite_t,418 fd_write: subscription_fd_readwrite_t,
546};419};
547420
421/// Nanoseconds.
548pub const timestamp_t = u64;422pub const timestamp_t = u64;
549423
550pub const userdata_t = u64;424pub const userdata_t = u64;
551425
552/// Also known as `WHENCE`.
553pub const whence_t = enum(u8) { SET, CUR, END };426pub const whence_t = enum(u8) { SET, CUR, END };
554
555pub const S = struct {
556 pub const IEXEC = @compileError("TODO audit this");
557 pub const IFBLK = 0x6000;
558 pub const IFCHR = 0x2000;
559 pub const IFDIR = 0x4000;
560 pub const IFIFO = 0xc000;
561 pub const IFLNK = 0xa000;
562 pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
563 pub const IFREG = 0x8000;
564 // There's no concept of UNIX domain socket but we define this value here in order to line with other OSes.
565 pub const IFSOCK = 0x1;
566};
567
568pub const LOCK = struct {
569 pub const SH = 0x1;
570 pub const EX = 0x2;
571 pub const NB = 0x4;
572 pub const UN = 0x8;
573};
lib/std/std.zig+4-1
...@@ -142,7 +142,10 @@ pub const meta = @import("meta.zig");...@@ -142,7 +142,10 @@ pub const meta = @import("meta.zig");
142/// Networking.142/// Networking.
143pub const net = @import("net.zig");143pub const net = @import("net.zig");
144144
145/// Wrappers around OS-specific APIs.145/// POSIX-like API layer.
146pub const posix = @import("os.zig");
147
148/// Non-portable Operating System-specific API.
146pub const os = @import("os.zig");149pub const os = @import("os.zig");
147150
148pub const once = @import("once.zig").once;151pub const once = @import("once.zig").once;
lib/std/time.zig+63-64
...@@ -19,19 +19,17 @@ pub fn sleep(nanoseconds: u64) void {...@@ -19,19 +19,17 @@ pub fn sleep(nanoseconds: u64) void {
19 if (builtin.os.tag == .wasi) {19 if (builtin.os.tag == .wasi) {
20 const w = std.os.wasi;20 const w = std.os.wasi;
21 const userdata: w.userdata_t = 0x0123_45678;21 const userdata: w.userdata_t = 0x0123_45678;
22 const clock = w.subscription_clock_t{22 const clock: w.subscription_clock_t = .{
23 .id = w.CLOCK.MONOTONIC,23 .id = .MONOTONIC,
24 .timeout = nanoseconds,24 .timeout = nanoseconds,
25 .precision = 0,25 .precision = 0,
26 .flags = 0,26 .flags = 0,
27 };27 };
28 const in = w.subscription_t{28 const in: w.subscription_t = .{
29 .userdata = userdata,29 .userdata = userdata,
30 .u = w.subscription_u_t{30 .u = .{
31 .tag = w.EVENTTYPE_CLOCK,31 .tag = .CLOCK,
32 .u = w.subscription_u_u_t{32 .u = .{ .clock = clock },
33 .clock = clock,
34 },
35 },33 },
36 };34 };
3735
...@@ -92,35 +90,36 @@ pub fn microTimestamp() i64 {...@@ -92,35 +90,36 @@ pub fn microTimestamp() i64 {
92/// before the epoch.90/// before the epoch.
93/// See `std.os.clock_gettime` for a POSIX timestamp.91/// See `std.os.clock_gettime` for a POSIX timestamp.
94pub fn nanoTimestamp() i128 {92pub fn nanoTimestamp() i128 {
95 if (builtin.os.tag == .windows) {93 switch (builtin.os.tag) {
96 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,94 .windows => {
97 // which is 1601-01-01.95 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
98 const epoch_adj = epoch.windows * (ns_per_s / 100);96 // which is 1601-01-01.
99 var ft: os.windows.FILETIME = undefined;97 const epoch_adj = epoch.windows * (ns_per_s / 100);
100 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);98 var ft: os.windows.FILETIME = undefined;
101 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;99 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
102 return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;100 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
103 }101 return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
104102 },
105 if (builtin.os.tag == .wasi and !builtin.link_libc) {103 .wasi => {
106 var ns: os.wasi.timestamp_t = undefined;104 var ns: os.wasi.timestamp_t = undefined;
107 const err = os.wasi.clock_time_get(os.wasi.CLOCK.REALTIME, 1, &ns);105 const err = os.wasi.clock_time_get(.REALTIME, 1, &ns);
108 assert(err == .SUCCESS);106 assert(err == .SUCCESS);
109 return ns;107 return ns;
110 }108 },
111109 .uefi => {
112 if (builtin.os.tag == .uefi) {110 var value: std.os.uefi.Time = undefined;
113 var value: std.os.uefi.Time = undefined;111 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
114 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);112 assert(status == .Success);
115 assert(status == .Success);113 return value.toEpoch();
116 return value.toEpoch();114 },
115 else => {
116 var ts: os.timespec = undefined;
117 os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
118 error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
119 };
120 return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
121 },
117 }122 }
118
119 var ts: os.timespec = undefined;
120 os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
121 error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
122 };
123 return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
124}123}
125124
126test "timestamp" {125test "timestamp" {
...@@ -177,43 +176,43 @@ pub const Instant = struct {...@@ -177,43 +176,43 @@ pub const Instant = struct {
177176
178 // true if we should use clock_gettime()177 // true if we should use clock_gettime()
179 const is_posix = switch (builtin.os.tag) {178 const is_posix = switch (builtin.os.tag) {
180 .wasi => builtin.link_libc,179 .windows, .uefi, .wasi => false,
181 .windows, .uefi => false,
182 else => true,180 else => true,
183 };181 };
184182
185 /// Queries the system for the current moment of time as an Instant.183 /// Queries the system for the current moment of time as an Instant.
186 /// This is not guaranteed to be monotonic or steadily increasing, but for most implementations it is.184 /// This is not guaranteed to be monotonic or steadily increasing, but for
185 /// most implementations it is.
187 /// Returns `error.Unsupported` when a suitable clock is not detected.186 /// Returns `error.Unsupported` when a suitable clock is not detected.
188 pub fn now() error{Unsupported}!Instant {187 pub fn now() error{Unsupported}!Instant {
189 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
190 if (builtin.os.tag == .windows) {
191 return Instant{ .timestamp = os.windows.QueryPerformanceCounter() };
192 }
193
194 // On WASI without libc, use clock_time_get directly.
195 if (builtin.os.tag == .wasi and !builtin.link_libc) {
196 var ns: os.wasi.timestamp_t = undefined;
197 const rc = os.wasi.clock_time_get(os.wasi.CLOCK.MONOTONIC, 1, &ns);
198 if (rc != .SUCCESS) return error.Unsupported;
199 return Instant{ .timestamp = ns };
200 }
201
202 if (builtin.os.tag == .uefi) {
203 var value: std.os.uefi.Time = undefined;
204 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
205 if (status != .Success) return error.Unsupported;
206 return Instant{ .timestamp = value.toEpoch() };
207 }
208
209 // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while suspended.
210 // On linux, use BOOTTIME instead of MONOTONIC as it ticks while suspended.
211 // On freebsd derivatives, use MONOTONIC_FAST as currently there's no precision tradeoff.
212 // On other posix systems, MONOTONIC is generally the fastest and ticks while suspended.
213 const clock_id = switch (builtin.os.tag) {188 const clock_id = switch (builtin.os.tag) {
189 .windows => {
190 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
191 return Instant{ .timestamp = os.windows.QueryPerformanceCounter() };
192 },
193 .wasi => {
194 var ns: os.wasi.timestamp_t = undefined;
195 const rc = os.wasi.clock_time_get(.MONOTONIC, 1, &ns);
196 if (rc != .SUCCESS) return error.Unsupported;
197 return .{ .timestamp = ns };
198 },
199 .uefi => {
200 var value: std.os.uefi.Time = undefined;
201 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
202 if (status != .Success) return error.Unsupported;
203 return Instant{ .timestamp = value.toEpoch() };
204 },
205 // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
206 // suspended.
214 .macos, .ios, .tvos, .watchos => os.CLOCK.UPTIME_RAW,207 .macos, .ios, .tvos, .watchos => os.CLOCK.UPTIME_RAW,
208 // On freebsd derivatives, use MONOTONIC_FAST as currently there's
209 // no precision tradeoff.
215 .freebsd, .dragonfly => os.CLOCK.MONOTONIC_FAST,210 .freebsd, .dragonfly => os.CLOCK.MONOTONIC_FAST,
211 // On linux, use BOOTTIME instead of MONOTONIC as it ticks while
212 // suspended.
216 .linux => os.CLOCK.BOOTTIME,213 .linux => os.CLOCK.BOOTTIME,
214 // On other posix systems, MONOTONIC is generally the fastest and
215 // ticks while suspended.
217 else => os.CLOCK.MONOTONIC,216 else => os.CLOCK.MONOTONIC,
218 };217 };
219218
...@@ -262,7 +261,7 @@ pub const Instant = struct {...@@ -262,7 +261,7 @@ pub const Instant = struct {
262 }261 }
263262
264 // WASI timestamps are directly in nanoseconds263 // WASI timestamps are directly in nanoseconds
265 if (builtin.os.tag == .wasi and !builtin.link_libc) {264 if (builtin.os.tag == .wasi) {
266 return self.timestamp - earlier.timestamp;265 return self.timestamp - earlier.timestamp;
267 }266 }
268267
src/TypedValue.zig+16-8
...@@ -367,18 +367,26 @@ pub fn print(...@@ -367,18 +367,26 @@ pub fn print(
367 try writer.writeAll(".?");367 try writer.writeAll(".?");
368 },368 },
369 .elem => |elem| {369 .elem => |elem| {
370 try print(.{370 if (level == 0) {
371 .ty = Type.fromInterned(ip.typeOf(elem.base)),371 try writer.writeAll("(...)");
372 .val = Value.fromInterned(elem.base),372 } else {
373 }, writer, level - 1, mod);373 try print(.{
374 .ty = Type.fromInterned(ip.typeOf(elem.base)),
375 .val = Value.fromInterned(elem.base),
376 }, writer, level - 1, mod);
377 }
374 try writer.print("[{}]", .{elem.index});378 try writer.print("[{}]", .{elem.index});
375 },379 },
376 .field => |field| {380 .field => |field| {
377 const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base));381 const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base));
378 try print(.{382 if (level == 0) {
379 .ty = ptr_container_ty,383 try writer.writeAll("(...)");
380 .val = Value.fromInterned(field.base),384 } else {
381 }, writer, level - 1, mod);385 try print(.{
386 .ty = ptr_container_ty,
387 .val = Value.fromInterned(field.base),
388 }, writer, level - 1, mod);
389 }
382390
383 const container_ty = ptr_container_ty.childType(mod);391 const container_ty = ptr_container_ty.childType(mod);
384 switch (container_ty.zigTypeTag(mod)) {392 switch (container_ty.zigTypeTag(mod)) {
test/behavior/packed-struct.zig+29
...@@ -1248,3 +1248,32 @@ test "bitcasting a packed struct at comptime and using the result" {...@@ -1248,3 +1248,32 @@ test "bitcasting a packed struct at comptime and using the result" {
1248 _ = Struct.bitcast(@as(u64, 0)).cannotReach();1248 _ = Struct.bitcast(@as(u64, 0)).cannotReach();
1249 }1249 }
1250}1250}
1251
1252test "2-byte packed struct argument in C calling convention" {
1253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1255 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1256 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1257
1258 const S = packed struct(u16) {
1259 x: u15 = 0,
1260 y: u1 = 0,
1261
1262 fn foo(s: @This()) callconv(.C) i32 {
1263 return s.x;
1264 }
1265 fn bar(s: @This()) !void {
1266 try expect(foo(s) == 1);
1267 }
1268 };
1269 {
1270 var s: S = .{};
1271 s.x += 1;
1272 try S.bar(s);
1273 }
1274 comptime {
1275 var s: S = .{};
1276 s.x += 1;
1277 try S.bar(s);
1278 }
1279}