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"
1212PREFIX="$HOME/deps/$CACHE_BASENAME"
1313ZIG="$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
1717# Make the `zig version` number consistent.
1818# 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"
1212PREFIX="$HOME/deps/$CACHE_BASENAME"
1313ZIG="$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
1717# Make the `zig version` number consistent.
1818# 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"
1212PREFIX="$HOME/deps/$CACHE_BASENAME"
1313ZIG="$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
1717# Make the `zig version` number consistent.
1818# 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"
1212PREFIX="$HOME/deps/$CACHE_BASENAME"
1313ZIG="$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
1717# Make the `zig version` number consistent.
1818# This will affect the cmake command below.
lib/std/c.zig+567-38
......@@ -4,6 +4,10 @@ const c = @This();
44const page_size = std.mem.page_size;
55const iovec = std.os.iovec;
66const 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
812/// If not linking libc, returns false.
913/// If linking musl libc, returns true.
......@@ -13,7 +17,7 @@ const iovec_const = std.os.iovec_const;
1317pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
1418 return comptime blk: {
1519 if (!builtin.link_libc) break :blk false;
16 if (builtin.abi.isMusl()) break :blk true;
20 if (native_abi.isMusl()) break :blk true;
1721 if (builtin.target.isGnuLibC()) {
1822 const ver = builtin.os.version_range.linux.glibc;
1923 const order = ver.order(glibc_version);
......@@ -27,7 +31,7 @@ pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
2731 };
2832}
2933
30pub usingnamespace switch (builtin.os.tag) {
34pub usingnamespace switch (native_os) {
3135 .linux => @import("c/linux.zig"),
3236 .windows => @import("c/windows.zig"),
3337 .macos, .ios, .tvos, .watchos => @import("c/darwin.zig"),
......@@ -36,16 +40,504 @@ pub usingnamespace switch (builtin.os.tag) {
3640 .dragonfly => @import("c/dragonfly.zig"),
3741 .openbsd => @import("c/openbsd.zig"),
3842 .haiku => @import("c/haiku.zig"),
39 .hermit => @import("c/hermit.zig"),
4043 .solaris, .illumos => @import("c/solaris.zig"),
41 .fuchsia => @import("c/fuchsia.zig"),
42 .minix => @import("c/minix.zig"),
4344 .emscripten => @import("c/emscripten.zig"),
44 .wasi => @import("c/wasi.zig"),
45 .wasi => wasi,
4546 else => struct {},
4647};
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) {
49541 .linux => std.os.linux.MAP,
50542 .emscripten => packed struct(u32) {
51543 TYPE: enum(u4) {
......@@ -187,10 +679,10 @@ pub const MAP = switch (builtin.os.tag) {
187679/// Used by libc to communicate failure. Not actually part of the underlying syscall.
188680pub 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
192684// Unix-like systems
193pub usingnamespace switch (builtin.os.tag) {
685pub usingnamespace switch (native_os) {
194686 .netbsd, .windows => struct {},
195687 else => struct {
196688 pub const DIR = opaque {};
......@@ -225,25 +717,40 @@ pub usingnamespace switch (builtin.os.tag) {
225717 },
226718};
227719
228pub usingnamespace switch (builtin.os.tag) {
229 .netbsd, .macos, .ios, .watchos, .tvos, .windows => struct {},
230 else => struct {
231 pub extern "c" fn fstat(fd: c.fd_t, buf: *c.Stat) c_int;
232 pub extern "c" fn readdir(dp: *c.DIR) ?*c.dirent;
720pub const fstat = switch (native_os) {
721 .netbsd => private.__fstat50,
722 .macos, .ios, .watchos, .tvos => switch (native_arch) {
723 .aarch64 => private.fstat,
724 else => private.@"fstat$INODE64",
233725 },
726 else => private.fstat,
234727};
235728
236pub usingnamespace switch (builtin.os.tag) {
237 .macos, .ios, .watchos, .tvos => struct {},
238 else => struct {
239 pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
240 pub extern "c" fn fstatat(dirfd: c.fd_t, path: [*:0]const u8, stat_buf: *c.Stat, flags: u32) c_int;
729pub const fstatat = switch (native_os) {
730 .macos, .ios, .watchos, .tvos => switch (native_arch) {
731 .aarch64 => private.fstatat,
732 else => private.@"fstatat$INODE64",
241733 },
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,
242749};
243750
244751pub fn getErrno(rc: anytype) c.E {
245752 if (rc == -1) {
246 return @as(c.E, @enumFromInt(c._errno().*));
753 return @enumFromInt(c._errno().*);
247754 } else {
248755 return .SUCCESS;
249756 }
......@@ -263,8 +770,8 @@ pub extern "c" fn _exit(code: c_int) noreturn;
263770pub extern "c" fn isatty(fd: c.fd_t) c_int;
264771pub extern "c" fn close(fd: c.fd_t) c_int;
265772pub 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;
267pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
773pub extern "c" fn open(path: [*:0]const u8, oflag: O, ...) c_int;
774pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;
268775pub extern "c" fn ftruncate(fd: c_int, length: c.off_t) c_int;
269776pub extern "c" fn raise(sig: c_int) c_int;
270777pub 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
275782pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: c.off_t) isize;
276783pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;
277784pub 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;
279786pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
280787pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
281788pub 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(
348855 arg1: ?*anyopaque,
349856 arg2: usize,
350857 arg3: c_int,
351) if (builtin.os.tag == .windows) c_int else isize;
858) if (native_os == .windows) c_int else isize;
352859pub extern "c" fn recvfrom(
353860 sockfd: c.fd_t,
354861 noalias buf: *anyopaque,
......@@ -356,7 +863,7 @@ pub extern "c" fn recvfrom(
356863 flags: u32,
357864 noalias src_addr: ?*c.sockaddr,
358865 noalias addrlen: ?*c.socklen_t,
359) if (builtin.os.tag == .windows) c_int else isize;
866) if (native_os == .windows) c_int else isize;
360867pub extern "c" fn recvmsg(sockfd: c.fd_t, msg: *c.msghdr, flags: u32) isize;
361868
362869pub extern "c" fn kill(pid: c.pid_t, sig: c_int) c_int;
......@@ -492,18 +999,18 @@ pub extern "c" fn dn_expand(
492999 length: c_int,
4931000) c_int;
4941001
495pub const PTHREAD_MUTEX_INITIALIZER = c.pthread_mutex_t{};
496pub extern "c" fn pthread_mutex_lock(mutex: *c.pthread_mutex_t) c.E;
497pub extern "c" fn pthread_mutex_unlock(mutex: *c.pthread_mutex_t) c.E;
498pub extern "c" fn pthread_mutex_trylock(mutex: *c.pthread_mutex_t) c.E;
499pub extern "c" fn pthread_mutex_destroy(mutex: *c.pthread_mutex_t) c.E;
1002pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
1003pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c.E;
1004pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c.E;
1005pub extern "c" fn pthread_mutex_trylock(mutex: *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{};
502pub extern "c" fn pthread_cond_wait(noalias cond: *c.pthread_cond_t, noalias mutex: *c.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;
504pub extern "c" fn pthread_cond_signal(cond: *c.pthread_cond_t) c.E;
505pub extern "c" fn pthread_cond_broadcast(cond: *c.pthread_cond_t) c.E;
506pub extern "c" fn pthread_cond_destroy(cond: *c.pthread_cond_t) c.E;
1008pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
1009pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) 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;
1011pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c.E;
1012pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c.E;
1013pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c.E;
5071014
5081015pub extern "c" fn pthread_rwlock_destroy(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;
5091016pub 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 {
5421049 // android bionic libc does not implement getcontext,
5431050 // and std.os.linux.getcontext also cannot be built for
5441051 // 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 {
5461053 // musl does not implement getcontext
5471054 pub const getcontext = std.os.linux.getcontext;
5481055} else struct {
5491056 pub extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;
5501057};
5511058
552pub const max_align_t = if (builtin.abi == .msvc)
1059pub const max_align_t = if (native_abi == .msvc)
5531060 f64
5541061else if (builtin.target.isDarwin())
5551062 c_longdouble
......@@ -558,3 +1065,25 @@ else
5581065 a: c_longlong,
5591066 b: c_longdouble,
5601067 };
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;
169169pub const copyfile_state_t = *opaque {};
170170pub 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
175172pub 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
197174pub extern "c" fn mach_absolute_time() u64;
198175pub extern "c" fn mach_continuous_time() u64;
199176pub 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) {
866843 QOS_CLASS_UNSPECIFIED = 0x00,
867844};
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};
881846pub 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
885848pub const pthread_attr_t = extern struct {
886849 __sig: c_long,
......@@ -1202,16 +1165,12 @@ pub const Sigaction = extern struct {
12021165};
12031166
12041167pub const dirent = extern struct {
1205 d_ino: u64,
1206 d_seekoff: u64,
1207 d_reclen: u16,
1208 d_namlen: u16,
1209 d_type: u8,
1210 d_name: [1024]u8,
1211
1212 pub fn reclen(self: dirent) u16 {
1213 return self.d_reclen;
1214 }
1168 ino: u64,
1169 seekoff: u64,
1170 reclen: u16,
1171 namlen: u16,
1172 type: u8,
1173 name: [1024]u8,
12151174};
12161175
12171176/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
......@@ -1346,49 +1305,6 @@ pub const X_OK = 1;
13461305pub const W_OK = 2;
13471306pub 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
13921308pub const SEEK = struct {
13931309 pub const SET = 0x0;
13941310 pub const CUR = 0x1;
......@@ -2529,18 +2445,6 @@ pub const S = struct {
25292445
25302446pub 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
25442448pub const addrinfo = extern struct {
25452449 flags: i32,
25462450 family: i32,
lib/std/c/dragonfly.zig+7-55
......@@ -22,22 +22,11 @@ pub extern "c" fn lwp_gettid() c_int;
2222
2323pub 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
3225pub const pthread_attr_t = extern struct { // copied from freebsd
3326 __size: [56]u8,
3427 __align: c_long,
3528};
3629
37pub const pthread_rwlock_t = extern struct {
38 ptr: ?*anyopaque = null,
39};
40
4130pub const sem_t = ?*opaque {};
4231
4332pub 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
394383pub const W_OK = 2; // test for write permission
395384pub 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
426386pub const SEEK = struct {
427387 pub const SET = 0;
428388 pub const CUR = 1;
......@@ -458,24 +418,16 @@ pub const F = struct {
458418
459419pub 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
469421pub const dirent = extern struct {
470 d_fileno: c_ulong,
471 d_namlen: u16,
472 d_type: u8,
473 d_unused1: u8,
474 d_unused2: u32,
475 d_name: [256]u8,
422 fileno: c_ulong,
423 namlen: u16,
424 type: u8,
425 unused1: u8,
426 unused2: u32,
427 name: [256]u8,
476428
477429 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);
479431 }
480432};
481433
lib/std/c/emscripten.zig+5-20
......@@ -3,7 +3,6 @@ const maxInt = std.math.maxInt;
33const emscripten = std.os.emscripten;
44
55pub const AF = emscripten.AF;
6pub const AT = emscripten.AT;
76pub const CLOCK = emscripten.CLOCK;
87pub const CPU_COUNT = emscripten.CPU_COUNT;
98pub const E = emscripten.E;
......@@ -19,7 +18,6 @@ pub const MADV = emscripten.MADV;
1918pub const MSF = emscripten.MSF;
2019pub const MSG = emscripten.MSG;
2120pub const NAME_MAX = emscripten.NAME_MAX;
22pub const O = emscripten.O;
2321pub const PATH_MAX = emscripten.PATH_MAX;
2422pub const POLL = emscripten.POLL;
2523pub const PROT = emscripten.PROT;
......@@ -159,19 +157,6 @@ pub const pthread_attr_t = extern struct {
159157 __align: c_long,
160158};
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
175160pub const pthread_key_t = c_uint;
176161pub const sem_t = extern struct {
177162 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
......@@ -189,9 +174,9 @@ pub const RTLD = struct {
189174};
190175
191176pub const dirent = struct {
192 d_ino: c_uint,
193 d_off: c_uint,
194 d_reclen: c_ushort,
195 d_type: u8,
196 d_name: [256]u8,
177 ino: c_uint,
178 off: c_uint,
179 reclen: c_ushort,
180 type: u8,
181 name: [256]u8,
197182};
lib/std/c/freebsd.zig+9-70
......@@ -44,16 +44,6 @@ pub extern "c" fn sendfile(
4444pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int;
4545pub 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
5747pub const pthread_attr_t = extern struct {
5848 inner: ?*anyopaque = null,
5949};
......@@ -376,23 +366,19 @@ pub const timeval = extern struct {
376366
377367pub const dirent = extern struct {
378368 /// File number of entry.
379 d_fileno: ino_t,
369 fileno: ino_t,
380370 /// Directory offset of entry.
381 d_off: off_t,
371 off: off_t,
382372 /// Length of this record.
383 d_reclen: u16,
373 reclen: u16,
384374 /// File type, one of DT_.
385 d_type: u8,
386 _d_pad0: u8,
387 /// Length of the d_name member.
388 d_namlen: u16,
389 _d_pad1: u16,
375 type: u8,
376 pad0: u8 = 0,
377 /// Length of the name member.
378 namlen: u16,
379 pad1: u16 = 0,
390380 /// Name of entry.
391 d_name: [255:0]u8,
392
393 pub fn reclen(self: dirent) u16 {
394 return self.d_reclen;
395 }
381 name: [255:0]u8,
396382};
397383
398384pub const in_port_t = u16;
......@@ -746,36 +732,6 @@ pub const X_OK = 1; // test for execute or search permission
746732pub const W_OK = 2; // test for write permission
747733pub 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
779735/// Command flags for fcntl(2).
780736pub const F = struct {
781737 /// Duplicate file descriptor.
......@@ -1573,23 +1529,6 @@ pub const S = struct {
15731529
15741530pub 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
15931532pub const addrinfo = extern struct {
15941533 flags: i32,
15951534 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 {
4545 __stack_address: ?*anyopaque,
4646};
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
6448pub const EAI = enum(c_int) {
6549 /// address family for hostname not supported
6650 ADDRFAMILY = 1,
......@@ -238,16 +222,12 @@ pub const timespec = extern struct {
238222};
239223
240224pub const dirent = extern struct {
241 d_dev: i32,
242 d_pdev: i32,
243 d_ino: i64,
244 d_pino: i64,
245 d_reclen: u16,
246 d_name: [256]u8,
247
248 pub fn reclen(self: dirent) u16 {
249 return self.d_reclen;
250 }
225 dev: i32,
226 pdev: i32,
227 ino: i64,
228 pino: i64,
229 reclen: u16,
230 name: [256]u8,
251231};
252232
253233pub const B_OS_NAME_LENGTH = 32; // OS.h
......@@ -510,32 +490,6 @@ pub const X_OK = 1; // test for execute or search permission
510490pub const W_OK = 2; // test for write permission
511491pub 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
539493pub const F = struct {
540494 pub const DUPFD = 0x0001;
541495 pub const GETFD = 0x0002;
......@@ -923,14 +877,6 @@ pub const S = struct {
923877
924878pub 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
934880pub const addrinfo = extern struct {
935881 flags: i32,
936882 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;
99
1010pub const AF = linux.AF;
1111pub const ARCH = linux.ARCH;
12pub const AT = linux.AT;
1312pub const CLOCK = linux.CLOCK;
1413pub const CPU_COUNT = linux.CPU_COUNT;
1514pub const E = linux.E;
......@@ -28,7 +27,6 @@ pub const MSF = linux.MSF;
2827pub const MMAP2_UNIT = linux.MMAP2_UNIT;
2928pub const MSG = linux.MSG;
3029pub const NAME_MAX = linux.NAME_MAX;
31pub const O = linux.O;
3230pub const PATH_MAX = linux.PATH_MAX;
3331pub const POLL = linux.POLL;
3432pub const PROT = linux.PROT;
......@@ -241,8 +239,8 @@ pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
241239pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
242240pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
243241pub 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;
245pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
242pub extern "c" fn open64(path: [*:0]const u8, oflag: linux.O, ...) c_int;
243pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: linux.O, ...) c_int;
246244pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
247245pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;
248246pub 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
277275pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
278276
279277pub 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
282280pub 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 {
313311 __align: c_long,
314312};
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};
336314pub const pthread_key_t = c_uint;
337315pub const sem_t = extern struct {
338316 __size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
339317};
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};
353319const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
354320
355321pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
......@@ -365,16 +331,16 @@ pub const RTLD = struct {
365331};
366332
367333pub const dirent = struct {
368 d_ino: c_uint,
369 d_off: c_uint,
370 d_reclen: c_ushort,
371 d_type: u8,
372 d_name: [256]u8,
334 ino: c_uint,
335 off: c_uint,
336 reclen: c_ushort,
337 type: u8,
338 name: [256]u8,
373339};
374340pub const dirent64 = struct {
375 d_ino: c_ulong,
376 d_off: c_ulong,
377 d_reclen: c_ushort,
378 d_type: u8,
379 d_name: [256]u8,
341 ino: c_ulong,
342 off: c_ulong,
343 reclen: c_ushort,
344 type: u8,
345 name: [256]u8,
380346};
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;
1818pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
1919pub 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
2421pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int;
2522pub const stat = __stat50;
2623
......@@ -62,41 +59,6 @@ pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: u
6259pub extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;
6360pub 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
10062const pthread_spin_t = switch (builtin.cpu.arch) {
10163 .aarch64, .aarch64_be, .aarch64_32 => u8,
10264 .mips, .mipsel, .mips64, .mips64el => u32,
......@@ -337,15 +299,11 @@ pub const timeval = extern struct {
337299pub const MAXNAMLEN = 511;
338300
339301pub const dirent = extern struct {
340 d_fileno: ino_t,
341 d_reclen: u16,
342 d_namlen: u16,
343 d_type: u8,
344 d_name: [MAXNAMLEN + 1]u8,
345
346 pub fn reclen(self: dirent) u16 {
347 return self.d_reclen;
348 }
302 fileno: ino_t,
303 reclen: u16,
304 namlen: u16,
305 type: u8,
306 name: [MAXNAMLEN + 1]u8,
349307};
350308
351309pub const SOCK = struct {
......@@ -630,53 +588,6 @@ pub const X_OK = 1; // test for execute or search permission
630588pub const W_OK = 2; // test for write permission
631589pub 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
680591pub const F = struct {
681592 pub const DUPFD = 0;
682593 pub const GETFD = 1;
......@@ -1466,21 +1377,6 @@ pub const S = struct {
14661377 }
14671378};
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
14841380pub const HOST_NAME_MAX = 255;
14851381
14861382pub 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;
1919pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
2020pub 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};
3122pub const pthread_spinlock_t = extern struct {
3223 inner: ?*anyopaque = null,
3324};
......@@ -336,17 +327,13 @@ pub const timezone = extern struct {
336327pub const MAXNAMLEN = 255;
337328
338329pub const dirent = extern struct {
339 d_fileno: ino_t,
340 d_off: off_t,
341 d_reclen: u16,
342 d_type: u8,
343 d_namlen: u8,
344 __d_padding: [4]u8,
345 d_name: [MAXNAMLEN + 1]u8,
346
347 pub fn reclen(self: dirent) u16 {
348 return self.d_reclen;
349 }
330 fileno: ino_t,
331 off: off_t,
332 reclen: u16,
333 type: u8,
334 namlen: u8,
335 _: u32 align(1) = 0,
336 name: [MAXNAMLEN + 1]u8,
350337};
351338
352339pub const in_port_t = u16;
......@@ -489,47 +476,6 @@ pub const X_OK = 1; // test for execute or search permission
489476pub const W_OK = 2; // test for write permission
490477pub 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
533479pub const F = struct {
534480 pub const DUPFD = 0;
535481 pub const GETFD = 1;
......@@ -1312,21 +1258,6 @@ pub const S = struct {
13121258 }
13131259};
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
13301261pub const HOST_NAME_MAX = 255;
13311262
13321263pub const IPPROTO = struct {
lib/std/c/solaris.zig+4-74
......@@ -21,29 +21,6 @@ pub extern "c" fn sysconf(sc: c_int) i64;
2121pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;
2222pub 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};
4724pub const pthread_attr_t = extern struct {
4825 mutexattr: ?*anyopaque = null,
4926};
......@@ -266,17 +243,13 @@ pub const MAXNAMLEN = 511;
266243
267244pub const dirent = extern struct {
268245 /// Inode number of entry.
269 d_ino: ino_t,
246 ino: ino_t,
270247 /// Offset of this entry on disk.
271 d_off: off_t,
248 off: off_t,
272249 /// Length of this record.
273 d_reclen: u16,
250 reclen: u16,
274251 /// File name.
275 d_name: [MAXNAMLEN:0]u8,
276
277 pub fn reclen(self: dirent) u16 {
278 return self.d_reclen;
279 }
252 name: [MAXNAMLEN:0]u8,
280253};
281254
282255pub const SOCK = struct {
......@@ -708,32 +681,6 @@ pub const F = struct {
708681 pub const RMDNY = 0x4;
709682};
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
737684pub const LOCK = struct {
738685 pub const SH = 1;
739686 pub const EX = 2;
......@@ -1430,23 +1377,6 @@ pub const S = struct {
14301377 }
14311378};
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
14501380pub const POSIX_FADV = struct {
14511381 pub const NORMAL = 0;
14521382 pub const RANDOM = 1;
lib/std/c/wasi.zig+90-45
......@@ -1,6 +1,6 @@
1const builtin = @import("builtin");
12const std = @import("../std.zig");
23const wasi = std.os.wasi;
3const FDFLAG = wasi.FDFLAG;
44
55extern threadlocal var errno: c_int;
66
......@@ -8,42 +8,82 @@ pub fn _errno() *c_int {
88 return &errno;
99}
1010
11pub const AT = wasi.AT;
12pub const CLOCK = wasi.CLOCK;
13pub const E = wasi.E;
14pub const IOV_MAX = wasi.IOV_MAX;
15pub const LOCK = wasi.LOCK;
16pub const S = wasi.S;
17pub const STDERR_FILENO = wasi.STDERR_FILENO;
18pub const STDIN_FILENO = wasi.STDIN_FILENO;
19pub const STDOUT_FILENO = wasi.STDOUT_FILENO;
11pub const mode_t = u32;
12pub const time_t = i64;
13
14pub const timespec = extern struct {
15 tv_sec: time_t,
16 tv_nsec: isize,
17
18 pub fn fromTimestamp(tm: wasi.timestamp_t) timespec {
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};
2060pub const fd_t = wasi.fd_t;
2161pub const pid_t = c_int;
2262pub const uid_t = u32;
2363pub const gid_t = u32;
2464pub const off_t = i64;
25pub const ino_t = wasi.ino_t;
26pub const mode_t = wasi.mode_t;
27pub const time_t = wasi.time_t;
28pub const timespec = wasi.timespec;
65pub const ino_t = wasi.inode_t;
66pub const dev_t = wasi.device_t;
67pub const nlink_t = c_ulonglong;
68pub const blksize_t = c_long;
69pub const blkcnt_t = c_longlong;
2970
3071pub const Stat = extern struct {
31 dev: i32,
72 dev: dev_t,
3273 ino: ino_t,
33 nlink: u64,
34
74 nlink: nlink_t,
3575 mode: mode_t,
3676 uid: uid_t,
3777 gid: gid_t,
38 __pad0: isize,
39 rdev: i32,
78 __pad0: c_uint = 0,
79 rdev: dev_t,
4080 size: off_t,
41 blksize: i32,
42 blocks: i64,
43
81 blksize: blksize_t,
82 blocks: blkcnt_t,
4483 atim: timespec,
4584 mtim: timespec,
4685 ctim: timespec,
86 __reserved: [3]c_longlong = [3]c_longlong{ 0, 0, 0 },
4787
4888 pub fn atime(self: @This()) timespec {
4989 return self.atim;
......@@ -56,30 +96,35 @@ pub const Stat = extern struct {
5696 pub fn ctime(self: @This()) timespec {
5797 return self.ctim;
5898 }
59};
6099
61/// Derived from
62/// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
63pub const O = struct {
64 pub const ACCMODE = (EXEC | RDWR | SEARCH);
65 pub const APPEND = @as(u32, FDFLAG.APPEND);
66 pub const CLOEXEC = (0);
67 pub const CREAT = ((1 << 0) << 12); // = __WASI_OFLAGS_CREAT << 12
68 pub const DIRECTORY = ((1 << 1) << 12); // = __WASI_OFLAGS_DIRECTORY << 12
69 pub const DSYNC = @as(u32, FDFLAG.DSYNC);
70 pub const EXCL = ((1 << 2) << 12); // = __WASI_OFLAGS_EXCL << 12
71 pub const EXEC = (0x02000000);
72 pub const NOCTTY = (0);
73 pub const NOFOLLOW = (0x01000000);
74 pub const NONBLOCK = @as(u32, FDFLAG.NONBLOCK);
75 pub const RDONLY = (0x04000000);
76 pub const RDWR = (RDONLY | WRONLY);
77 pub const RSYNC = @as(u32, FDFLAG.RSYNC);
78 pub const SEARCH = (0x08000000);
79 pub const SYNC = @as(u32, FDFLAG.SYNC);
80 pub const TRUNC = ((1 << 3) << 12); // = __WASI_OFLAGS_TRUNC << 12
81 pub const TTY_INIT = (0);
82 pub const WRONLY = (0x10000000);
100 pub fn fromFilestat(stat: wasi.filestat_t) Stat {
101 return .{
102 .dev = stat.dev,
103 .ino = stat.ino,
104 .mode = switch (stat.filetype) {
105 .UNKNOWN => 0,
106 .BLOCK_DEVICE => S.IFBLK,
107 .CHARACTER_DEVICE => S.IFCHR,
108 .DIRECTORY => S.IFDIR,
109 .REGULAR_FILE => S.IFREG,
110 .SOCKET_DGRAM => S.IFSOCK,
111 .SOCKET_STREAM => S.IFIFO,
112 .SYMBOLIC_LINK => S.IFLNK,
113 _ => 0,
114 },
115 .nlink = stat.nlink,
116 .size = @intCast(stat.size),
117 .atim = timespec.fromTimestamp(stat.atim),
118 .mtim = timespec.fromTimestamp(stat.mtim),
119 .ctim = timespec.fromTimestamp(stat.ctim),
120
121 .uid = 0,
122 .gid = 0,
123 .rdev = 0,
124 .blksize = 0,
125 .blocks = 0,
126 };
127 }
83128};
84129
85130pub const F = struct {
lib/std/c/windows.zig-33
......@@ -11,7 +11,6 @@ pub extern "c" fn _msize(memblock: ?*anyopaque) usize;
1111// need to verify which of these is actually supported on windows
1212pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
1313pub 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;
1514pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
1615pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
1716pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
......@@ -200,11 +199,6 @@ pub const STRUNCATE = 80;
200199
201200pub const F_OK = 0;
202201
203/// Remove directory instead of unlinking file
204pub const AT = struct {
205 pub const REMOVEDIR = 0x200;
206};
207
208202pub const in_port_t = u16;
209203pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
210204pub const socklen_t = ws2_32.socklen_t;
......@@ -229,31 +223,4 @@ pub const SOL = ws2_32.SOL;
229223pub const SO = ws2_32.SO;
230224pub 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
259226pub const IFNAMESIZE = 30;
lib/std/child_process.zig+3-3
......@@ -495,7 +495,7 @@ pub const ChildProcess = struct {
495495 }
496496
497497 fn spawnPosix(self: *ChildProcess) SpawnError!void {
498 const pipe_flags = 0;
498 const pipe_flags: os.O = .{};
499499 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
500500 errdefer if (self.stdin_behavior == StdIo.Pipe) {
501501 destroyPipe(stdin_pipe);
......@@ -513,7 +513,7 @@ pub const ChildProcess = struct {
513513
514514 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
515515 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) {
517517 error.PathAlreadyExists => unreachable,
518518 error.NoSpaceLeft => unreachable,
519519 error.FileTooBig => unreachable,
......@@ -572,7 +572,7 @@ pub const ChildProcess = struct {
572572 // end with eventfd
573573 break :blk [2]os.fd_t{ fd, fd };
574574 } else {
575 break :blk try os.pipe2(os.O.CLOEXEC);
575 break :blk try os.pipe2(.{ .CLOEXEC = true });
576576 }
577577 };
578578 errdefer destroyPipe(err_pipe);
lib/std/compress/deflate/deflate_fast.zig+8
......@@ -354,6 +354,10 @@ pub const DeflateFast = struct {
354354};
355355
356356test "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 }
357361 const expectEqual = std.testing.expectEqual;
358362
359363 {
......@@ -450,6 +454,10 @@ test "best speed match 1/3" {
450454}
451455
452456test "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 }
453461 const expectEqual = std.testing.expectEqual;
454462
455463 {
lib/std/dynamic_library.zig+1-1
......@@ -115,7 +115,7 @@ pub const ElfDynLib = struct {
115115
116116 /// Trusts the file. Malicious file will be able to execute arbitrary code.
117117 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);
119119 defer os.close(fd);
120120
121121 const stat = try os.fstat(fd);
lib/std/fs/Dir.zig+239-224
......@@ -62,16 +62,16 @@ pub const Iterator = switch (builtin.os.tag) {
6262 self.end_index = @as(usize, @intCast(rc));
6363 }
6464 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;
6666 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)) {
7171 continue :start_over;
7272 }
7373
74 const entry_kind: Entry.Kind = switch (darwin_entry.d_type) {
74 const entry_kind: Entry.Kind = switch (darwin_entry.type) {
7575 posix.DT.BLK => .block_device,
7676 posix.DT.CHR => .character_device,
7777 posix.DT.DIR => .directory,
......@@ -110,14 +110,14 @@ pub const Iterator = switch (builtin.os.tag) {
110110 self.end_index = @as(usize, @intCast(rc));
111111 }
112112 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;
114114 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);
117117 if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
118118 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.
121121 const stat_info = posix.fstatat(
122122 self.dir.fd,
123123 name,
......@@ -174,23 +174,23 @@ pub const Iterator = switch (builtin.os.tag) {
174174 self.end_index = @as(usize, @intCast(rc));
175175 }
176176 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;
178178 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
182182 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.
184184 .openbsd, .netbsd => true,
185185 else => false,
186186 };
187187 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))
189189 {
190190 continue :start_over;
191191 }
192192
193 const entry_kind: Entry.Kind = switch (bsd_entry.d_type) {
193 const entry_kind: Entry.Kind = switch (bsd_entry.type) {
194194 posix.DT.BLK => .block_device,
195195 posix.DT.CHR => .character_device,
196196 posix.DT.DIR => .directory,
......@@ -256,18 +256,18 @@ pub const Iterator = switch (builtin.os.tag) {
256256 self.end_index = @as(usize, @intCast(rc));
257257 }
258258 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;
260260 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)) {
264264 continue :start_over;
265265 }
266266
267267 var stat_info: posix.Stat = undefined;
268268 const rc = posix.system._kern_read_stat(
269269 self.dir.fd,
270 &haiku_entry.d_name,
270 &haiku_entry.name,
271271 false,
272272 &stat_info,
273273 0,
......@@ -359,17 +359,17 @@ pub const Iterator = switch (builtin.os.tag) {
359359 self.end_index = rc;
360360 }
361361 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;
363363 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
367367 // skip . and .. entries
368368 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
369369 continue :start_over;
370370 }
371371
372 const entry_kind: Entry.Kind = switch (linux_entry.d_type) {
372 const entry_kind: Entry.Kind = switch (linux_entry.type) {
373373 linux.DT.BLK => .block_device,
374374 linux.DT.CHR => .character_device,
375375 linux.DT.DIR => .directory,
......@@ -525,23 +525,23 @@ pub const Iterator = switch (builtin.os.tag) {
525525 const entry = @as(*align(1) w.dirent_t, @ptrCast(&self.buf[self.index]));
526526 const entry_size = @sizeOf(w.dirent_t);
527527 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) {
529529 // This case, the name is truncated, so we need to call readdir to store the entire name.
530530 self.end_index = self.index; // Force fd_readdir in the next loop.
531531 continue :start_over;
532532 }
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;
536536 self.index = next_index;
537 self.cookie = entry.d_next;
537 self.cookie = entry.next;
538538
539539 // skip . and .. entries
540540 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
541541 continue :start_over;
542542 }
543543
544 const entry_kind: Entry.Kind = switch (entry.d_type) {
544 const entry_kind: Entry.Kind = switch (entry.type) {
545545 .BLOCK_DEVICE => .block_device,
546546 .CHARACTER_DEVICE => .character_device,
547547 .DIRECTORY => .directory,
......@@ -764,81 +764,79 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
764764 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
765765 return self.openFileW(path_w.span(), flags);
766766 }
767 if (builtin.os.tag == .wasi and !builtin.link_libc) {
768 return self.openFileWasi(sub_path, flags);
767 if (builtin.os.tag == .wasi) {
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 };
769789 }
770790 const path_c = try posix.toPosixPath(sub_path);
771791 return self.openFileZ(&path_c, flags);
772792}
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
799794/// Same as `openFile` but the path parameter is null-terminated.
800795pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
801 if (builtin.os.tag == .windows) {
802 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);
803 return self.openFileW(path_w.span(), flags);
796 switch (builtin.os.tag) {
797 .windows => {
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 => {},
804805 }
805806
806 var os_flags: u32 = 0;
807 if (@hasDecl(posix.O, "CLOEXEC")) os_flags = posix.O.CLOEXEC;
807 var os_flags: posix.O = .{
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
809818 // Use the O locking flags if the os supports them to acquire the lock
810819 // atomically.
811 const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");
820 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
812821 if (has_flock_open_flags) {
813 // Note that the O.NONBLOCK flag is removed after the openat() call
822 // Note that the NONBLOCK flag is removed after the openat() call
814823 // is successful.
815 const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking)
816 posix.O.NONBLOCK
817 else
818 0;
819 os_flags |= switch (flags.lock) {
820 .none => @as(u32, 0),
821 .shared => posix.O.SHLOCK | nonblocking_lock_flag,
822 .exclusive => posix.O.EXLOCK | nonblocking_lock_flag,
823 };
824 }
825 if (@hasDecl(posix.O, "LARGEFILE")) {
826 os_flags |= posix.O.LARGEFILE;
827 }
828 if (@hasDecl(posix.O, "NOCTTY") and !flags.allow_ctty) {
829 os_flags |= posix.O.NOCTTY;
824 switch (flags.lock) {
825 .none => {},
826 .shared => {
827 os_flags.SHLOCK = true;
828 os_flags.NONBLOCK = flags.lock_nonblocking;
829 },
830 .exclusive => {
831 os_flags.EXLOCK = true;
832 os_flags.NONBLOCK = flags.lock_nonblocking;
833 },
834 }
830835 }
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 };
836836 const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
837837 errdefer posix.close(fd);
838838
839 // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block
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) {
839 if (@hasDecl(posix.system, "LOCK")) {
842840 if (!has_flock_open_flags and flags.lock != .none) {
843841 // TODO: integrate async I/O
844842 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
859857 error.LockedRegionLimitExceeded => unreachable,
860858 else => |e| return e,
861859 };
862 fl_flags &= ~@as(usize, posix.O.NONBLOCK);
860 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
863861 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
864862 error.FileBusy => unreachable,
865863 error.Locked => unreachable,
......@@ -870,7 +868,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
870868 };
871869 }
872870
873 return File{ .handle = fd };
871 return .{ .handle = fd };
874872}
875873
876874/// 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
918916 const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
919917 return self.createFileW(path_w.span(), flags);
920918 }
921 if (builtin.os.tag == .wasi and !builtin.link_libc) {
922 return self.createFileWasi(sub_path, flags);
919 if (builtin.os.tag == .wasi) {
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 };
923940 }
924941 const path_c = try posix.toPosixPath(sub_path);
925942 return self.createFileZ(&path_c, flags);
926943}
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
956945/// Same as `createFile` but the path parameter is null-terminated.
957946pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
958 if (builtin.os.tag == .windows) {
959 const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
960 return self.createFileW(path_w.span(), flags);
947 switch (builtin.os.tag) {
948 .windows => {
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 => {},
961956 }
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
963967 // Use the O locking flags if the os supports them to acquire the lock
964 // atomically.
965 const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");
966 // Note that the O.NONBLOCK flag is removed after the openat() call
967 // is successful.
968 const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking)
969 posix.O.NONBLOCK
970 else
971 0;
972 const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) {
973 .none => @as(u32, 0),
974 .shared => posix.O.SHLOCK | nonblocking_lock_flag,
975 .exclusive => posix.O.EXLOCK | nonblocking_lock_flag,
976 } else 0;
977
978 const O_LARGEFILE = if (@hasDecl(posix.O, "LARGEFILE")) posix.O.LARGEFILE else 0;
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);
968 // atomically. Note that the NONBLOCK flag is removed after the openat()
969 // call is successful.
970 const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
971 if (has_flock_open_flags) switch (flags.lock) {
972 .none => {},
973 .shared => {
974 os_flags.SHLOCK = true;
975 os_flags.NONBLOCK = flags.lock_nonblocking;
976 },
977 .exclusive => {
978 os_flags.EXLOCK = true;
979 os_flags.NONBLOCK = flags.lock_nonblocking;
980 },
981 };
982
983983 const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
984984 errdefer posix.close(fd);
985985
986 // WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block
987 // since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
988 if (builtin.target.os.tag != .wasi) {
989 if (!has_flock_open_flags and flags.lock != .none) {
990 // TODO: integrate async I/O
991 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
992 try posix.flock(fd, switch (flags.lock) {
993 .none => unreachable,
994 .shared => posix.LOCK.SH | lock_nonblocking,
995 .exclusive => posix.LOCK.EX | lock_nonblocking,
996 });
997 }
986 if (!has_flock_open_flags and flags.lock != .none) {
987 // TODO: integrate async I/O
988 const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
989 try posix.flock(fd, switch (flags.lock) {
990 .none => unreachable,
991 .shared => posix.LOCK.SH | lock_nonblocking,
992 .exclusive => posix.LOCK.EX | lock_nonblocking,
993 });
998994 }
999995
1000996 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
10061002 error.LockedRegionLimitExceeded => unreachable,
10071003 else => |e| return e,
10081004 };
1009 fl_flags &= ~@as(usize, posix.O.NONBLOCK);
1005 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
10101006 _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
10111007 error.FileBusy => unreachable,
10121008 error.Locked => unreachable,
......@@ -1017,7 +1013,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
10171013 };
10181014 }
10191015
1020 return File{ .handle = fd };
1016 return .{ .handle = fd };
10211017}
10221018
10231019/// 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 {
12101206 return self.realpathW(pathname_w.span(), out_buffer);
12111207 }
12121208
1213 const flags = if (builtin.os.tag == .linux)
1214 posix.O.PATH | posix.O.NONBLOCK | posix.O.CLOEXEC
1215 else
1216 posix.O.NONBLOCK | posix.O.CLOEXEC;
1209 const flags: posix.O = switch (builtin.os.tag) {
1210 .linux => .{
1211 .NONBLOCK = true,
1212 .CLOEXEC = true,
1213 .PATH = true,
1214 },
1215 else => .{
1216 .NONBLOCK = true,
1217 .CLOEXEC = true,
1218 },
1219 };
1220
12171221 const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) {
12181222 error.FileLocksNotSupported => unreachable,
12191223 else => |e| return e,
......@@ -1334,76 +1338,85 @@ pub const OpenDirOptions = struct {
13341338///
13351339/// Asserts that the path parameter has no null bytes.
13361340pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
1337 if (builtin.os.tag == .windows) {
1338 const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
1339 return self.openDirW(sub_path_w.span().ptr, args);
1340 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
1341 return self.openDirWasi(sub_path, args);
1342 } else {
1343 const sub_path_c = try posix.toPosixPath(sub_path);
1344 return self.openDirZ(&sub_path_c, args);
1345 }
1346}
1341 switch (builtin.os.tag) {
1342 .windows => {
1343 const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
1344 return self.openDirW(sub_path_w.span().ptr, args);
1345 },
1346 .wasi => {
1347 var base: std.os.wasi.rights_t = .{
1348 .FD_FILESTAT_GET = true,
1349 .FD_FDSTAT_SET_FLAGS = true,
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.
1349pub fn openDirWasi(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
1350 const w = std.os.wasi;
1351 var base: w.rights_t = w.RIGHT.FD_FILESTAT_GET | w.RIGHT.FD_FDSTAT_SET_FLAGS | w.RIGHT.FD_FILESTAT_SET_TIMES;
1352 if (args.access_sub_paths) {
1353 base |= w.RIGHT.FD_READDIR |
1354 w.RIGHT.PATH_CREATE_DIRECTORY |
1355 w.RIGHT.PATH_CREATE_FILE |
1356 w.RIGHT.PATH_LINK_SOURCE |
1357 w.RIGHT.PATH_LINK_TARGET |
1358 w.RIGHT.PATH_OPEN |
1359 w.RIGHT.PATH_READLINK |
1360 w.RIGHT.PATH_RENAME_SOURCE |
1361 w.RIGHT.PATH_RENAME_TARGET |
1362 w.RIGHT.PATH_FILESTAT_GET |
1363 w.RIGHT.PATH_FILESTAT_SET_SIZE |
1364 w.RIGHT.PATH_FILESTAT_SET_TIMES |
1365 w.RIGHT.PATH_SYMLINK |
1366 w.RIGHT.PATH_REMOVE_DIRECTORY |
1367 w.RIGHT.PATH_UNLINK_FILE;
1370 const result = posix.openatWasi(
1371 self.fd,
1372 sub_path,
1373 .{ .SYMLINK_FOLLOW = !args.no_follow },
1374 .{ .DIRECTORY = true },
1375 .{},
1376 base,
1377 base,
1378 );
1379 const fd = result catch |err| switch (err) {
1380 error.FileTooBig => unreachable, // can't happen for directories
1381 error.IsDir => unreachable, // we're setting DIRECTORY
1382 error.NoSpaceLeft => unreachable, // not setting CREAT
1383 error.PathAlreadyExists => unreachable, // not setting CREAT
1384 error.FileLocksNotSupported => unreachable, // locking folders is not supported
1385 error.WouldBlock => unreachable, // can't happen for directories
1386 error.FileBusy => unreachable, // can't happen for directories
1387 else => |e| return e,
1388 };
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 },
13681395 }
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 };
13931396}
13941397
13951398/// Same as `openDir` except the parameter is null-terminated.
13961399pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
1397 if (builtin.os.tag == .windows) {
1398 const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1399 return self.openDirW(sub_path_w.span().ptr, args);
1400 }
1401 const symlink_flags: u32 = if (args.no_follow) posix.O.NOFOLLOW else 0x0;
1402 if (!args.iterate) {
1403 const O_PATH = if (@hasDecl(posix.O, "PATH")) posix.O.PATH else 0;
1404 return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | O_PATH | symlink_flags);
1405 } else {
1406 return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | symlink_flags);
1400 switch (builtin.os.tag) {
1401 .windows => {
1402 const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
1403 return self.openDirW(sub_path_w.span().ptr, args);
1404 },
1405 .wasi => {
1406 return openDir(self, mem.sliceTo(sub_path_c, 0), args);
1407 },
1408 else => {
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 },
14071420 }
14081421}
14091422
......@@ -1422,13 +1435,14 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope
14221435 return dir;
14231436}
14241437
1425/// `flags` must contain `posix.O.DIRECTORY`.
1426fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir {
1438/// Asserts `flags` has `DIRECTORY` set.
1439fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError!Dir {
1440 assert(flags.DIRECTORY);
14271441 const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) {
14281442 error.FileTooBig => unreachable, // can't happen for directories
1429 error.IsDir => unreachable, // we're providing O.DIRECTORY
1430 error.NoSpaceLeft => unreachable, // not providing O.CREAT
1431 error.PathAlreadyExists => unreachable, // not providing O.CREAT
1443 error.IsDir => unreachable, // we're setting DIRECTORY
1444 error.NoSpaceLeft => unreachable, // not setting CREAT
1445 error.PathAlreadyExists => unreachable, // not setting CREAT
14321446 error.FileLocksNotSupported => unreachable, // locking folders is not supported
14331447 error.WouldBlock => unreachable, // can't happen for directories
14341448 error.FileBusy => unreachable, // can't happen for directories
......@@ -2446,8 +2460,8 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
24462460 return file.stat();
24472461 }
24482462 if (builtin.os.tag == .wasi and !builtin.link_libc) {
2449 const st = try posix.fstatatWasi(self.fd, sub_path, posix.wasi.LOOKUP_SYMLINK_FOLLOW);
2450 return Stat.fromSystem(st);
2463 const st = try posix.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
2464 return Stat.fromWasi(st);
24512465 }
24522466 const st = try posix.fstatat(self.fd, sub_path, 0);
24532467 return Stat.fromSystem(st);
......@@ -2507,3 +2521,4 @@ const posix = std.os;
25072521const mem = std.mem;
25082522const fs = std.fs;
25092523const Allocator = std.mem.Allocator;
2524const assert = std.debug.assert;
lib/std/fs/File.zig+95-47
......@@ -290,49 +290,59 @@ pub const Stat = struct {
290290 /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
291291 ctime: i128,
292292
293 pub fn fromSystem(st: posix.system.Stat) Stat {
293 pub fn fromSystem(st: posix.Stat) Stat {
294294 const atime = st.atime();
295295 const mtime = st.mtime();
296296 const ctime = st.ctime();
297 const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {
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{
297 return .{
327298 .inode = st.ino,
328 .size = @as(u64, @bitCast(st.size)),
299 .size = @bitCast(st.size),
329300 .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 },
331321 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
332322 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
333323 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
334324 };
335325 }
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 }
336346};
337347
338348pub const StatError = posix.FStatError;
......@@ -355,7 +365,7 @@ pub fn stat(self: File) StatError!Stat {
355365 .ACCESS_DENIED => return error.AccessDenied,
356366 else => return windows.unexpectedStatus(rc),
357367 }
358 return Stat{
368 return .{
359369 .inode = info.InternalInformation.IndexNumber,
360370 .size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
361371 .mode = 0,
......@@ -385,6 +395,11 @@ pub fn stat(self: File) StatError!Stat {
385395 };
386396 }
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
388403 const st = try posix.fstat(self.handle);
389404 return Stat.fromSystem(st);
390405}
......@@ -576,10 +591,11 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError!
576591/// Cross-platform representation of file metadata.
577592/// Platform-specific functionality is available through the `inner` field.
578593pub const Metadata = struct {
579 /// You may use the `inner` field to use platform-specific functionality
594 /// Exposes platform-specific functionality.
580595 inner: switch (builtin.os.tag) {
581596 .windows => MetadataWindows,
582597 .linux => MetadataLinux,
598 .wasi => MetadataWasi,
583599 else => MetadataUnix,
584600 },
585601
......@@ -628,12 +644,12 @@ pub const MetadataUnix = struct {
628644
629645 /// Returns the size of the file
630646 pub fn size(self: Self) u64 {
631 return @as(u64, @intCast(self.stat.size));
647 return @intCast(self.stat.size);
632648 }
633649
634650 /// Returns a `Permissions` struct, representing the permissions on the file
635651 pub fn permissions(self: Self) Permissions {
636 return Permissions{ .inner = PermissionsUnix{ .mode = self.stat.mode } };
652 return .{ .inner = .{ .mode = self.stat.mode } };
637653 }
638654
639655 /// Returns the `Kind` of the file
......@@ -756,6 +772,42 @@ pub const MetadataLinux = struct {
756772 }
757773};
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
759811pub const MetadataWindows = struct {
760812 attributes: windows.DWORD,
761813 reparse_tag: windows.DWORD,
......@@ -773,7 +825,7 @@ pub const MetadataWindows = struct {
773825
774826 /// Returns a `Permissions` struct, representing the permissions on the file
775827 pub fn permissions(self: Self) Permissions {
776 return Permissions{ .inner = PermissionsWindows{ .attributes = self.attributes } };
828 return .{ .inner = .{ .attributes = self.attributes } };
777829 }
778830
779831 /// Returns the `Kind` of the file.
......@@ -811,7 +863,7 @@ pub const MetadataWindows = struct {
811863pub const MetadataError = posix.FStatError;
812864
813865pub fn metadata(self: File) MetadataError!Metadata {
814 return Metadata{
866 return .{
815867 .inner = switch (builtin.os.tag) {
816868 .windows => blk: {
817869 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
......@@ -846,7 +898,7 @@ pub fn metadata(self: File) MetadataError!Metadata {
846898 break :reparse_blk 0;
847899 };
848900
849 break :blk MetadataWindows{
901 break :blk .{
850902 .attributes = info.BasicInformation.FileAttributes,
851903 .reparse_tag = reparse_tag,
852904 ._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
......@@ -887,16 +939,12 @@ pub fn metadata(self: File) MetadataError!Metadata {
887939 else => |err| return posix.unexpectedErrno(err),
888940 }
889941
890 break :blk MetadataLinux{
942 break :blk .{
891943 .statx = stx,
892944 };
893945 },
894 else => blk: {
895 const st = try posix.fstat(self.handle);
896 break :blk MetadataUnix{
897 .stat = st,
898 };
899 },
946 .wasi => .{ .stat = try posix.fstat_wasi(self.handle) },
947 else => .{ .stat = try posix.fstat(self.handle) },
900948 },
901949 };
902950}
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" {
242242 const sub_path_c = try os.toPosixPath("symlink");
243243 // the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
244244 // 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 };
246251 const fd = try os.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
247252 break :linux_symlink Dir{ .fd = fd };
248253 },
lib/std/os.zig+214-220
......@@ -24,7 +24,6 @@ const elf = std.elf;
2424const fs = std.fs;
2525const dl = @import("dynamic_library.zig");
2626const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
27const is_windows = builtin.os.tag == .windows;
2827
2928pub const darwin = std.c;
3029pub const dragonfly = std.c;
......@@ -62,16 +61,21 @@ test {
6261/// When not linking libc, it is the OS-specific system interface.
6362pub const system = if (@hasDecl(root, "os") and root.os != @This())
6463 root.os.system
65else if (builtin.link_libc or is_windows)
64else if (use_libc)
6665 std.c
6766else switch (builtin.os.tag) {
6867 .linux => linux,
6968 .plan9 => plan9,
70 .wasi => wasi,
7169 .uefi => uefi,
7270 else => struct {},
7371};
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
7579pub const AF = system.AF;
7680pub const AF_SUN = system.AF_SUN;
7781pub const ARCH = system.ARCH;
......@@ -87,10 +91,7 @@ pub const F = system.F;
8791pub const FD_CLOEXEC = system.FD_CLOEXEC;
8892pub const Flock = system.Flock;
8993pub const HOST_NAME_MAX = system.HOST_NAME_MAX;
90pub const HW = switch (builtin.os.tag) {
91 .openbsd => system.HW,
92 else => .{},
93};
94pub const HW = system.HW;
9495pub const IFNAMESIZE = system.IFNAMESIZE;
9596pub const IOV_MAX = system.IOV_MAX;
9697pub const IPPROTO = system.IPPROTO;
......@@ -105,19 +106,13 @@ pub const MFD = system.MFD;
105106pub const MMAP2_UNIT = system.MMAP2_UNIT;
106107pub const MSG = system.MSG;
107108pub const NAME_MAX = system.NAME_MAX;
108pub const O = switch (builtin.os.tag) {
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};
109pub const O = system.O;
114110pub const PATH_MAX = system.PATH_MAX;
115111pub const POLL = system.POLL;
116112pub const POSIX_FADV = system.POSIX_FADV;
117113pub const PR = system.PR;
118114pub const PROT = system.PROT;
119115pub const REG = system.REG;
120pub const RIGHT = system.RIGHT;
121116pub const RLIM = system.RLIM;
122117pub const RR = system.RR;
123118pub const S = system.S;
......@@ -151,12 +146,9 @@ pub const dl_phdr_info = system.dl_phdr_info;
151146pub const empty_sigset = system.empty_sigset;
152147pub const filled_sigset = system.filled_sigset;
153148pub const fd_t = system.fd_t;
154pub const fdflags_t = system.fdflags_t;
155pub const fdstat_t = system.fdstat_t;
156149pub const gid_t = system.gid_t;
157150pub const ifreq = system.ifreq;
158151pub const ino_t = system.ino_t;
159pub const lookupflags_t = system.lookupflags_t;
160152pub const mcontext_t = system.mcontext_t;
161153pub const mode_t = system.mode_t;
162154pub const msghdr = system.msghdr;
......@@ -164,14 +156,12 @@ pub const msghdr_const = system.msghdr_const;
164156pub const nfds_t = system.nfds_t;
165157pub const nlink_t = system.nlink_t;
166158pub const off_t = system.off_t;
167pub const oflags_t = system.oflags_t;
168159pub const pid_t = system.pid_t;
169160pub const pollfd = system.pollfd;
170161pub const port_t = system.port_t;
171162pub const port_event = system.port_event;
172163pub const port_notify = system.port_notify;
173164pub const file_obj = system.file_obj;
174pub const rights_t = system.rights_t;
175165pub const rlim_t = system.rlim_t;
176166pub const rlimit = system.rlimit;
177167pub const rlimit_resource = system.rlimit_resource;
......@@ -209,6 +199,12 @@ pub const iovec_const = extern struct {
209199 iov_len: usize,
210200};
211201
202pub const ACCMODE = enum(u2) {
203 RDONLY = 0,
204 WRONLY = 1,
205 RDWR = 2,
206};
207
212208pub const LOG = struct {
213209 /// system is unusable
214210 pub const EMERG = 0;
......@@ -460,13 +456,13 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
460456
461457 // Fallback to changing permissions using procfs:
462458 //
463 // 1. Open `path` as an `O.PATH` descriptor.
459 // 1. Open `path` as a `PATH` descriptor.
464460 // 2. Stat the fd and check if it isn't a symbolic link.
465461 // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`.
466462 // 4. Pass the procfs path to `chmod` with the `mode`.
467463 var pathfd: fd_t = undefined;
468464 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));
470466 switch (system.getErrno(rc)) {
471467 .SUCCESS => {
472468 pathfd = @as(fd_t, @intCast(rc));
......@@ -536,8 +532,10 @@ pub const FChownError = error{
536532/// any group of which the owner is a member. If the owner or group is
537533/// specified as `null`, the ID is not changed.
538534pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
539 if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
540 @compileError("Unsupported OS");
535 switch (builtin.os.tag) {
536 .windows, .wasi => @compileError("Unsupported OS"),
537 else => {},
538 }
541539
542540 while (true) {
543541 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 {
675673}
676674
677675fn 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);
679677 defer close(fd);
680678
681679 const st = try fstat(fd);
......@@ -1590,18 +1588,18 @@ pub const OpenError = error{
15901588 /// for 64-bit targets, as well as when opening directories.
15911589 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.
15941592 IsDir,
15951593
15961594 /// 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.
15981596 NoSpaceLeft,
15991597
16001598 /// 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.
16021600 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.
16051603 PathAlreadyExists,
16061604 DeviceBusy,
16071605
......@@ -1629,12 +1627,11 @@ pub const OpenError = error{
16291627
16301628/// Open and possibly create a file. Keeps trying if it gets interrupted.
16311629/// 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 {
16331631 if (builtin.os.tag == .windows) {
1634 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
1635 return openW(file_path_w.span(), flags, perm);
1632 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
16361633 } 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);
16381635 }
16391636 const file_path_c = try toPosixPath(file_path);
16401637 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 {
16421639
16431640/// Open and possibly create a file. Keeps trying if it gets interrupted.
16441641/// 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 {
16461643 if (builtin.os.tag == .windows) {
1647 const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
1648 return openW(file_path_w.span(), flags, perm);
1644 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
16491645 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
16501646 return open(mem.sliceTo(file_path, 0), flags, perm);
16511647 }
......@@ -1681,64 +1677,15 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
16811677 }
16821678}
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
17321680/// Open and possibly create a file. Keeps trying if it gets interrupted.
17331681/// `file_path` is relative to the open directory handle `dir_fd`.
17341682/// 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 {
17361684 if (builtin.os.tag == .windows) {
1737 const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path);
1738 return openatW(dir_fd, file_path_w.span(), flags, mode);
1685 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
17391686 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
17401687 // `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);
17421689 const fd = try openatWasi(
17431690 dir_fd,
17441691 file_path,
......@@ -1750,8 +1697,8 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
17501697 );
17511698 errdefer close(fd);
17521699
1753 if (flags & O.WRONLY != 0) {
1754 const info = try fstat(fd);
1700 if (flags.write) {
1701 const info = try fstat_wasi(fd);
17551702 if (info.filetype == .DIRECTORY)
17561703 return error.IsDir;
17571704 }
......@@ -1762,6 +1709,37 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
17621709 return openatZ(dir_fd, &file_path_c, flags, mode);
17631710}
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
17651743/// A struct to contain all lookup/rights flags accepted by `wasi.path_open`
17661744const WasiOpenOptions = struct {
17671745 oflags: wasi.oflags_t,
......@@ -1772,42 +1750,38 @@ const WasiOpenOptions = struct {
17721750};
17731751
17741752/// 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 {
17761754 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
17861756 // Next, calculate the read/write rights to request, depending on the
17871757 // provided POSIX access mode
1788 var rights: w.rights_t = 0;
1789 if (oflag & O.RDONLY != 0) {
1790 rights |= w.RIGHT.FD_READ | w.RIGHT.FD_READDIR;
1758 var rights: w.rights_t = .{};
1759 if (oflag.read) {
1760 rights.FD_READ = true;
1761 rights.FD_READDIR = true;
17911762 }
1792 if (oflag & O.WRONLY != 0) {
1793 rights |= w.RIGHT.FD_DATASYNC | w.RIGHT.FD_WRITE |
1794 w.RIGHT.FD_ALLOCATE | w.RIGHT.FD_FILESTAT_SET_SIZE;
1763 if (oflag.write) {
1764 rights.FD_DATASYNC = true;
1765 rights.FD_WRITE = true;
1766 rights.FD_ALLOCATE = true;
1767 rights.FD_FILESTAT_SET_SIZE = true;
17951768 }
17961769
1797 // Request all other rights unconditionally
1798 rights |= ~(w.RIGHT.FD_DATASYNC | w.RIGHT.FD_READ |
1799 w.RIGHT.FD_WRITE | w.RIGHT.FD_ALLOCATE |
1800 w.RIGHT.FD_READDIR | w.RIGHT.FD_FILESTAT_SET_SIZE);
1801
1802 // But only take rights that we can actually inherit
1803 rights &= fsb_cur.fs_rights_inheriting;
1770 // https://github.com/ziglang/zig/issues/18882
1771 const flag_bits: u32 = @bitCast(oflag);
1772 const oflags_int: u16 = @as(u12, @truncate(flag_bits >> 12));
1773 const fs_flags_int: u16 = @as(u12, @truncate(flag_bits));
18041774
1805 return WasiOpenOptions{
1806 .oflags = @as(w.oflags_t, @truncate((oflag >> 12))) & 0xfff,
1807 .lookup_flags = if (oflag & O.NOFOLLOW == 0) w.LOOKUP_SYMLINK_FOLLOW else 0,
1775 return .{
1776 // https://github.com/ziglang/zig/issues/18882
1777 .oflags = @bitCast(oflags_int),
1778 .lookup_flags = .{
1779 .SYMLINK_FOLLOW = !oflag.NOFOLLOW,
1780 },
18081781 .fs_rights_base = rights,
1809 .fs_rights_inheriting = fsb_cur.fs_rights_inheriting,
1810 .fs_flags = @as(w.fdflags_t, @truncate(oflag & 0xfff)),
1782 .fs_rights_inheriting = rights,
1783 // https://github.com/ziglang/zig/issues/18882
1784 .fs_flags = @bitCast(fs_flags_int),
18111785 };
18121786}
18131787
......@@ -1815,11 +1789,11 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {
18151789pub fn openatWasi(
18161790 dir_fd: fd_t,
18171791 file_path: []const u8,
1818 lookup_flags: lookupflags_t,
1819 oflags: oflags_t,
1820 fdflags: fdflags_t,
1821 base: rights_t,
1822 inheriting: rights_t,
1792 lookup_flags: wasi.lookupflags_t,
1793 oflags: wasi.oflags_t,
1794 fdflags: wasi.fdflags_t,
1795 base: wasi.rights_t,
1796 inheriting: wasi.rights_t,
18231797) OpenError!fd_t {
18241798 while (true) {
18251799 var fd: fd_t = undefined;
......@@ -1829,6 +1803,7 @@ pub fn openatWasi(
18291803
18301804 .FAULT => unreachable,
18311805 .INVAL => unreachable,
1806 .BADF => unreachable,
18321807 .ACCES => return error.AccessDenied,
18331808 .FBIG => return error.FileTooBig,
18341809 .OVERFLOW => return error.FileTooBig,
......@@ -1854,10 +1829,9 @@ pub fn openatWasi(
18541829/// Open and possibly create a file. Keeps trying if it gets interrupted.
18551830/// `file_path` is relative to the open directory handle `dir_fd`.
18561831/// 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 {
18581833 if (builtin.os.tag == .windows) {
1859 const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path);
1860 return openatW(dir_fd, file_path_w.span(), flags, mode);
1834 @compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
18611835 } else if (builtin.os.tag == .wasi and !builtin.link_libc) {
18621836 return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);
18631837 }
......@@ -1897,21 +1871,6 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
18971871 }
18981872}
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
19151874pub fn dup(old_fd: fd_t) !fd_t {
19161875 const rc = system.dup(old_fd);
19171876 return switch (errno(rc)) {
......@@ -2403,42 +2362,43 @@ pub fn linkat(
24032362 if (builtin.os.tag == .wasi and !builtin.link_libc) {
24042363 const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };
24052364 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 }
24072396 }
24082397 const old = try toPosixPath(oldpath);
24092398 const new = try toPosixPath(newpath);
24102399 return try linkatZ(olddir, &old, newdir, &new, flags);
24112400}
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
24422402pub const UnlinkError = error{
24432403 FileNotFound,
24442404
......@@ -3404,20 +3364,16 @@ pub fn isatty(handle: fd_t) bool {
34043364 return system.isatty(handle) != 0;
34053365 }
34063366 if (builtin.os.tag == .wasi) {
3407 var statbuf: fdstat_t = undefined;
3408 const err = system.fd_fdstat_get(handle, &statbuf);
3409 if (err != .SUCCESS) {
3410 // errno = err;
3367 var statbuf: wasi.fdstat_t = undefined;
3368 const err = wasi.fd_fdstat_get(handle, &statbuf);
3369 if (err != .SUCCESS)
34113370 return false;
3412 }
34133371
34143372 // A tty is a character device that we can't seek or tell on.
3415 if (statbuf.fs_filetype != .CHARACTER_DEVICE or
3416 (statbuf.fs_rights_base & (RIGHT.FD_SEEK | RIGHT.FD_TELL)) != 0)
3417 {
3418 // errno = ENOTTY;
3373 if (statbuf.fs_filetype != .CHARACTER_DEVICE)
3374 return false;
3375 if (statbuf.fs_rights_base.FD_SEEK or statbuf.fs_rights_base.FD_TELL)
34193376 return false;
3420 }
34213377
34223378 return true;
34233379 }
......@@ -3838,11 +3794,11 @@ pub fn accept(
38383794 /// will return a value greater than was supplied to the call.
38393795 addr_size: ?*socklen_t,
38403796 /// 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`)
38423798 /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
38433799 /// the same result.
38443800 /// * `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.
38463802 flags: u32,
38473803) AcceptError!socket_t {
38483804 const have_accept4 = comptime !(builtin.target.isDarwin() or builtin.os.tag == .windows);
......@@ -4278,16 +4234,7 @@ pub const FStatError = error{
42784234/// Return information about a file descriptor.
42794235pub fn fstat(fd: fd_t) FStatError!Stat {
42804236 if (builtin.os.tag == .wasi and !builtin.link_libc) {
4281 var stat: wasi.filestat_t = undefined;
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 }
4237 return Stat.fromFilestat(try fstat_wasi(fd));
42914238 }
42924239 if (builtin.os.tag == .windows) {
42934240 @compileError("fstat is not yet implemented on Windows");
......@@ -4306,15 +4253,30 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
43064253 }
43074254}
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
43094269pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLinkLoop };
43104270
43114271/// Similar to `fstat`, but returns stat of a resource pointed to by `pathname`
43124272/// which is relative to `dirfd` handle.
4313/// See also `fstatatZ` and `fstatatWasi`.
4273/// See also `fstatatZ` and `fstatat_wasi`.
43144274pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
43154275 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;
4317 return fstatatWasi(dirfd, pathname, wasi_flags);
4276 const filestat = try fstatat_wasi(dirfd, pathname, .{
4277 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
4278 });
4279 return Stat.fromFilestat(filestat);
43184280 } else if (builtin.os.tag == .windows) {
43194281 @compileError("fstatat is not yet implemented on Windows");
43204282 } else {
......@@ -4325,10 +4287,10 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat
43254287
43264288/// WASI-only. Same as `fstatat` but targeting WASI.
43274289/// 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 {
43294291 var stat: wasi.filestat_t = undefined;
43304292 switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) {
4331 .SUCCESS => return Stat.fromFilestat(stat),
4293 .SUCCESS => return stat,
43324294 .INVAL => unreachable,
43334295 .BADF => unreachable, // Always a race condition.
43344296 .NOMEM => return error.SystemResources,
......@@ -4346,7 +4308,10 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
43464308/// See also `fstatat`.
43474309pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
43484310 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);
43504315 }
43514316
43524317 const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
......@@ -4627,7 +4592,7 @@ pub const MMapError = error{
46274592
46284593 /// A file descriptor refers to a non-regular file. Or a file mapping was requested,
46294594 /// 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.
46314596 /// Or `PROT_WRITE` is set, but the file is append-only.
46324597 AccessDenied,
46334598
......@@ -4795,10 +4760,12 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
47954760 const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
47964761 return faccessatW(dirfd, path_w.span().ptr, mode, flags);
47974762 } 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: {
4801 break :blk fstatat(dirfd, path, flags);
4765 const st = blk: {
4766 break :blk fstatat_wasi(dirfd, path, .{
4767 .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
4768 });
48024769 } catch |err| switch (err) {
48034770 error.AccessDenied => return error.PermissionDenied,
48044771 else => |e| return e,
......@@ -4810,19 +4777,23 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
48104777 return error.PermissionDenied;
48114778 }
48124779
4813 var rights: wasi.rights_t = 0;
4780 var rights: wasi.rights_t = .{};
48144781 if (mode & R_OK != 0) {
4815 rights |= if (file.filetype == .DIRECTORY)
4816 wasi.RIGHT.FD_READDIR
4817 else
4818 wasi.RIGHT.FD_READ;
4782 if (st.filetype == .DIRECTORY) {
4783 rights.FD_READDIR = true;
4784 } else {
4785 rights.FD_READ = true;
4786 }
48194787 }
48204788 if (mode & W_OK != 0) {
4821 rights |= wasi.RIGHT.FD_WRITE;
4789 rights.FD_WRITE = true;
48224790 }
48234791 // 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) {
48264797 return error.PermissionDenied;
48274798 }
48284799 }
......@@ -4915,7 +4886,7 @@ pub fn pipe() PipeError![2]fd_t {
49154886 }
49164887}
49174888
4918pub fn pipe2(flags: u32) PipeError![2]fd_t {
4889pub fn pipe2(flags: O) PipeError![2]fd_t {
49194890 if (@hasDecl(system, "pipe2")) {
49204891 var fds: [2]fd_t = undefined;
49214892 switch (errno(system.pipe2(&fds, flags))) {
......@@ -4934,12 +4905,13 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
49344905 close(fds[1]);
49354906 }
49364907
4937 if (flags == 0)
4908 // https://github.com/ziglang/zig/issues/18882
4909 if (@as(u32, @bitCast(flags)) == 0)
49384910 return fds;
49394911
4940 // O.CLOEXEC is special, it's a file descriptor flag and must be set using
4912 // CLOEXEC is special, it's a file descriptor flag and must be set using
49414913 // F.SETFD.
4942 if (flags & O.CLOEXEC != 0) {
4914 if (flags.CLOEXEC) {
49434915 for (fds) |fd| {
49444916 switch (errno(system.fcntl(fd, F.SETFD, @as(u32, FD_CLOEXEC)))) {
49454917 .SUCCESS => {},
......@@ -4950,7 +4922,11 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
49504922 }
49514923 }
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 };
49544930 // Set every other flag affecting the file status using F.SETFL.
49554931 if (new_flags != 0) {
49564932 for (fds) |fd| {
......@@ -5289,7 +5265,7 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
52895265 error.LockedRegionLimitExceeded => unreachable,
52905266 else => |e| return e,
52915267 };
5292 fl_flags |= O.NONBLOCK;
5268 fl_flags |= 1 << @bitOffsetOf(O, "NONBLOCK");
52935269 _ = fcntl(sock, F.SETFL, fl_flags) catch |err| switch (err) {
52945270 error.FileBusy => unreachable,
52955271 error.Locked => unreachable,
......@@ -5389,7 +5365,17 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
53895365 return realpath(mem.sliceTo(pathname, 0), out_buffer);
53905366 }
53915367 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 };
53935379 const fd = openZ(pathname, flags, 0) catch |err| switch (err) {
53945380 error.FileLocksNotSupported => unreachable,
53955381 error.WouldBlock => unreachable,
......@@ -5893,7 +5879,10 @@ pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {
58935879 // this here, but we should really handle it somehow.
58945880 const atim = times[0].toTimestamp();
58955881 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 })) {
58975886 .SUCCESS => return,
58985887 .ACCES => return error.AccessDenied,
58995888 .PERM => return error.PermissionDenied,
......@@ -6390,7 +6379,7 @@ pub fn sendfile(
63906379 // * Descriptor is not valid or locked
63916380 // * an mmap(2)-like operation is not available for in_fd
63926381 // * count is negative
6393 // * out_fd has the O.APPEND flag set
6382 // * out_fd has the APPEND flag set
63946383 // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write
63956384 // manually, the same as ENOSYS.
63966385 break :sf;
......@@ -6588,7 +6577,7 @@ pub const CopyFileRangeError = error{
65886577 FileTooBig,
65896578 InputOutput,
65906579 /// `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`.
65926581 FilesOpenedWithWrongFlags,
65936582 IsDir,
65946583 OutOfMemory,
......@@ -7425,7 +7414,7 @@ pub const TimerFdCreateError = error{
74257414pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
74267415pub 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 {
74297418 const rc = linux.timerfd_create(clokid, flags);
74307419 return switch (errno(rc)) {
74317420 .SUCCESS => @as(fd_t, @intCast(rc)),
......@@ -7439,7 +7428,12 @@ pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {
74397428 };
74407429}
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 {
74437437 const rc = linux.timerfd_settime(fd, flags, new_value, old_value);
74447438 return switch (errno(rc)) {
74457439 .SUCCESS => {},
lib/std/os/emscripten.zig-41
......@@ -127,20 +127,6 @@ pub const AF = struct {
127127 pub const MAX = PF.MAX;
128128};
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
144130pub const CLOCK = struct {
145131 pub const REALTIME = 0;
146132 pub const MONOTONIC = 1;
......@@ -479,33 +465,6 @@ pub const MSG = struct {
479465 pub const CMSG_CLOEXEC = 0x40000000;
480466};
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
509468pub const POLL = struct {
510469 pub const IN = 0x001;
511470 pub const PRI = 0x002;
lib/std/os/linux.zig+206-57
......@@ -20,6 +20,7 @@ const is_ppc64 = native_arch.isPPC64();
2020const is_sparc = native_arch.isSPARC();
2121const iovec = std.os.iovec;
2222const iovec_const = std.os.iovec_const;
23const ACCMODE = std.os.ACCMODE;
2324
2425test {
2526 if (builtin.os.tag == .linux) {
......@@ -241,12 +242,145 @@ pub const MAP = switch (native_arch) {
241242 else => @compileError("missing std.os.linux.MAP constants for this architecture"),
242243};
243244
244pub const O = struct {
245 pub usingnamespace arch_bits.O;
246
247 pub const RDONLY = 0o0;
248 pub const WRONLY = 0o1;
249 pub const RDWR = 0o2;
245pub const O = switch (native_arch) {
246 .x86_64 => packed struct(u32) {
247 ACCMODE: ACCMODE = .RDONLY,
248 _2: u4 = 0,
249 CREAT: bool = false,
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"),
250384};
251385
252386pub usingnamespace @import("linux/io_uring.zig");
......@@ -620,20 +754,20 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {
620754 return syscall2(.umount2, @intFromPtr(special), flags);
621755}
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 {
624758 if (@hasField(SYS, "mmap2")) {
625759 // Make sure the offset is also specified in multiples of page size
626760 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
629763 return syscall6(
630764 .mmap2,
631765 @intFromPtr(address),
632766 length,
633767 prot,
634 flags,
635 @as(usize, @bitCast(@as(isize, fd))),
636 @as(usize, @truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT)),
768 @as(u32, @bitCast(flags)),
769 @bitCast(@as(isize, fd)),
770 @truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT),
637771 );
638772 } else {
639773 return syscall6(
......@@ -641,8 +775,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
641775 @intFromPtr(address),
642776 length,
643777 prot,
644 flags,
645 @as(usize, @bitCast(@as(isize, fd))),
778 @as(u32, @bitCast(flags)),
779 @bitCast(@as(isize, fd)),
646780 @as(u64, @bitCast(offset)),
647781 );
648782 }
......@@ -840,12 +974,12 @@ pub fn pipe(fd: *[2]i32) usize {
840974 }
841975}
842976
843pub fn pipe2(fd: *[2]i32, flags: u32) usize {
844 return syscall2(.pipe2, @intFromPtr(fd), flags);
977pub fn pipe2(fd: *[2]i32, flags: O) usize {
978 return syscall2(.pipe2, @intFromPtr(fd), @as(u32, @bitCast(flags)));
845979}
846980
847981pub 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);
849983}
850984
851985pub 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
9581092 );
9591093}
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 {
9621096 if (@hasField(SYS, "open")) {
963 return syscall3(.open, @intFromPtr(path), flags, perm);
1097 return syscall3(.open, @intFromPtr(path), @as(u32, @bitCast(flags)), perm);
9641098 } else {
9651099 return syscall4(
9661100 .openat,
967 @as(usize, @bitCast(@as(isize, AT.FDCWD))),
1101 @bitCast(@as(isize, AT.FDCWD)),
9681102 @intFromPtr(path),
969 flags,
1103 @as(u32, @bitCast(flags)),
9701104 perm,
9711105 );
9721106 }
......@@ -976,9 +1110,9 @@ pub fn create(path: [*:0]const u8, perm: mode_t) usize {
9761110 return syscall2(.creat, @intFromPtr(path), perm);
9771111}
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 {
9801114 // 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);
9821116}
9831117
9841118/// See also `clone` (from the arch-specific include)
......@@ -1800,8 +1934,8 @@ pub fn eventfd(count: u32, flags: u32) usize {
18001934 return syscall2(.eventfd2, count, flags);
18011935}
18021936
1803pub fn timerfd_create(clockid: i32, flags: u32) usize {
1804 return syscall2(.timerfd_create, @as(usize, @bitCast(@as(isize, clockid))), flags);
1937pub fn timerfd_create(clockid: i32, flags: TFD) usize {
1938 return syscall2(.timerfd_create, @bitCast(@as(isize, clockid)), @as(u32, @bitCast(flags)));
18051939}
18061940
18071941pub const itimerspec = extern struct {
......@@ -1810,11 +1944,11 @@ pub const itimerspec = extern struct {
18101944};
18111945
18121946pub 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));
18141948}
18151949
1816pub fn timerfd_settime(fd: i32, flags: u32, 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));
1950pub fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
1951 return syscall4(.timerfd_settime, @bitCast(@as(isize, fd)), @as(u32, @bitCast(flags)), @intFromPtr(new_value), @intFromPtr(old_value));
18181952}
18191953
18201954// Flags for the 'setitimer' system call
......@@ -2478,19 +2612,10 @@ pub const SIG = if (is_mips) struct {
24782612pub const kernel_rwf = u32;
24792613
24802614pub const RWF = struct {
2481 /// high priority request, poll if possible
24822615 pub const HIPRI: kernel_rwf = 0x00000001;
2483
2484 /// per-IO O.DSYNC
24852616 pub const DSYNC: kernel_rwf = 0x00000002;
2486
2487 /// per-IO O.SYNC
24882617 pub const SYNC: kernel_rwf = 0x00000004;
2489
2490 /// per-IO, return -EAGAIN if operation would block
24912618 pub const NOWAIT: kernel_rwf = 0x00000008;
2492
2493 /// per-IO O.APPEND
24942619 pub const APPEND: kernel_rwf = 0x00000010;
24952620};
24962621
......@@ -3257,7 +3382,7 @@ pub const T = struct {
32573382};
32583383
32593384pub const EPOLL = struct {
3260 pub const CLOEXEC = O.CLOEXEC;
3385 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
32613386
32623387 pub const CTL_ADD = 1;
32633388 pub const CTL_DEL = 2;
......@@ -3338,8 +3463,8 @@ pub const CLONE = struct {
33383463
33393464pub const EFD = struct {
33403465 pub const SEMAPHORE = 1;
3341 pub const CLOEXEC = O.CLOEXEC;
3342 pub const NONBLOCK = O.NONBLOCK;
3466 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3467 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
33433468};
33443469
33453470pub const MS = struct {
......@@ -3388,8 +3513,8 @@ pub const MNT = struct {
33883513pub const UMOUNT_NOFOLLOW = 8;
33893514
33903515pub const IN = struct {
3391 pub const CLOEXEC = O.CLOEXEC;
3392 pub const NONBLOCK = O.NONBLOCK;
3516 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3517 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
33933518
33943519 pub const ACCESS = 0x00000001;
33953520 pub const MODIFY = 0x00000002;
......@@ -3534,12 +3659,40 @@ pub const UTIME = struct {
35343659 pub const OMIT = 0x3ffffffe;
35353660};
35363661
3537pub const TFD = struct {
3538 pub const NONBLOCK = O.NONBLOCK;
3539 pub const CLOEXEC = O.CLOEXEC;
3662const TFD_TIMER = packed struct(u32) {
3663 ABSTIME: bool = false,
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;
3542 pub const TIMER_CANCEL_ON_SET = (1 << 1);
3694 pub const TIMER = TFD_TIMER;
3695 },
35433696};
35443697
35453698pub const winsize = extern struct {
......@@ -3603,8 +3756,8 @@ pub const empty_sigset = [_]u32{0} ** sigset_len;
36033756pub const filled_sigset = [_]u32{(1 << (31 & (usize_bits - 1))) - 1} ++ [_]u32{0} ** (sigset_len - 1);
36043757
36053758pub const SFD = struct {
3606 pub const CLOEXEC = O.CLOEXEC;
3607 pub const NONBLOCK = O.NONBLOCK;
3759 pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
3760 pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
36083761};
36093762
36103763pub const signalfd_siginfo = extern struct {
......@@ -3865,15 +4018,11 @@ pub const inotify_event = extern struct {
38654018};
38664019
38674020pub const dirent64 = extern struct {
3868 d_ino: u64,
3869 d_off: u64,
3870 d_reclen: u16,
3871 d_type: u8,
3872 d_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 }
4021 ino: u64,
4022 off: u64,
4023 reclen: u16,
4024 type: u8,
4025 name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
38774026};
38784027
38794028pub 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 {
141141
142142pub 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
167144pub const F = struct {
168145 pub const DUPFD = 0;
169146 pub const GETFD = 1;
lib/std/os/linux/arm64.zig-23
......@@ -123,29 +123,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
123123 }
124124}
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
149126pub const F = struct {
150127 pub const DUPFD = 0;
151128 pub const GETFD = 1;
lib/std/os/linux/io_uring.zig+13-13
......@@ -760,7 +760,7 @@ pub const IO_Uring = struct {
760760 user_data: u64,
761761 fd: os.fd_t,
762762 path: [*:0]const u8,
763 flags: u32,
763 flags: linux.O,
764764 mode: os.mode_t,
765765 ) !*linux.io_uring_sqe {
766766 const sqe = try self.get_sqe();
......@@ -785,7 +785,7 @@ pub const IO_Uring = struct {
785785 user_data: u64,
786786 fd: os.fd_t,
787787 path: [*:0]const u8,
788 flags: u32,
788 flags: linux.O,
789789 mode: os.mode_t,
790790 file_index: u32,
791791 ) !*linux.io_uring_sqe {
......@@ -1658,18 +1658,18 @@ pub fn io_uring_prep_openat(
16581658 sqe: *linux.io_uring_sqe,
16591659 fd: os.fd_t,
16601660 path: [*:0]const u8,
1661 flags: u32,
1661 flags: linux.O,
16621662 mode: os.mode_t,
16631663) void {
16641664 io_uring_prep_rw(.OPENAT, sqe, fd, @intFromPtr(path), mode, 0);
1665 sqe.rw_flags = flags;
1665 sqe.rw_flags = @bitCast(flags);
16661666}
16671667
16681668pub fn io_uring_prep_openat_direct(
16691669 sqe: *linux.io_uring_sqe,
16701670 fd: os.fd_t,
16711671 path: [*:0]const u8,
1672 flags: u32,
1672 flags: linux.O,
16731673 mode: os.mode_t,
16741674 file_index: u32,
16751675) void {
......@@ -2054,7 +2054,7 @@ test "readv" {
20542054 };
20552055 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);
20582058 defer os.close(fd);
20592059
20602060 // 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" {
23612361 break :p @intFromPtr(workaround);
23622362 } 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 };
23652365 const mode: os.mode_t = 0o666;
23662366 const sqe_openat = try ring.openat(0x33333333, tmp.dir.fd, path, flags, mode);
23672367 try testing.expectEqual(linux.io_uring_sqe{
......@@ -2372,7 +2372,7 @@ test "openat" {
23722372 .off = 0,
23732373 .addr = path_addr,
23742374 .len = mode,
2375 .rw_flags = flags,
2375 .rw_flags = @bitCast(flags),
23762376 .user_data = 0x33333333,
23772377 .buf_index = 0,
23782378 .personality = 0,
......@@ -2888,7 +2888,7 @@ test "register_files_update" {
28882888 };
28892889 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);
28922892 defer os.close(fd);
28932893
28942894 var registered_fds = [_]os.fd_t{0} ** 2;
......@@ -2906,7 +2906,7 @@ test "register_files_update" {
29062906 // Test IORING_REGISTER_FILES_UPDATE
29072907 // 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);
29102910 defer os.close(fd2);
29112911
29122912 registered_fds[fd_index] = fd2;
......@@ -3311,7 +3311,7 @@ test "provide_buffers: read" {
33113311 };
33123312 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);
33153315 defer os.close(fd);
33163316
33173317 const group_id = 1337;
......@@ -3443,7 +3443,7 @@ test "remove_buffers" {
34433443 };
34443444 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);
34473447 defer os.close(fd);
34483448
34493449 const group_id = 1337;
......@@ -4113,7 +4113,7 @@ test "openat_direct/close_direct" {
41134113 var tmp = std.testing.tmpDir(.{});
41144114 defer tmp.cleanup();
41154115 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 };
41174117 const mode: os.mode_t = 0o666;
41184118 const user_data: u64 = 0;
41194119
lib/std/os/linux/mips.zig-23
......@@ -213,29 +213,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
213213 );
214214}
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
239216pub const F = struct {
240217 pub const DUPFD = 0;
241218 pub const GETFD = 1;
lib/std/os/linux/mips64.zig-23
......@@ -198,29 +198,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
198198 );
199199}
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
224201pub const F = struct {
225202 pub const DUPFD = 0;
226203 pub const GETFD = 1;
lib/std/os/linux/powerpc.zig-23
......@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
142142 );
143143}
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
168145pub const F = struct {
169146 pub const DUPFD = 0;
170147 pub const GETFD = 1;
lib/std/os/linux/powerpc64.zig-23
......@@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
142142 );
143143}
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
168145pub const F = struct {
169146 pub const DUPFD = 0;
170147 pub const GETFD = 1;
lib/std/os/linux/riscv64.zig-23
......@@ -110,29 +110,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
110110 );
111111}
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
136113pub const F = struct {
137114 pub const DUPFD = 0;
138115 pub const GETFD = 1;
lib/std/os/linux/sparc64.zig-23
......@@ -195,29 +195,6 @@ pub fn restore_rt() callconv(.C) void {
195195 );
196196}
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
221198pub const F = struct {
222199 pub const DUPFD = 0;
223200 pub const GETFD = 1;
lib/std/os/linux/test.zig+2-2
......@@ -37,7 +37,7 @@ test "timer" {
3737 var err: linux.E = linux.getErrno(epoll_fd);
3838 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, .{});
4141 try expect(linux.getErrno(timer_fd) == .SUCCESS);
4242
4343 const time_interval = linux.timespec{
......@@ -50,7 +50,7 @@ test "timer" {
5050 .it_value = time_interval,
5151 };
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));
5454 try expect(err == .SUCCESS);
5555
5656 var event = linux.epoll_event{
lib/std/os/linux/x86.zig-23
......@@ -159,29 +159,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
159159 }
160160}
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
185162pub const F = struct {
186163 pub const DUPFD = 0;
187164 pub const GETFD = 1;
lib/std/os/linux/x86_64.zig-23
......@@ -131,29 +131,6 @@ pub const nlink_t = usize;
131131pub const blksize_t = isize;
132132pub 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
157134pub const F = struct {
158135 pub const DUPFD = 0;
159136 pub const GETFD = 1;
lib/std/os/plan9.zig+17-11
......@@ -242,17 +242,23 @@ pub fn close(fd: i32) usize {
242242 return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
243243}
244244pub const mode_t = i32;
245pub const O = struct {
246 pub const READ = 0; // open for read
247 pub const RDONLY = 0;
248 pub const WRITE = 1; // write
249 pub const WRONLY = 1;
250 pub const RDWR = 2; // read and write
251 pub const EXEC = 3; // execute, == read but check execute permission
252 pub const TRUNC = 16; // or'ed in (except for exec), truncate file first
253 pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec
254 pub const RCLOSE = 64; // or'ed in, remove on close
255 pub const EXCL = 0x1000; // or'ed in, exclusive create
245
246pub const AccessMode = enum(u2) {
247 RDONLY,
248 WRONLY,
249 RDWR,
250 EXEC,
251};
252
253pub const O = packed struct(u32) {
254 access: AccessMode,
255 _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,
256262};
257263
258264pub const ExecData = struct {
lib/std/os/test.zig+49-27
......@@ -87,6 +87,7 @@ test "chdir smoke test" {
8787
8888test "open smoke test" {
8989 if (native_os == .wasi) return error.SkipZigTest;
90 if (native_os == .windows) return error.SkipZigTest;
9091
9192 // TODO verify file attributes using `fstat`
9293
......@@ -109,21 +110,21 @@ test "open smoke test" {
109110
110111 // Create some file using `open`.
111112 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);
113114 os.close(fd);
114115
115116 // Try this again with the same flags. This op should fail with error.PathAlreadyExists.
116117 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.
120121 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);
122123 os.close(fd);
123124
124125 // Try opening as a directory which should fail.
125126 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
128129 // Create some directory
129130 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
......@@ -131,16 +132,17 @@ test "open smoke test" {
131132
132133 // Open dir using `open`
133134 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);
135136 os.close(fd);
136137
137138 // Try opening as file which should fail.
138139 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));
140141}
141142
142143test "openat smoke test" {
143144 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
145 if (native_os == .windows) return error.SkipZigTest;
144146
145147 // TODO verify file attributes using `fstatat`
146148
......@@ -151,28 +153,47 @@ test "openat smoke test" {
151153 const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
152154
153155 // 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);
155161 os.close(fd);
156162
157163 // 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));
159
160 // Try opening without `O.EXCL` flag.
161 fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT, mode);
164 try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
165 .ACCMODE = .RDWR,
166 .CREAT = true,
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);
162175 os.close(fd);
163176
164177 // 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
167183 // Create some directory
168184 try os.mkdirat(tmp.dir.fd, "some_dir", mode);
169185
170186 // 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);
172191 os.close(fd);
173192
174193 // 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));
176197}
177198
178199test "symlink with relative paths" {
......@@ -688,7 +709,7 @@ test "fcntl" {
688709 tmp.dir.deleteFile(test_out_file) catch {};
689710 }
690711
691 // Note: The test assumes createFile opens the file with O.CLOEXEC
712 // Note: The test assumes createFile opens the file with CLOEXEC
692713 {
693714 const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
694715 try expect((flags & os.FD_CLOEXEC) != 0);
......@@ -987,6 +1008,7 @@ test "POSIX file locking with fcntl" {
9871008
9881009test "rename smoke test" {
9891010 if (native_os == .wasi) return error.SkipZigTest;
1011 if (native_os == .windows) return error.SkipZigTest;
9901012
9911013 var tmp = tmpDir(.{});
9921014 defer tmp.cleanup();
......@@ -1007,7 +1029,7 @@ test "rename smoke test" {
10071029
10081030 // Create some file using `open`.
10091031 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);
10111033 os.close(fd);
10121034
10131035 // Rename the file
......@@ -1016,12 +1038,12 @@ test "rename smoke test" {
10161038
10171039 // Try opening renamed file
10181040 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);
10201042 os.close(fd);
10211043
10221044 // Try opening original file - should fail with error.FileNotFound
10231045 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
10261048 // Create some directory
10271049 file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
......@@ -1033,16 +1055,17 @@ test "rename smoke test" {
10331055
10341056 // Try opening renamed directory
10351057 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);
10371059 os.close(fd);
10381060
10391061 // Try opening original directory - should fail with error.FileNotFound
10401062 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));
10421064}
10431065
10441066test "access smoke test" {
10451067 if (native_os == .wasi) return error.SkipZigTest;
1068 if (native_os == .windows) return error.SkipZigTest;
10461069
10471070 var tmp = tmpDir(.{});
10481071 defer tmp.cleanup();
......@@ -1063,7 +1086,7 @@ test "access smoke test" {
10631086
10641087 // Create some file using `open`.
10651088 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);
10671090 os.close(fd);
10681091
10691092 // Try to access() the file
......@@ -1088,16 +1111,15 @@ test "access smoke test" {
10881111}
10891112
10901113test "timerfd" {
1091 if (native_os != .linux)
1092 return error.SkipZigTest;
1114 if (native_os != .linux) return error.SkipZigTest;
10931115
10941116 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 });
10961118 defer os.close(tfd);
10971119
10981120 // Fire event 10_000_000ns = 10ms after the os.timerfd_settime call.
10991121 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
11021124 var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
11031125 try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting
......@@ -1232,7 +1254,7 @@ test "fchmodat smoke test" {
12321254 const fd = try os.openat(
12331255 tmp.dir.fd,
12341256 "regfile",
1235 os.O.WRONLY | os.O.CREAT | os.O.EXCL | os.O.TRUNC,
1257 .{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
12361258 0o644,
12371259 );
12381260 os.close(fd);
lib/std/os/wasi.zig+121-268
......@@ -1,6 +1,7 @@
1// wasi_snapshot_preview1 spec available (in witx format) here:
2// * 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.witx
1//! wasi_snapshot_preview1 spec available (in witx format) here:
2//! * 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.witx
4//! Note that libc API does *not* go in this file. wasi libc API goes into std/c/wasi.zig instead.
45const builtin = @import("builtin");
56const std = @import("std");
67const assert = std.debug.assert;
......@@ -16,11 +17,6 @@ comptime {
1617 // assert(@alignOf(u64) == 8);
1718}
1819
19pub const F_OK = 0;
20pub const X_OK = 1;
21pub const W_OK = 2;
22pub const R_OK = 4;
23
2420pub const iovec_t = std.os.iovec;
2521pub 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
8278pub 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;
8379pub 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
16981// As defined in the wasi_snapshot_preview1 spec file:
17082// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
171pub const advice_t = u8;
172pub const ADVICE_NORMAL: advice_t = 0;
173pub const ADVICE_SEQUENTIAL: advice_t = 1;
174pub const ADVICE_RANDOM: advice_t = 2;
175pub const ADVICE_WILLNEED: advice_t = 3;
176pub const ADVICE_DONTNEED: advice_t = 4;
177pub const ADVICE_NOREUSE: advice_t = 5;
178
179pub const clockid_t = u32;
180pub const CLOCK = struct {
181 pub const REALTIME: clockid_t = 0;
182 pub const MONOTONIC: clockid_t = 1;
183 pub const PROCESS_CPUTIME_ID: clockid_t = 2;
184 pub const THREAD_CPUTIME_ID: clockid_t = 3;
83pub const advice_t = enum(u8) {
84 NORMAL = 0,
85 SEQUENTIAL = 1,
86 RANDOM = 2,
87 WILLNEED = 3,
88 DONTNEED = 4,
89 NOREUSE = 5,
90};
91
92pub const clockid_t = enum(u32) {
93 REALTIME = 0,
94 MONOTONIC = 1,
95 PROCESS_CPUTIME_ID = 2,
96 THREAD_CPUTIME_ID = 3,
18597};
18698
18799pub const device_t = u64;
......@@ -192,10 +104,10 @@ pub const DIRCOOKIE_START: dircookie_t = 0;
192104pub const dirnamlen_t = u32;
193105
194106pub const dirent_t = extern struct {
195 d_next: dircookie_t,
196 d_ino: inode_t,
197 d_namlen: dirnamlen_t,
198 d_type: filetype_t,
107 next: dircookie_t,
108 ino: inode_t,
109 namlen: dirnamlen_t,
110 type: filetype_t,
199111};
200112
201113pub const errno_t = enum(u16) {
......@@ -280,7 +192,6 @@ pub const errno_t = enum(u16) {
280192 NOTCAPABLE = 76,
281193 _,
282194};
283pub const E = errno_t;
284195
285196pub const event_t = extern struct {
286197 userdata: userdata_t,
......@@ -297,22 +208,23 @@ pub const eventfdreadwrite_t = extern struct {
297208pub const eventrwflags_t = u16;
298209pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
299210
300pub const eventtype_t = u8;
301pub const EVENTTYPE_CLOCK: eventtype_t = 0;
302pub const EVENTTYPE_FD_READ: eventtype_t = 1;
303pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
211pub const eventtype_t = enum(u8) {
212 CLOCK = 0,
213 FD_READ = 1,
214 FD_WRITE = 2,
215};
304216
305217pub const exitcode_t = u32;
306218
307219pub const fd_t = i32;
308220
309pub const fdflags_t = u16;
310pub const FDFLAG = struct {
311 pub const APPEND: fdflags_t = 0x0001;
312 pub const DSYNC: fdflags_t = 0x0002;
313 pub const NONBLOCK: fdflags_t = 0x0004;
314 pub const RSYNC: fdflags_t = 0x0008;
315 pub const SYNC: fdflags_t = 0x0010;
221pub const fdflags_t = packed struct(u16) {
222 APPEND: bool = false,
223 DSYNC: bool = false,
224 NONBLOCK: bool = false,
225 RSYNC: bool = false,
226 SYNC: bool = false,
227 _: u11 = 0,
316228};
317229
318230pub const fdstat_t = extern struct {
......@@ -335,21 +247,8 @@ pub const filestat_t = extern struct {
335247 atim: timestamp_t,
336248 mtim: timestamp_t,
337249 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 }
350250};
351251
352/// Also known as `FILETYPE`.
353252pub const filetype_t = enum(u8) {
354253 UNKNOWN,
355254 BLOCK_DEVICE,
......@@ -362,26 +261,29 @@ pub const filetype_t = enum(u8) {
362261 _,
363262};
364263
365pub const fstflags_t = u16;
366pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
367pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
368pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
369pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
264pub const fstflags_t = packed struct(u16) {
265 ATIM: bool = false,
266 ATIM_NOW: bool = false,
267 MTIM: bool = false,
268 MTIM_NOW: bool = false,
269 _: u12 = 0,
270};
370271
371272pub const inode_t = u64;
372pub const ino_t = inode_t;
373273
374274pub const linkcount_t = u64;
375275
376pub const lookupflags_t = u32;
377pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
276pub const lookupflags_t = packed struct(u32) {
277 SYMLINK_FOLLOW: bool = false,
278 _: u31 = 0,
279};
378280
379pub const oflags_t = u16;
380pub const O = struct {
381 pub const CREAT: oflags_t = 0x0001;
382 pub const DIRECTORY: oflags_t = 0x0002;
383 pub const EXCL: oflags_t = 0x0004;
384 pub const TRUNC: oflags_t = 0x0008;
281pub const oflags_t = packed struct(u16) {
282 CREAT: bool = false,
283 DIRECTORY: bool = false,
284 EXCL: bool = false,
285 TRUNC: bool = false,
286 _: u12 = 0,
385287};
386288
387289pub const preopentype_t = u8;
......@@ -410,110 +312,81 @@ pub const SOCK = struct {
410312 pub const RECV_DATA_TRUNCATED: roflags_t = 0x0001;
411313};
412314
413pub const rights_t = u64;
414pub const RIGHT = struct {
415 pub const FD_DATASYNC: rights_t = 0x0000000000000001;
416 pub const FD_READ: rights_t = 0x0000000000000002;
417 pub const FD_SEEK: rights_t = 0x0000000000000004;
418 pub const FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
419 pub const FD_SYNC: rights_t = 0x0000000000000010;
420 pub const FD_TELL: rights_t = 0x0000000000000020;
421 pub const FD_WRITE: rights_t = 0x0000000000000040;
422 pub const FD_ADVISE: rights_t = 0x0000000000000080;
423 pub const FD_ALLOCATE: rights_t = 0x0000000000000100;
424 pub const PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
425 pub const PATH_CREATE_FILE: rights_t = 0x0000000000000400;
426 pub const PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
427 pub const PATH_LINK_TARGET: rights_t = 0x0000000000001000;
428 pub const PATH_OPEN: rights_t = 0x0000000000002000;
429 pub const FD_READDIR: rights_t = 0x0000000000004000;
430 pub const PATH_READLINK: rights_t = 0x0000000000008000;
431 pub const PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
432 pub const PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
433 pub const PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
434 pub const PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
435 pub const PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
436 pub const FD_FILESTAT_GET: rights_t = 0x0000000000200000;
437 pub const FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
438 pub const FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
439 pub const PATH_SYMLINK: rights_t = 0x0000000001000000;
440 pub const PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
441 pub const PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
442 pub const POLL_FD_READWRITE: rights_t = 0x0000000008000000;
443 pub const SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
444 pub const SOCK_ACCEPT: rights_t = 0x0000000020000000;
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;
315pub const rights_t = packed struct(u64) {
316 FD_DATASYNC: bool = false,
317 FD_READ: bool = false,
318 FD_SEEK: bool = false,
319 FD_FDSTAT_SET_FLAGS: bool = false,
320 FD_SYNC: bool = false,
321 FD_TELL: bool = false,
322 FD_WRITE: bool = false,
323 FD_ADVISE: bool = false,
324 FD_ALLOCATE: bool = false,
325 PATH_CREATE_DIRECTORY: bool = false,
326 PATH_CREATE_FILE: bool = false,
327 PATH_LINK_SOURCE: bool = false,
328 PATH_LINK_TARGET: bool = false,
329 PATH_OPEN: bool = false,
330 FD_READDIR: bool = false,
331 PATH_READLINK: bool = false,
332 PATH_RENAME_SOURCE: bool = false,
333 PATH_RENAME_TARGET: bool = false,
334 PATH_FILESTAT_GET: bool = false,
335 PATH_FILESTAT_SET_SIZE: bool = false,
336 PATH_FILESTAT_SET_TIMES: bool = false,
337 FD_FILESTAT_GET: bool = false,
338 FD_FILESTAT_SET_SIZE: bool = false,
339 FD_FILESTAT_SET_TIMES: bool = false,
340 PATH_SYMLINK: bool = false,
341 PATH_REMOVE_DIRECTORY: bool = false,
342 PATH_UNLINK_FILE: bool = false,
343 POLL_FD_READWRITE: bool = false,
344 SOCK_SHUTDOWN: bool = false,
345 SOCK_ACCEPT: bool = false,
346 _: u34 = 0,
475347};
476348
477pub const sdflags_t = u8;
478pub const SHUT = struct {
479 pub const RD: sdflags_t = 0x01;
480 pub const WR: sdflags_t = 0x02;
349pub const sdflags_t = packed struct(u8) {
350 RD: bool = false,
351 WR: bool = false,
352 _: u6 = 0,
481353};
482354
483355pub const siflags_t = u16;
484356
485pub const signal_t = u8;
486pub const SIGNONE: signal_t = 0;
487pub const SIGHUP: signal_t = 1;
488pub const SIGINT: signal_t = 2;
489pub const SIGQUIT: signal_t = 3;
490pub const SIGILL: signal_t = 4;
491pub const SIGTRAP: signal_t = 5;
492pub const SIGABRT: signal_t = 6;
493pub const SIGBUS: signal_t = 7;
494pub const SIGFPE: signal_t = 8;
495pub const SIGKILL: signal_t = 9;
496pub const SIGUSR1: signal_t = 10;
497pub const SIGSEGV: signal_t = 11;
498pub const SIGUSR2: signal_t = 12;
499pub const SIGPIPE: signal_t = 13;
500pub const SIGALRM: signal_t = 14;
501pub const SIGTERM: signal_t = 15;
502pub const SIGCHLD: signal_t = 16;
503pub const SIGCONT: signal_t = 17;
504pub const SIGSTOP: signal_t = 18;
505pub const SIGTSTP: signal_t = 19;
506pub const SIGTTIN: signal_t = 20;
507pub const SIGTTOU: signal_t = 21;
508pub const SIGURG: signal_t = 22;
509pub const SIGXCPU: signal_t = 23;
510pub const SIGXFSZ: signal_t = 24;
511pub const SIGVTALRM: signal_t = 25;
512pub const SIGPROF: signal_t = 26;
513pub const SIGWINCH: signal_t = 27;
514pub const SIGPOLL: signal_t = 28;
515pub const SIGPWR: signal_t = 29;
516pub const SIGSYS: signal_t = 30;
357pub const signal_t = enum(u8) {
358 NONE = 0,
359 HUP = 1,
360 INT = 2,
361 QUIT = 3,
362 ILL = 4,
363 TRAP = 5,
364 ABRT = 6,
365 BUS = 7,
366 FPE = 8,
367 KILL = 9,
368 USR1 = 10,
369 SEGV = 11,
370 USR2 = 12,
371 PIPE = 13,
372 ALRM = 14,
373 TERM = 15,
374 CHLD = 16,
375 CONT = 17,
376 STOP = 18,
377 TSTP = 19,
378 TTIN = 20,
379 TTOU = 21,
380 URG = 22,
381 XCPU = 23,
382 XFSZ = 24,
383 VTALRM = 25,
384 PROF = 26,
385 WINCH = 27,
386 POLL = 28,
387 PWR = 29,
388 SYS = 30,
389};
517390
518391pub const subclockflags_t = u16;
519392pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
......@@ -545,29 +418,9 @@ pub const subscription_u_u_t = extern union {
545418 fd_write: subscription_fd_readwrite_t,
546419};
547420
421/// Nanoseconds.
548422pub const timestamp_t = u64;
549423
550424pub const userdata_t = u64;
551425
552/// Also known as `WHENCE`.
553426pub 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");
142142/// Networking.
143143pub 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.
146149pub const os = @import("os.zig");
147150
148151pub const once = @import("once.zig").once;
lib/std/time.zig+63-64
......@@ -19,19 +19,17 @@ pub fn sleep(nanoseconds: u64) void {
1919 if (builtin.os.tag == .wasi) {
2020 const w = std.os.wasi;
2121 const userdata: w.userdata_t = 0x0123_45678;
22 const clock = w.subscription_clock_t{
23 .id = w.CLOCK.MONOTONIC,
22 const clock: w.subscription_clock_t = .{
23 .id = .MONOTONIC,
2424 .timeout = nanoseconds,
2525 .precision = 0,
2626 .flags = 0,
2727 };
28 const in = w.subscription_t{
28 const in: w.subscription_t = .{
2929 .userdata = userdata,
30 .u = w.subscription_u_t{
31 .tag = w.EVENTTYPE_CLOCK,
32 .u = w.subscription_u_u_t{
33 .clock = clock,
34 },
30 .u = .{
31 .tag = .CLOCK,
32 .u = .{ .clock = clock },
3533 },
3634 };
3735
......@@ -92,35 +90,36 @@ pub fn microTimestamp() i64 {
9290/// before the epoch.
9391/// See `std.os.clock_gettime` for a POSIX timestamp.
9492pub fn nanoTimestamp() i128 {
95 if (builtin.os.tag == .windows) {
96 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
97 // which is 1601-01-01.
98 const epoch_adj = epoch.windows * (ns_per_s / 100);
99 var ft: os.windows.FILETIME = undefined;
100 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
101 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
102 return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
103 }
104
105 if (builtin.os.tag == .wasi and !builtin.link_libc) {
106 var ns: os.wasi.timestamp_t = undefined;
107 const err = os.wasi.clock_time_get(os.wasi.CLOCK.REALTIME, 1, &ns);
108 assert(err == .SUCCESS);
109 return ns;
110 }
111
112 if (builtin.os.tag == .uefi) {
113 var value: std.os.uefi.Time = undefined;
114 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
115 assert(status == .Success);
116 return value.toEpoch();
93 switch (builtin.os.tag) {
94 .windows => {
95 // FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
96 // which is 1601-01-01.
97 const epoch_adj = epoch.windows * (ns_per_s / 100);
98 var ft: os.windows.FILETIME = undefined;
99 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
100 const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
101 return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
102 },
103 .wasi => {
104 var ns: os.wasi.timestamp_t = undefined;
105 const err = os.wasi.clock_time_get(.REALTIME, 1, &ns);
106 assert(err == .SUCCESS);
107 return ns;
108 },
109 .uefi => {
110 var value: std.os.uefi.Time = undefined;
111 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
112 assert(status == .Success);
113 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 },
117122 }
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;
124123}
125124
126125test "timestamp" {
......@@ -177,43 +176,43 @@ pub const Instant = struct {
177176
178177 // true if we should use clock_gettime()
179178 const is_posix = switch (builtin.os.tag) {
180 .wasi => builtin.link_libc,
181 .windows, .uefi => false,
179 .windows, .uefi, .wasi => false,
182180 else => true,
183181 };
184182
185183 /// 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.
187186 /// Returns `error.Unsupported` when a suitable clock is not detected.
188187 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.
213188 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.
214207 .macos, .ios, .tvos, .watchos => os.CLOCK.UPTIME_RAW,
208 // On freebsd derivatives, use MONOTONIC_FAST as currently there's
209 // no precision tradeoff.
215210 .freebsd, .dragonfly => os.CLOCK.MONOTONIC_FAST,
211 // On linux, use BOOTTIME instead of MONOTONIC as it ticks while
212 // suspended.
216213 .linux => os.CLOCK.BOOTTIME,
214 // On other posix systems, MONOTONIC is generally the fastest and
215 // ticks while suspended.
217216 else => os.CLOCK.MONOTONIC,
218217 };
219218
......@@ -262,7 +261,7 @@ pub const Instant = struct {
262261 }
263262
264263 // WASI timestamps are directly in nanoseconds
265 if (builtin.os.tag == .wasi and !builtin.link_libc) {
264 if (builtin.os.tag == .wasi) {
266265 return self.timestamp - earlier.timestamp;
267266 }
268267
src/TypedValue.zig+16-8
......@@ -367,18 +367,26 @@ pub fn print(
367367 try writer.writeAll(".?");
368368 },
369369 .elem => |elem| {
370 try print(.{
371 .ty = Type.fromInterned(ip.typeOf(elem.base)),
372 .val = Value.fromInterned(elem.base),
373 }, writer, level - 1, mod);
370 if (level == 0) {
371 try writer.writeAll("(...)");
372 } else {
373 try print(.{
374 .ty = Type.fromInterned(ip.typeOf(elem.base)),
375 .val = Value.fromInterned(elem.base),
376 }, writer, level - 1, mod);
377 }
374378 try writer.print("[{}]", .{elem.index});
375379 },
376380 .field => |field| {
377381 const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base));
378 try print(.{
379 .ty = ptr_container_ty,
380 .val = Value.fromInterned(field.base),
381 }, writer, level - 1, mod);
382 if (level == 0) {
383 try writer.writeAll("(...)");
384 } else {
385 try print(.{
386 .ty = ptr_container_ty,
387 .val = Value.fromInterned(field.base),
388 }, writer, level - 1, mod);
389 }
382390
383391 const container_ty = ptr_container_ty.childType(mod);
384392 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" {
12481248 _ = Struct.bitcast(@as(u64, 0)).cannotReach();
12491249 }
12501250}
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}