authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-19 00:53:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-26 18:32:40-04:00
log67726e36b02d26343398ed8ede460622d706c539
treee25a71f83d194f3a13112295174ea3de155dcff1
parentdf7aa9a4f0360945db999f6a6190290eb91d6351
signature Commit is signed but in an unrecognized format.

extract posix functions from std/os.zig to std/os/posix.zig

See #2380

20 files changed, 2709 insertions(+), 2483 deletions(-)

CMakeLists.txt+1-1
......@@ -621,9 +621,9 @@ set(ZIG_STD_FILES
621621 "os/time.zig"
622622 "os/uefi.zig"
623623 "os/wasi.zig"
624 "os/wasi/core.zig"
625624 "os/windows.zig"
626625 "os/windows/advapi32.zig"
626 "os/windows/errno.zig"
627627 "os/windows/error.zig"
628628 "os/windows/kernel32.zig"
629629 "os/windows/ntdll.zig"
doc/langref.html.in+1-1
......@@ -195,7 +195,7 @@ const std = @import("std");
195195
196196pub fn main() !void {
197197 // If this program is run without stdout attached, exit with an error.
198 const stdout_file = try std.io.getStdOut();
198 const stdout_file = try std.os.File.stdout();
199199 // If this program encounters pipe failure when printing to stdout, exit
200200 // with an error.
201201 try stdout_file.write("Hello, world!\n");
example/hello_world/hello.zig+2-6
......@@ -1,9 +1,5 @@
11const std = @import("std");
22
3pub fn main() !void {
4 // If this program is run without stdout attached, exit with an error.
5 const stdout_file = try std.io.getStdOut();
6 // If this program encounters pipe failure when printing to stdout, exit
7 // with an error.
8 try stdout_file.write("Hello, world!\n");
3pub fn main() void {
4 std.debug.warn("Hello, world!\n");
95}
example/hello_world/hello_libc.zig+2-6
......@@ -2,13 +2,9 @@ const c = @cImport({
22 // See https://github.com/ziglang/zig/issues/515
33 @cDefine("_NO_CRT_STDIO_INLINE", "1");
44 @cInclude("stdio.h");
5 @cInclude("string.h");
65});
76
8const msg = c"Hello, world!\n";
9
10export fn main(argc: c_int, argv: **u8) c_int {
11 if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
12
7export fn main(argc: c_int, argv: [*]?[*]u8) c_int {
8 c.fprintf(c.stderr, c"Hello, world!\n");
139 return 0;
1410}
std/c.zig+16-6
......@@ -1,15 +1,24 @@
11const builtin = @import("builtin");
2const Os = builtin.Os;
2
3pub const is_the_target = builtin.link_libc;
34
45pub use switch (builtin.os) {
5 Os.linux => @import("c/linux.zig"),
6 Os.windows => @import("c/windows.zig"),
7 Os.macosx, Os.ios => @import("c/darwin.zig"),
8 Os.freebsd => @import("c/freebsd.zig"),
9 Os.netbsd => @import("c/netbsd.zig"),
6 .linux => @import("c/linux.zig"),
7 .windows => @import("c/windows.zig"),
8 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
9 .freebsd => @import("c/freebsd.zig"),
10 .netbsd => @import("c/netbsd.zig"),
1011 else => struct {},
1112};
1213
14pub fn getErrno(rc: var) u12 {
15 if (rc == -1) {
16 return @intCast(u12, _errno().*);
17 } else {
18 return 0;
19 }
20}
21
1322// TODO https://github.com/ziglang/zig/issues/265 on this whole file
1423
1524pub const FILE = @OpaqueType();
......@@ -56,6 +65,7 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
5665pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
5766pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
5867pub extern "c" fn rmdir(path: [*]const u8) c_int;
68pub extern "c" fn getenv(name: [*]const u8) ?[*]u8;
5969
6070pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
6171pub extern "c" fn malloc(usize) ?*c_void;
std/event/net.zig+1-8
......@@ -89,14 +89,7 @@ pub const Server = struct {
8989 },
9090 };
9191 } else |err| switch (err) {
92 error.ProcessFdQuotaExceeded => {
93 errdefer os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
94 suspend {
95 self.waiting_for_emfile_node = PromiseNode.init(@handle());
96 os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
97 }
98 continue;
99 },
92 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
10093 error.ConnectionAborted => continue,
10194
10295 error.FileDescriptorNotASocket => unreachable,
std/io.zig-17
......@@ -18,23 +18,6 @@ const testing = std.testing;
1818const is_posix = builtin.os != builtin.Os.windows;
1919const is_windows = builtin.os == builtin.Os.windows;
2020
21const GetStdIoErrs = os.WindowsGetStdHandleErrs;
22
23pub fn getStdErr() GetStdIoErrs!File {
24 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
25 return File.openHandle(handle);
26}
27
28pub fn getStdOut() GetStdIoErrs!File {
29 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
30 return File.openHandle(handle);
31}
32
33pub fn getStdIn() GetStdIoErrs!File {
34 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
35 return File.openHandle(handle);
36}
37
3821pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
3922pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream;
4023pub const COutStream = @import("io/c_out_stream.zig").COutStream;
std/os.zig+85-1810
......@@ -2,10 +2,6 @@ const std = @import("std.zig");
22const builtin = @import("builtin");
33const Os = builtin.Os;
44const is_windows = builtin.os == Os.windows;
5const is_posix = switch (builtin.os) {
6 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
7 else => false,
8};
95const os = @This();
106
117comptime {
......@@ -36,13 +32,13 @@ pub const zen = @import("os/zen.zig");
3632pub const uefi = @import("os/uefi.zig");
3733pub const wasi = @import("os/wasi.zig");
3834
39pub const posix = switch (builtin.os) {
40 Os.linux => linux,
41 Os.macosx, Os.ios => darwin,
42 Os.freebsd => freebsd,
43 Os.netbsd => netbsd,
44 Os.zen => zen,
45 Os.wasi => wasi,
35pub const system = if (builtin.link_libc) c else switch (builtin.os) {
36 .linux => linux,
37 .macosx, .ios, .watchos, .tvos => darwin,
38 .freebsd => freebsd,
39 .netbsd => netbsd,
40 .zen => zen,
41 .wasi => wasi,
4642 else => @compileError("Unsupported OS"),
4743};
4844
......@@ -58,13 +54,17 @@ pub const page_size = switch (builtin.arch) {
5854 else => 4 * 1024,
5955};
6056
57/// This represents the maximum size of a UTF-8 encoded file path.
58/// All file system operations which return a path are guaranteed to
59/// fit into a UTF-8 encoded array of this length.
60/// path being too long if it is this 0long
6161pub const MAX_PATH_BYTES = switch (builtin.os) {
62 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
62 .linux, .macosx, .ios, .freebsd, .netbsd => posix.PATH_MAX,
6363 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
6464 // If it would require 4 UTF-8 bytes, then there would be a surrogate
6565 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
6666 // +1 for the null byte at the end, which can be encoded in 1 byte.
67 Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
67 .windows => posix.PATH_MAX_WIDE * 3 + 1,
6868 else => @compileError("Unsupported OS"),
6969};
7070
......@@ -98,6 +98,22 @@ pub const FileHandle = if (is_windows) windows.HANDLE else i32;
9898pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
9999pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
100100
101pub const getRandomBytes = posix.getrandom;
102pub const abort = posix.abort;
103pub const exit = posix.exit;
104pub const symLink = posix.symlink;
105pub const symLinkC = posix.symlinkC;
106pub const symLinkW = posix.symlinkW;
107pub const deleteFile = posix.unlink;
108pub const deleteFileC = posix.unlinkC;
109pub const deleteFileW = posix.unlinkW;
110pub const rename = posix.rename;
111pub const renameC = posix.renameC;
112pub const renameW = posix.renameW;
113pub const changeCurDir = posix.chdir;
114pub const changeCurDirC = posix.chdirC;
115pub const changeCurDirW = posix.chdirW;
116
101117const debug = std.debug;
102118const assert = debug.assert;
103119const testing = std.testing;
......@@ -116,610 +132,6 @@ const ArrayList = std.ArrayList;
116132const Buffer = std.Buffer;
117133const math = std.math;
118134
119/// Fills `buf` with random bytes. If linking against libc, this calls the
120/// appropriate OS-specific library call. Otherwise it uses the zig standard
121/// library implementation.
122pub fn getRandomBytes(buf: []u8) !void {
123 switch (builtin.os) {
124 Os.linux => while (true) {
125 // TODO check libc version and potentially call c.getrandom.
126 // See #397
127 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
128 switch (errno) {
129 0 => return,
130 posix.EINVAL => unreachable,
131 posix.EFAULT => unreachable,
132 posix.EINTR => continue,
133 posix.ENOSYS => return getRandomBytesDevURandom(buf),
134 else => return unexpectedErrorPosix(errno),
135 }
136 },
137 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
138 Os.windows => {
139 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
140 // https://github.com/rust-lang-nursery/rand/issues/111
141 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
142 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
143 const err = windows.GetLastError();
144 return switch (err) {
145 else => unexpectedErrorWindows(err),
146 };
147 }
148 },
149 Os.wasi => {
150 const random_get_result = os.wasi.random_get(buf.ptr, buf.len);
151 if (random_get_result != os.wasi.ESUCCESS) {
152 return error.Unknown;
153 }
154 },
155 Os.zen => {
156 const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
157 var i: usize = 0;
158 while (i < buf.len) : (i += 1) {
159 if (i > randomness.len) return error.Unknown;
160 buf[i] = randomness[i];
161 }
162 },
163 else => @compileError("Unsupported OS"),
164 }
165}
166
167fn getRandomBytesDevURandom(buf: []u8) !void {
168 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
169 defer close(fd);
170
171 const stream = &File.openHandle(fd).inStream().stream;
172 stream.readNoEof(buf) catch |err| switch (err) {
173 error.EndOfStream => unreachable,
174 error.OperationAborted => unreachable,
175 error.BrokenPipe => unreachable,
176 error.Unexpected => return error.Unexpected,
177 error.InputOutput => return error.Unexpected,
178 error.SystemResources => return error.Unexpected,
179 error.IsDir => unreachable,
180 };
181}
182
183test "os.getRandomBytes" {
184 var buf_a: [50]u8 = undefined;
185 var buf_b: [50]u8 = undefined;
186 // Call Twice
187 try getRandomBytes(buf_a[0..]);
188 try getRandomBytes(buf_b[0..]);
189
190 // Check if random (not 100% conclusive)
191 testing.expect(!mem.eql(u8, buf_a, buf_b));
192}
193
194/// Raises a signal in the current kernel thread, ending its execution.
195/// If linking against libc, this calls the abort() libc function. Otherwise
196/// it uses the zig standard library implementation.
197pub fn abort() noreturn {
198 @setCold(true);
199 if (builtin.link_libc) {
200 c.abort();
201 }
202 switch (builtin.os) {
203 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
204 _ = posix.raise(posix.SIGABRT);
205 _ = posix.raise(posix.SIGKILL);
206 while (true) {}
207 },
208 Os.windows => {
209 if (builtin.mode == builtin.Mode.Debug) {
210 @breakpoint();
211 }
212 windows.ExitProcess(3);
213 },
214 Os.wasi => {
215 _ = wasi.proc_raise(wasi.SIGABRT);
216 // TODO: Is SIGKILL even necessary?
217 _ = wasi.proc_raise(wasi.SIGKILL);
218 while (true) {}
219 },
220 Os.uefi => {
221 // TODO there's gotta be a better thing to do here than loop forever
222 while (true) {}
223 },
224 else => @compileError("Unsupported OS"),
225 }
226}
227
228/// Exits the program cleanly with the specified status code.
229pub fn exit(status: u8) noreturn {
230 @setCold(true);
231 if (builtin.link_libc) {
232 c.exit(status);
233 }
234 switch (builtin.os) {
235 Os.linux => {
236 if (builtin.single_threaded) {
237 linux.exit(status);
238 } else {
239 linux.exit_group(status);
240 }
241 },
242 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
243 posix.exit(status);
244 },
245 Os.windows => {
246 windows.ExitProcess(status);
247 },
248 Os.wasi => {
249 wasi.proc_exit(status);
250 },
251 else => @compileError("Unsupported OS"),
252 }
253}
254
255/// When a file descriptor is closed on linux, it pops the first
256/// node from this queue and resumes it.
257/// Async functions which get the EMFILE error code can suspend,
258/// putting their coroutine handle into this list.
259/// TODO make this an atomic linked list
260pub var emfile_promise_queue = std.LinkedList(promise).init();
261
262/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
263pub fn close(handle: FileHandle) void {
264 if (is_windows) {
265 windows_util.windowsClose(handle);
266 } else {
267 while (true) {
268 const err = posix.getErrno(posix.close(handle));
269 switch (err) {
270 posix.EINTR => continue,
271 else => {
272 if (emfile_promise_queue.popFirst()) |p| resume p.data;
273 return;
274 },
275 }
276 }
277 }
278}
279
280pub const PosixReadError = error{
281 InputOutput,
282 SystemResources,
283 IsDir,
284 Unexpected,
285};
286
287/// Returns the number of bytes that were read, which can be less than
288/// buf.len. If 0 bytes were read, that means EOF.
289pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
290 // Linux can return EINVAL when read amount is > 0x7ffff000
291 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
292 const max_buf_len = 0x7ffff000;
293
294 var index: usize = 0;
295 while (index < buf.len) {
296 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
297 const rc = posix.read(fd, buf.ptr + index, want_to_read);
298 const err = posix.getErrno(rc);
299 switch (err) {
300 0 => {
301 index += rc;
302 if (rc == want_to_read) continue;
303 // Read returned less than buf.len.
304 return index;
305 },
306 posix.EINTR => continue,
307 posix.EINVAL => unreachable,
308 posix.EFAULT => unreachable,
309 posix.EAGAIN => unreachable,
310 posix.EBADF => unreachable, // always a race condition
311 posix.EIO => return error.InputOutput,
312 posix.EISDIR => return error.IsDir,
313 posix.ENOBUFS => return error.SystemResources,
314 posix.ENOMEM => return error.SystemResources,
315 else => return unexpectedErrorPosix(err),
316 }
317 }
318 return index;
319}
320
321/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
322pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
323 switch (builtin.os) {
324 builtin.Os.macosx => {
325 // Darwin does not have preadv but it does have pread.
326 var off: usize = 0;
327 var iov_i: usize = 0;
328 var inner_off: usize = 0;
329 while (true) {
330 const v = iov[iov_i];
331 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
332 const err = darwin.getErrno(rc);
333 switch (err) {
334 0 => {
335 off += rc;
336 inner_off += rc;
337 if (inner_off == v.iov_len) {
338 iov_i += 1;
339 inner_off = 0;
340 if (iov_i == count) {
341 return off;
342 }
343 }
344 if (rc == 0) return off; // EOF
345 continue;
346 },
347 posix.EINTR => continue,
348 posix.EINVAL => unreachable,
349 posix.EFAULT => unreachable,
350 posix.ESPIPE => unreachable, // fd is not seekable
351 posix.EAGAIN => unreachable, // this function is not for non blocking
352 posix.EBADF => unreachable, // always a race condition
353 posix.EIO => return error.InputOutput,
354 posix.EISDIR => return error.IsDir,
355 posix.ENOBUFS => return error.SystemResources,
356 posix.ENOMEM => return error.SystemResources,
357 else => return unexpectedErrorPosix(err),
358 }
359 }
360 },
361 builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
362 const rc = posix.preadv(fd, iov, count, offset);
363 const err = posix.getErrno(rc);
364 switch (err) {
365 0 => return rc,
366 posix.EINTR => continue,
367 posix.EINVAL => unreachable,
368 posix.EFAULT => unreachable,
369 posix.EAGAIN => unreachable, // don't call this function for non blocking
370 posix.EBADF => unreachable, // always a race condition
371 posix.EIO => return error.InputOutput,
372 posix.EISDIR => return error.IsDir,
373 posix.ENOBUFS => return error.SystemResources,
374 posix.ENOMEM => return error.SystemResources,
375 else => return unexpectedErrorPosix(err),
376 }
377 },
378 else => @compileError("Unsupported OS"),
379 }
380}
381
382pub const PosixWriteError = error{
383 DiskQuota,
384 FileTooBig,
385 InputOutput,
386 NoSpaceLeft,
387 AccessDenied,
388 BrokenPipe,
389
390 /// See https://github.com/ziglang/zig/issues/1396
391 Unexpected,
392};
393
394/// Calls POSIX write, and keeps trying if it gets interrupted.
395pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
396 // Linux can return EINVAL when write amount is > 0x7ffff000
397 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
398 const max_bytes_len = 0x7ffff000;
399
400 var index: usize = 0;
401 while (index < bytes.len) {
402 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
403 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
404 const write_err = posix.getErrno(rc);
405 switch (write_err) {
406 0 => {
407 index += rc;
408 continue;
409 },
410 posix.EINTR => continue,
411 posix.EINVAL => unreachable,
412 posix.EFAULT => unreachable,
413 posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
414 posix.EBADF => unreachable, // always a race condition
415 posix.EDESTADDRREQ => unreachable, // connect was never called
416 posix.EDQUOT => return PosixWriteError.DiskQuota,
417 posix.EFBIG => return PosixWriteError.FileTooBig,
418 posix.EIO => return PosixWriteError.InputOutput,
419 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
420 posix.EPERM => return PosixWriteError.AccessDenied,
421 posix.EPIPE => return PosixWriteError.BrokenPipe,
422 else => return unexpectedErrorPosix(write_err),
423 }
424 }
425}
426
427pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
428 switch (builtin.os) {
429 builtin.Os.macosx => {
430 // Darwin does not have pwritev but it does have pwrite.
431 var off: usize = 0;
432 var iov_i: usize = 0;
433 var inner_off: usize = 0;
434 while (true) {
435 const v = iov[iov_i];
436 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
437 const err = darwin.getErrno(rc);
438 switch (err) {
439 0 => {
440 off += rc;
441 inner_off += rc;
442 if (inner_off == v.iov_len) {
443 iov_i += 1;
444 inner_off = 0;
445 if (iov_i == count) {
446 return;
447 }
448 }
449 continue;
450 },
451 posix.EINTR => continue,
452 posix.ESPIPE => unreachable, // fd is not seekable
453 posix.EINVAL => unreachable,
454 posix.EFAULT => unreachable,
455 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
456 posix.EBADF => unreachable, // always a race condition
457 posix.EDESTADDRREQ => unreachable, // connect was never called
458 posix.EDQUOT => return PosixWriteError.DiskQuota,
459 posix.EFBIG => return PosixWriteError.FileTooBig,
460 posix.EIO => return PosixWriteError.InputOutput,
461 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
462 posix.EPERM => return PosixWriteError.AccessDenied,
463 posix.EPIPE => return PosixWriteError.BrokenPipe,
464 else => return unexpectedErrorPosix(err),
465 }
466 }
467 },
468 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
469 const rc = posix.pwritev(fd, iov, count, offset);
470 const err = posix.getErrno(rc);
471 switch (err) {
472 0 => return,
473 posix.EINTR => continue,
474 posix.EINVAL => unreachable,
475 posix.EFAULT => unreachable,
476 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
477 posix.EBADF => unreachable, // always a race condition
478 posix.EDESTADDRREQ => unreachable, // connect was never called
479 posix.EDQUOT => return PosixWriteError.DiskQuota,
480 posix.EFBIG => return PosixWriteError.FileTooBig,
481 posix.EIO => return PosixWriteError.InputOutput,
482 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
483 posix.EPERM => return PosixWriteError.AccessDenied,
484 posix.EPIPE => return PosixWriteError.BrokenPipe,
485 else => return unexpectedErrorPosix(err),
486 }
487 },
488 else => @compileError("Unsupported OS"),
489 }
490}
491
492pub const PosixOpenError = error{
493 AccessDenied,
494 FileTooBig,
495 IsDir,
496 SymLinkLoop,
497 ProcessFdQuotaExceeded,
498 NameTooLong,
499 SystemFdQuotaExceeded,
500 NoDevice,
501 FileNotFound,
502 SystemResources,
503 NoSpaceLeft,
504 NotDir,
505 PathAlreadyExists,
506 DeviceBusy,
507
508 /// See https://github.com/ziglang/zig/issues/1396
509 Unexpected,
510};
511
512/// ::file_path needs to be copied in memory to add a null terminating byte.
513/// Calls POSIX open, keeps trying if it gets interrupted, and translates
514/// the return value into zig errors.
515pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
516 const file_path_c = try toPosixPath(file_path);
517 return posixOpenC(&file_path_c, flags, perm);
518}
519
520// TODO https://github.com/ziglang/zig/issues/265
521pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
522 while (true) {
523 const result = posix.open(file_path, flags, perm);
524 const err = posix.getErrno(result);
525 if (err > 0) {
526 switch (err) {
527 posix.EINTR => continue,
528
529 posix.EFAULT => unreachable,
530 posix.EINVAL => unreachable,
531 posix.EACCES => return PosixOpenError.AccessDenied,
532 posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
533 posix.EISDIR => return PosixOpenError.IsDir,
534 posix.ELOOP => return PosixOpenError.SymLinkLoop,
535 posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
536 posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
537 posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
538 posix.ENODEV => return PosixOpenError.NoDevice,
539 posix.ENOENT => return PosixOpenError.FileNotFound,
540 posix.ENOMEM => return PosixOpenError.SystemResources,
541 posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
542 posix.ENOTDIR => return PosixOpenError.NotDir,
543 posix.EPERM => return PosixOpenError.AccessDenied,
544 posix.EEXIST => return PosixOpenError.PathAlreadyExists,
545 posix.EBUSY => return PosixOpenError.DeviceBusy,
546 else => return unexpectedErrorPosix(err),
547 }
548 }
549 return @intCast(i32, result);
550 }
551}
552
553/// Used to convert a slice to a null terminated slice on the stack.
554/// TODO well defined copy elision
555pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
556 var path_with_null: [posix.PATH_MAX]u8 = undefined;
557 if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
558 mem.copy(u8, path_with_null[0..], file_path);
559 path_with_null[file_path.len] = 0;
560 return path_with_null;
561}
562
563pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
564 while (true) {
565 const err = posix.getErrno(posix.dup2(old_fd, new_fd));
566 if (err > 0) {
567 return switch (err) {
568 posix.EBUSY, posix.EINTR => continue,
569 posix.EMFILE => error.ProcessFdQuotaExceeded,
570 posix.EINVAL => unreachable,
571 else => unexpectedErrorPosix(err),
572 };
573 }
574 return;
575 }
576}
577
578pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
579 const envp_count = env_map.count();
580 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
581 mem.set(?[*]u8, envp_buf, null);
582 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
583 {
584 var it = env_map.iterator();
585 var i: usize = 0;
586 while (it.next()) |pair| : (i += 1) {
587 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
588 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
589 env_buf[pair.key.len] = '=';
590 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
591 env_buf[env_buf.len - 1] = 0;
592
593 envp_buf[i] = env_buf.ptr;
594 }
595 assert(i == envp_count);
596 }
597 assert(envp_buf[envp_count] == null);
598 return envp_buf;
599}
600
601pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
602 for (envp_buf) |env| {
603 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
604 allocator.free(env_buf);
605 }
606 allocator.free(envp_buf);
607}
608
609/// This function must allocate memory to add a null terminating bytes on path and each arg.
610/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
611/// pointers after the args and after the environment variables.
612/// `argv[0]` is the executable path.
613/// This function also uses the PATH environment variable to get the full path to the executable.
614pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
615 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
616 mem.set(?[*]u8, argv_buf, null);
617 defer {
618 for (argv_buf) |arg| {
619 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
620 allocator.free(arg_buf);
621 }
622 allocator.free(argv_buf);
623 }
624 for (argv) |arg, i| {
625 const arg_buf = try allocator.alloc(u8, arg.len + 1);
626 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
627 arg_buf[arg.len] = 0;
628
629 argv_buf[i] = arg_buf.ptr;
630 }
631 argv_buf[argv.len] = null;
632
633 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
634 defer freeNullDelimitedEnvMap(allocator, envp_buf);
635
636 const exe_path = argv[0];
637 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
638 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
639 }
640
641 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
642 // PATH.len because it is >= the largest search_path
643 // +1 for the / to join the search path and exe_path
644 // +1 for the null terminating byte
645 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
646 defer allocator.free(path_buf);
647 var it = mem.tokenize(PATH, ":");
648 var seen_eacces = false;
649 var err: usize = undefined;
650 while (it.next()) |search_path| {
651 mem.copy(u8, path_buf, search_path);
652 path_buf[search_path.len] = '/';
653 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
654 path_buf[search_path.len + exe_path.len + 1] = 0;
655 err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
656 assert(err > 0);
657 if (err == posix.EACCES) {
658 seen_eacces = true;
659 } else if (err != posix.ENOENT) {
660 return posixExecveErrnoToErr(err);
661 }
662 }
663 if (seen_eacces) {
664 err = posix.EACCES;
665 }
666 return posixExecveErrnoToErr(err);
667}
668
669pub const PosixExecveError = error{
670 SystemResources,
671 AccessDenied,
672 InvalidExe,
673 FileSystem,
674 IsDir,
675 FileNotFound,
676 NotDir,
677 FileBusy,
678
679 /// See https://github.com/ziglang/zig/issues/1396
680 Unexpected,
681};
682
683fn posixExecveErrnoToErr(err: usize) PosixExecveError {
684 assert(err > 0);
685 switch (err) {
686 posix.EFAULT => unreachable,
687 posix.E2BIG => return error.SystemResources,
688 posix.EMFILE => return error.SystemResources,
689 posix.ENAMETOOLONG => return error.SystemResources,
690 posix.ENFILE => return error.SystemResources,
691 posix.ENOMEM => return error.SystemResources,
692 posix.EACCES => return error.AccessDenied,
693 posix.EPERM => return error.AccessDenied,
694 posix.EINVAL => return error.InvalidExe,
695 posix.ENOEXEC => return error.InvalidExe,
696 posix.EIO => return error.FileSystem,
697 posix.ELOOP => return error.FileSystem,
698 posix.EISDIR => return error.IsDir,
699 posix.ENOENT => return error.FileNotFound,
700 posix.ENOTDIR => return error.NotDir,
701 posix.ETXTBSY => return error.FileBusy,
702 else => return unexpectedErrorPosix(err),
703 }
704}
705
706pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
707pub var posix_environ_raw: [][*]u8 = undefined;
708
709/// See std.elf for the constants.
710pub fn linuxGetAuxVal(index: usize) usize {
711 if (builtin.link_libc) {
712 return usize(std.c.getauxval(index));
713 } else if (linux_elf_aux_maybe) |auxv| {
714 var i: usize = 0;
715 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
716 if (auxv[i].a_type == index)
717 return auxv[i].a_un.a_val;
718 }
719 }
720 return 0;
721}
722
723135pub fn getBaseAddress() usize {
724136 switch (builtin.os) {
725137 builtin.Os.linux => {
......@@ -803,7 +215,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
803215 }
804216 return result;
805217 } else {
806 for (posix_environ_raw) |ptr| {
218 for (posix.environ) |ptr| {
807219 var line_i: usize = 0;
808220 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
809221 const key = ptr[0..line_i];
......@@ -823,23 +235,6 @@ test "os.getEnvMap" {
823235 defer env.deinit();
824236}
825237
826/// TODO make this go through libc when we have it
827pub fn getEnvPosix(key: []const u8) ?[]const u8 {
828 for (posix_environ_raw) |ptr| {
829 var line_i: usize = 0;
830 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
831 const this_key = ptr[0..line_i];
832 if (!mem.eql(u8, key, this_key)) continue;
833
834 var end_i: usize = line_i;
835 while (ptr[end_i] != 0) : (end_i += 1) {}
836 const this_value = ptr[line_i + 1 .. end_i];
837
838 return this_value;
839 }
840 return null;
841}
842
843238pub const GetEnvVarOwnedError = error{
844239 OutOfMemory,
845240 EnvironmentVariableNotFound,
......@@ -896,130 +291,22 @@ test "os.getEnvVarOwned" {
896291 testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
897292}
898293
899/// Caller must free the returned memory.
900pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
901 var buf: [MAX_PATH_BYTES]u8 = undefined;
902 return mem.dupe(allocator, u8, try getCwd(&buf));
294/// The result is a slice of `out_buffer`, from index `0`.
295pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
296 return posix.getcwd(out_buffer);
903297}
904298
905pub const GetCwdError = error{Unexpected};
906
907/// The result is a slice of out_buffer.
908pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
909 switch (builtin.os) {
910 Os.windows => {
911 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
912 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
913 const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
914 const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
915 if (result == 0) {
916 const err = windows.GetLastError();
917 switch (err) {
918 else => return unexpectedErrorWindows(err),
919 }
920 }
921 assert(result <= utf16le_buf.len);
922 const utf16le_slice = utf16le_buf[0..result];
923 // Trust that Windows gives us valid UTF-16LE.
924 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
925 return out_buffer[0..end_index];
926 },
927 else => {
928 const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
929 switch (err) {
930 0 => return cstr.toSlice(out_buffer),
931 posix.ERANGE => unreachable,
932 else => return unexpectedErrorPosix(err),
933 }
934 },
935 }
299/// Caller must free the returned memory.
300pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
301 var buf: [os.MAX_PATH_BYTES]u8 = undefined;
302 return mem.dupe(allocator, u8, try posix.getcwd(&buf));
936303}
937304
938test "os.getCwd" {
305test "getCwdAlloc" {
939306 // at least call it so it gets compiled
940 _ = getCwdAlloc(debug.global_allocator) catch undefined;
941 var buf: [MAX_PATH_BYTES]u8 = undefined;
942 _ = getCwd(&buf) catch undefined;
943}
944
945pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
946
947/// TODO add a symLinkC variant
948pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
949 if (is_windows) {
950 return symLinkWindows(existing_path, new_path);
951 } else {
952 return symLinkPosix(existing_path, new_path);
953 }
954}
955
956pub const WindowsSymLinkError = error{
957 NameTooLong,
958 InvalidUtf8,
959 BadPathName,
960
961 /// See https://github.com/ziglang/zig/issues/1396
962 Unexpected,
963};
964
965pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
966 if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
967 const err = windows.GetLastError();
968 switch (err) {
969 else => return unexpectedErrorWindows(err),
970 }
971 }
972}
973
974pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
975 const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
976 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
977 return symLinkW(&existing_path_w, &new_path_w);
978}
979
980pub const PosixSymLinkError = error{
981 AccessDenied,
982 DiskQuota,
983 PathAlreadyExists,
984 FileSystem,
985 SymLinkLoop,
986 NameTooLong,
987 FileNotFound,
988 SystemResources,
989 NoSpaceLeft,
990 ReadOnlyFileSystem,
991 NotDir,
992
993 /// See https://github.com/ziglang/zig/issues/1396
994 Unexpected,
995};
996
997pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
998 const err = posix.getErrno(posix.symlink(existing_path, new_path));
999 switch (err) {
1000 0 => return,
1001 posix.EFAULT => unreachable,
1002 posix.EINVAL => unreachable,
1003 posix.EACCES => return error.AccessDenied,
1004 posix.EPERM => return error.AccessDenied,
1005 posix.EDQUOT => return error.DiskQuota,
1006 posix.EEXIST => return error.PathAlreadyExists,
1007 posix.EIO => return error.FileSystem,
1008 posix.ELOOP => return error.SymLinkLoop,
1009 posix.ENAMETOOLONG => return error.NameTooLong,
1010 posix.ENOENT => return error.FileNotFound,
1011 posix.ENOTDIR => return error.NotDir,
1012 posix.ENOMEM => return error.SystemResources,
1013 posix.ENOSPC => return error.NoSpaceLeft,
1014 posix.EROFS => return error.ReadOnlyFileSystem,
1015 else => return unexpectedErrorPosix(err),
1016 }
1017}
1018
1019pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
1020 const existing_path_c = try toPosixPath(existing_path);
1021 const new_path_c = try toPosixPath(new_path);
1022 return symLinkPosixC(&existing_path_c, &new_path_c);
307 var buf: [1000]u8 = undefined;
308 const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator;
309 _ = getCwdAlloc(allocator) catch {};
1023310}
1024311
1025312// here we replace the standard +/ with -_ so that it can be used in a file name
......@@ -1054,78 +341,6 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
1054341 }
1055342}
1056343
1057pub const DeleteFileError = error{
1058 FileNotFound,
1059 AccessDenied,
1060 FileBusy,
1061 FileSystem,
1062 IsDir,
1063 SymLinkLoop,
1064 NameTooLong,
1065 NotDir,
1066 SystemResources,
1067 ReadOnlyFileSystem,
1068
1069 /// On Windows, file paths must be valid Unicode.
1070 InvalidUtf8,
1071
1072 /// On Windows, file paths cannot contain these characters:
1073 /// '/', '*', '?', '"', '<', '>', '|'
1074 BadPathName,
1075
1076 /// See https://github.com/ziglang/zig/issues/1396
1077 Unexpected,
1078};
1079
1080pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
1081 if (builtin.os == Os.windows) {
1082 const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
1083 return deleteFileW(&file_path_w);
1084 } else {
1085 const file_path_c = try toPosixPath(file_path);
1086 return deleteFileC(&file_path_c);
1087 }
1088}
1089
1090pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
1091 if (windows.DeleteFileW(file_path) == 0) {
1092 const err = windows.GetLastError();
1093 switch (err) {
1094 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1095 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1096 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1097 windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
1098 else => return unexpectedErrorWindows(err),
1099 }
1100 }
1101}
1102
1103pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
1104 if (is_windows) {
1105 const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
1106 return deleteFileW(&file_path_w);
1107 } else {
1108 const err = posix.getErrno(posix.unlink(file_path));
1109 switch (err) {
1110 0 => return,
1111 posix.EACCES => return error.AccessDenied,
1112 posix.EPERM => return error.AccessDenied,
1113 posix.EBUSY => return error.FileBusy,
1114 posix.EFAULT => unreachable,
1115 posix.EINVAL => unreachable,
1116 posix.EIO => return error.FileSystem,
1117 posix.EISDIR => return error.IsDir,
1118 posix.ELOOP => return error.SymLinkLoop,
1119 posix.ENAMETOOLONG => return error.NameTooLong,
1120 posix.ENOENT => return error.FileNotFound,
1121 posix.ENOTDIR => return error.NotDir,
1122 posix.ENOMEM => return error.SystemResources,
1123 posix.EROFS => return error.ReadOnlyFileSystem,
1124 else => return unexpectedErrorPosix(err),
1125 }
1126 }
1127}
1128
1129344/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
1130345/// merged and readily available,
1131346/// there is a possibility of power loss or application termination leaving temporary files present
......@@ -1236,8 +451,8 @@ pub const AtomicFile = struct {
1236451 const dest_path_c = try toPosixPath(self.dest_path);
1237452 return renameC(&self.tmp_path_buf, &dest_path_c);
1238453 } else if (is_windows) {
1239 const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
1240 const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
454 const dest_path_w = try posix.sliceToPrefixedFileW(self.dest_path);
455 const tmp_path_w = try posix.cStrToPrefixedFileW(&self.tmp_path_buf);
1241456 return renameW(&tmp_path_w, &dest_path_w);
1242457 } else {
1243458 @compileError("Unsupported OS");
......@@ -1245,109 +460,27 @@ pub const AtomicFile = struct {
1245460 }
1246461};
1247462
1248pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
1249 if (is_windows) {
1250 const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
1251 const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
1252 return renameW(&old_path_w, &new_path_w);
1253 } else {
1254 const err = posix.getErrno(posix.rename(old_path, new_path));
1255 switch (err) {
1256 0 => return,
1257 posix.EACCES => return error.AccessDenied,
1258 posix.EPERM => return error.AccessDenied,
1259 posix.EBUSY => return error.FileBusy,
1260 posix.EDQUOT => return error.DiskQuota,
1261 posix.EFAULT => unreachable,
1262 posix.EINVAL => unreachable,
1263 posix.EISDIR => return error.IsDir,
1264 posix.ELOOP => return error.SymLinkLoop,
1265 posix.EMLINK => return error.LinkQuotaExceeded,
1266 posix.ENAMETOOLONG => return error.NameTooLong,
1267 posix.ENOENT => return error.FileNotFound,
1268 posix.ENOTDIR => return error.NotDir,
1269 posix.ENOMEM => return error.SystemResources,
1270 posix.ENOSPC => return error.NoSpaceLeft,
1271 posix.EEXIST => return error.PathAlreadyExists,
1272 posix.ENOTEMPTY => return error.PathAlreadyExists,
1273 posix.EROFS => return error.ReadOnlyFileSystem,
1274 posix.EXDEV => return error.RenameAcrossMountPoints,
1275 else => return unexpectedErrorPosix(err),
1276 }
1277 }
1278}
1279
1280pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
1281 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
1282 if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
1283 const err = windows.GetLastError();
1284 switch (err) {
1285 else => return unexpectedErrorWindows(err),
1286 }
1287 }
1288}
1289
1290pub fn rename(old_path: []const u8, new_path: []const u8) !void {
1291 if (is_windows) {
1292 const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
1293 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
1294 return renameW(&old_path_w, &new_path_w);
1295 } else {
1296 const old_path_c = try toPosixPath(old_path);
1297 const new_path_c = try toPosixPath(new_path);
1298 return renameC(&old_path_c, &new_path_c);
1299 }
1300}
463const default_new_dir_mode = 0o755;
1301464
465/// Create a new directory.
1302466pub fn makeDir(dir_path: []const u8) !void {
1303 if (is_windows) {
1304 return makeDirWindows(dir_path);
1305 } else {
1306 return makeDirPosix(dir_path);
1307 }
467 return posix.mkdir(dir_path, default_new_dir_mode);
1308468}
1309469
1310pub fn makeDirWindows(dir_path: []const u8) !void {
1311 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1312
1313 if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
1314 const err = windows.GetLastError();
1315 return switch (err) {
1316 windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
1317 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1318 else => unexpectedErrorWindows(err),
1319 };
1320 }
470/// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string.
471pub fn makeDirC(dir_path: [*]const u8) !void {
472 return posix.mkdirC(dir_path, default_new_dir_mode);
1321473}
1322474
1323pub fn makeDirPosixC(dir_path: [*]const u8) !void {
1324 const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
1325 switch (err) {
1326 0 => return,
1327 posix.EACCES => return error.AccessDenied,
1328 posix.EPERM => return error.AccessDenied,
1329 posix.EDQUOT => return error.DiskQuota,
1330 posix.EEXIST => return error.PathAlreadyExists,
1331 posix.EFAULT => unreachable,
1332 posix.ELOOP => return error.SymLinkLoop,
1333 posix.EMLINK => return error.LinkQuotaExceeded,
1334 posix.ENAMETOOLONG => return error.NameTooLong,
1335 posix.ENOENT => return error.FileNotFound,
1336 posix.ENOMEM => return error.SystemResources,
1337 posix.ENOSPC => return error.NoSpaceLeft,
1338 posix.ENOTDIR => return error.NotDir,
1339 posix.EROFS => return error.ReadOnlyFileSystem,
1340 else => return unexpectedErrorPosix(err),
1341 }
1342}
1343
1344pub fn makeDirPosix(dir_path: []const u8) !void {
1345 const dir_path_c = try toPosixPath(dir_path);
1346 return makeDirPosixC(&dir_path_c);
475/// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string.
476pub fn makeDirW(dir_path: [*]const u16) !void {
477 return posix.mkdirW(dir_path, default_new_dir_mode);
1347478}
1348479
1349480/// Calls makeDir recursively to make an entire path. Returns success if the path
1350481/// already exists and is a directory.
482/// This function is not atomic, and if it returns an error, the file system may
483/// have been modified regardless.
1351484/// TODO determine if we can remove the allocator requirement from this function
1352485pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1353486 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
......@@ -1381,78 +514,20 @@ pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1381514 }
1382515}
1383516
1384pub const DeleteDirError = error{
1385 AccessDenied,
1386 FileBusy,
1387 SymLinkLoop,
1388 NameTooLong,
1389 FileNotFound,
1390 SystemResources,
1391 NotDir,
1392 DirNotEmpty,
1393 ReadOnlyFileSystem,
1394 InvalidUtf8,
1395 BadPathName,
1396
1397 /// See https://github.com/ziglang/zig/issues/1396
1398 Unexpected,
1399};
1400
1401pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
1402 switch (builtin.os) {
1403 Os.windows => {
1404 const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
1405 return deleteDirW(&dir_path_w);
1406 },
1407 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1408 const err = posix.getErrno(posix.rmdir(dir_path));
1409 switch (err) {
1410 0 => return,
1411 posix.EACCES => return error.AccessDenied,
1412 posix.EPERM => return error.AccessDenied,
1413 posix.EBUSY => return error.FileBusy,
1414 posix.EFAULT => unreachable,
1415 posix.EINVAL => unreachable,
1416 posix.ELOOP => return error.SymLinkLoop,
1417 posix.ENAMETOOLONG => return error.NameTooLong,
1418 posix.ENOENT => return error.FileNotFound,
1419 posix.ENOMEM => return error.SystemResources,
1420 posix.ENOTDIR => return error.NotDir,
1421 posix.EEXIST => return error.DirNotEmpty,
1422 posix.ENOTEMPTY => return error.DirNotEmpty,
1423 posix.EROFS => return error.ReadOnlyFileSystem,
1424 else => return unexpectedErrorPosix(err),
1425 }
1426 },
1427 else => @compileError("unimplemented"),
1428 }
517/// Returns `error.DirNotEmpty` if the directory is not empty.
518/// To delete a directory recursively, see `deleteTree`.
519pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
520 return posix.rmdir(dir_path);
1429521}
1430522
1431pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
1432 if (windows.RemoveDirectoryW(dir_path_w) == 0) {
1433 const err = windows.GetLastError();
1434 switch (err) {
1435 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1436 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1437 else => return unexpectedErrorWindows(err),
1438 }
1439 }
523/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
524pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
525 return posix.rmdirC(dir_path);
1440526}
1441527
1442/// Returns ::error.DirNotEmpty if the directory is not empty.
1443/// To delete a directory recursively, see ::deleteTree
1444pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
1445 switch (builtin.os) {
1446 Os.windows => {
1447 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1448 return deleteDirW(&dir_path_w);
1449 },
1450 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1451 const dir_path_c = try toPosixPath(dir_path);
1452 return deleteDirC(&dir_path_c);
1453 },
1454 else => @compileError("unimplemented"),
1455 }
528/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
529pub fn deleteDirW(dir_path: [*]const u16) DeleteDirError!void {
530 return posix.rmdirW(dir_path);
1456531}
1457532
1458533/// Whether ::full_path describes a symlink, file, or directory, this function
......@@ -1486,7 +561,6 @@ const DeleteTreeError = error{
1486561 /// '/', '*', '?', '"', '<', '>', '|'
1487562 BadPathName,
1488563
1489 /// See https://github.com/ziglang/zig/issues/1396
1490564 Unexpected,
1491565};
1492566
......@@ -1624,7 +698,6 @@ pub const Dir = struct {
1624698 BadPathName,
1625699 DeviceBusy,
1626700
1627 /// See https://github.com/ziglang/zig/issues/1396
1628701 Unexpected,
1629702 };
1630703
......@@ -1878,121 +951,23 @@ pub const Dir = struct {
1878951 posix.DT_WHT => Entry.Kind.Whiteout,
1879952 else => Entry.Kind.Unknown,
1880953 };
1881 return Entry{
1882 .name = name,
1883 .kind = entry_kind,
1884 };
1885 }
1886 }
1887};
1888
1889pub fn changeCurDir(dir_path: []const u8) !void {
1890 const dir_path_c = try toPosixPath(dir_path);
1891 const err = posix.getErrno(posix.chdir(&dir_path_c));
1892 switch (err) {
1893 0 => return,
1894 posix.EACCES => return error.AccessDenied,
1895 posix.EFAULT => unreachable,
1896 posix.EIO => return error.FileSystem,
1897 posix.ELOOP => return error.SymLinkLoop,
1898 posix.ENAMETOOLONG => return error.NameTooLong,
1899 posix.ENOENT => return error.FileNotFound,
1900 posix.ENOMEM => return error.SystemResources,
1901 posix.ENOTDIR => return error.NotDir,
1902 else => return unexpectedErrorPosix(err),
1903 }
1904}
1905
1906/// Read value of a symbolic link.
1907/// The return value is a slice of out_buffer.
1908pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
1909 const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
1910 const err = posix.getErrno(rc);
1911 switch (err) {
1912 0 => return out_buffer[0..rc],
1913 posix.EACCES => return error.AccessDenied,
1914 posix.EFAULT => unreachable,
1915 posix.EINVAL => unreachable,
1916 posix.EIO => return error.FileSystem,
1917 posix.ELOOP => return error.SymLinkLoop,
1918 posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
1919 posix.ENOENT => return error.FileNotFound,
1920 posix.ENOMEM => return error.SystemResources,
1921 posix.ENOTDIR => return error.NotDir,
1922 else => return unexpectedErrorPosix(err),
1923 }
1924}
1925
1926/// Read value of a symbolic link.
1927/// The return value is a slice of out_buffer.
1928pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
1929 const file_path_c = try toPosixPath(file_path);
1930 return readLinkC(out_buffer, &file_path_c);
1931}
1932
1933pub fn posix_setuid(uid: u32) !void {
1934 const err = posix.getErrno(posix.setuid(uid));
1935 if (err == 0) return;
1936 return switch (err) {
1937 posix.EAGAIN => error.ResourceLimitReached,
1938 posix.EINVAL => error.InvalidUserId,
1939 posix.EPERM => error.PermissionDenied,
1940 else => unexpectedErrorPosix(err),
1941 };
1942}
1943
1944pub fn posix_setreuid(ruid: u32, euid: u32) !void {
1945 const err = posix.getErrno(posix.setreuid(ruid, euid));
1946 if (err == 0) return;
1947 return switch (err) {
1948 posix.EAGAIN => error.ResourceLimitReached,
1949 posix.EINVAL => error.InvalidUserId,
1950 posix.EPERM => error.PermissionDenied,
1951 else => unexpectedErrorPosix(err),
1952 };
1953}
1954
1955pub fn posix_setgid(gid: u32) !void {
1956 const err = posix.getErrno(posix.setgid(gid));
1957 if (err == 0) return;
1958 return switch (err) {
1959 posix.EAGAIN => error.ResourceLimitReached,
1960 posix.EINVAL => error.InvalidUserId,
1961 posix.EPERM => error.PermissionDenied,
1962 else => unexpectedErrorPosix(err),
1963 };
1964}
1965
1966pub fn posix_setregid(rgid: u32, egid: u32) !void {
1967 const err = posix.getErrno(posix.setregid(rgid, egid));
1968 if (err == 0) return;
1969 return switch (err) {
1970 posix.EAGAIN => error.ResourceLimitReached,
1971 posix.EINVAL => error.InvalidUserId,
1972 posix.EPERM => error.PermissionDenied,
1973 else => unexpectedErrorPosix(err),
1974 };
1975}
1976
1977pub const WindowsGetStdHandleErrs = error{
1978 NoStdHandles,
1979
1980 /// See https://github.com/ziglang/zig/issues/1396
1981 Unexpected,
1982};
1983
1984pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
1985 if (windows.GetStdHandle(handle_id)) |handle| {
1986 if (handle == windows.INVALID_HANDLE_VALUE) {
1987 const err = windows.GetLastError();
1988 return switch (err) {
1989 else => os.unexpectedErrorWindows(err),
1990 };
954 return Entry{
955 .name = name,
956 .kind = entry_kind,
957 };
1991958 }
1992 return handle;
1993 } else {
1994 return error.NoStdHandles;
1995959 }
960};
961
962/// Read value of a symbolic link.
963/// The return value is a slice of buffer, from index `0`.
964pub fn readLink(buffer: *[posix.PATH_MAX]u8, pathname: []const u8) ![]u8 {
965 return posix.readlink(pathname, buffer);
966}
967
968/// Same as `readLink`, except the `pathname` parameter is null-terminated.
969pub fn readLinkC(buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
970 return posix.readlinkC(pathname, buffer);
1996971}
1997972
1998973pub const ArgIteratorPosix = struct {
......@@ -2328,34 +1303,6 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
23281303 testing.expect(it.next(debug.global_allocator) == null);
23291304}
23301305
2331// TODO make this a build variable that you can set
2332const unexpected_error_tracing = false;
2333const UnexpectedError = error{
2334 /// The Operating System returned an undocumented error code.
2335 Unexpected,
2336};
2337
2338/// Call this when you made a syscall or something that sets errno
2339/// and you get an unexpected error.
2340pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2341 if (unexpected_error_tracing) {
2342 debug.warn("unexpected errno: {}\n", errno);
2343 debug.dumpCurrentStackTrace(null);
2344 }
2345 return error.Unexpected;
2346}
2347
2348/// Call this when you made a windows DLL call or something that does SetLastError
2349/// and you get an unexpected error.
2350pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2351 if (unexpected_error_tracing) {
2352 debug.warn("unexpected GetLastError(): {}\n", err);
2353 @breakpoint();
2354 debug.dumpCurrentStackTrace(null);
2355 }
2356 return error.Unexpected;
2357}
2358
23591306pub fn openSelfExe() !os.File {
23601307 switch (builtin.os) {
23611308 Os.linux => return os.File.openReadC(c"/proc/self/exe"),
......@@ -2366,7 +1313,7 @@ pub fn openSelfExe() !os.File {
23661313 return os.File.openReadC(self_exe_path.ptr);
23671314 },
23681315 Os.windows => {
2369 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
1316 var buf: [posix.PATH_MAX_WIDE]u16 = undefined;
23701317 const wide_slice = try selfExePathW(&buf);
23711318 return os.File.openReadW(wide_slice.ptr);
23721319 },
......@@ -2381,7 +1328,7 @@ test "openSelfExe" {
23811328 }
23821329}
23831330
2384pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
1331pub fn selfExePathW(out_buffer: *[posix.PATH_MAX_WIDE]u16) ![]u16 {
23851332 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
23861333 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
23871334 assert(rc <= out_buffer.len);
......@@ -2434,7 +1381,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
24341381 };
24351382 },
24361383 Os.windows => {
2437 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
1384 var utf16le_buf: [posix.PATH_MAX_WIDE]u16 = undefined;
24381385 const utf16le_slice = try selfExePathW(&utf16le_buf);
24391386 // Trust that Windows gives us valid UTF-16LE.
24401387 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
......@@ -2481,521 +1428,6 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
24811428 }
24821429}
24831430
2484pub fn isTty(handle: FileHandle) bool {
2485 if (is_windows) {
2486 return windows_util.windowsIsTty(handle);
2487 } else {
2488 if (builtin.link_libc) {
2489 return c.isatty(handle) != 0;
2490 } else {
2491 return posix.isatty(handle);
2492 }
2493 }
2494}
2495
2496pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
2497 if (is_windows) {
2498 return windows_util.windowsIsCygwinPty(handle);
2499 } else {
2500 if (builtin.link_libc) {
2501 return c.isatty(handle) != 0;
2502 } else {
2503 return posix.isatty(handle);
2504 }
2505 }
2506}
2507
2508pub const PosixSocketError = error{
2509 /// Permission to create a socket of the specified type and/or
2510 /// pro‐tocol is denied.
2511 PermissionDenied,
2512
2513 /// The implementation does not support the specified address family.
2514 AddressFamilyNotSupported,
2515
2516 /// Unknown protocol, or protocol family not available.
2517 ProtocolFamilyNotAvailable,
2518
2519 /// The per-process limit on the number of open file descriptors has been reached.
2520 ProcessFdQuotaExceeded,
2521
2522 /// The system-wide limit on the total number of open files has been reached.
2523 SystemFdQuotaExceeded,
2524
2525 /// Insufficient memory is available. The socket cannot be created until sufficient
2526 /// resources are freed.
2527 SystemResources,
2528
2529 /// The protocol type or the specified protocol is not supported within this domain.
2530 ProtocolNotSupported,
2531};
2532
2533pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
2534 const rc = posix.socket(domain, socket_type, protocol);
2535 const err = posix.getErrno(rc);
2536 switch (err) {
2537 0 => return @intCast(i32, rc),
2538 posix.EACCES => return PosixSocketError.PermissionDenied,
2539 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
2540 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
2541 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
2542 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
2543 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
2544 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
2545 else => return unexpectedErrorPosix(err),
2546 }
2547}
2548
2549pub const PosixBindError = error{
2550 /// The address is protected, and the user is not the superuser.
2551 /// For UNIX domain sockets: Search permission is denied on a component
2552 /// of the path prefix.
2553 AccessDenied,
2554
2555 /// The given address is already in use, or in the case of Internet domain sockets,
2556 /// The port number was specified as zero in the socket
2557 /// address structure, but, upon attempting to bind to an ephemeral port, it was
2558 /// determined that all port numbers in the ephemeral port range are currently in
2559 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
2560 AddressInUse,
2561
2562 /// A nonexistent interface was requested or the requested address was not local.
2563 AddressNotAvailable,
2564
2565 /// Too many symbolic links were encountered in resolving addr.
2566 SymLinkLoop,
2567
2568 /// addr is too long.
2569 NameTooLong,
2570
2571 /// A component in the directory prefix of the socket pathname does not exist.
2572 FileNotFound,
2573
2574 /// Insufficient kernel memory was available.
2575 SystemResources,
2576
2577 /// A component of the path prefix is not a directory.
2578 NotDir,
2579
2580 /// The socket inode would reside on a read-only filesystem.
2581 ReadOnlyFileSystem,
2582
2583 /// See https://github.com/ziglang/zig/issues/1396
2584 Unexpected,
2585};
2586
2587/// addr is `&const T` where T is one of the sockaddr
2588pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
2589 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2590 const err = posix.getErrno(rc);
2591 switch (err) {
2592 0 => return,
2593 posix.EACCES => return PosixBindError.AccessDenied,
2594 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2595 posix.EBADF => unreachable, // always a race condition if this error is returned
2596 posix.EINVAL => unreachable,
2597 posix.ENOTSOCK => unreachable,
2598 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2599 posix.EFAULT => unreachable,
2600 posix.ELOOP => return PosixBindError.SymLinkLoop,
2601 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2602 posix.ENOENT => return PosixBindError.FileNotFound,
2603 posix.ENOMEM => return PosixBindError.SystemResources,
2604 posix.ENOTDIR => return PosixBindError.NotDir,
2605 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2606 else => return unexpectedErrorPosix(err),
2607 }
2608}
2609
2610const PosixListenError = error{
2611 /// Another socket is already listening on the same port.
2612 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2613 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2614 /// was determined that all port numbers in the ephemeral port range are currently in
2615 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2616 AddressInUse,
2617
2618 /// The file descriptor sockfd does not refer to a socket.
2619 FileDescriptorNotASocket,
2620
2621 /// The socket is not of a type that supports the listen() operation.
2622 OperationNotSupported,
2623
2624 /// See https://github.com/ziglang/zig/issues/1396
2625 Unexpected,
2626};
2627
2628pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2629 const rc = posix.listen(sockfd, backlog);
2630 const err = posix.getErrno(rc);
2631 switch (err) {
2632 0 => return,
2633 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2634 posix.EBADF => unreachable,
2635 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2636 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2637 else => return unexpectedErrorPosix(err),
2638 }
2639}
2640
2641pub const PosixAcceptError = error{
2642 ConnectionAborted,
2643
2644 /// The per-process limit on the number of open file descriptors has been reached.
2645 ProcessFdQuotaExceeded,
2646
2647 /// The system-wide limit on the total number of open files has been reached.
2648 SystemFdQuotaExceeded,
2649
2650 /// Not enough free memory. This often means that the memory allocation is limited
2651 /// by the socket buffer limits, not by the system memory.
2652 SystemResources,
2653
2654 /// The file descriptor sockfd does not refer to a socket.
2655 FileDescriptorNotASocket,
2656
2657 /// The referenced socket is not of type SOCK_STREAM.
2658 OperationNotSupported,
2659
2660 ProtocolFailure,
2661
2662 /// Firewall rules forbid connection.
2663 BlockedByFirewall,
2664
2665 /// See https://github.com/ziglang/zig/issues/1396
2666 Unexpected,
2667};
2668
2669pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2670 while (true) {
2671 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2672 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2673 const err = posix.getErrno(rc);
2674 switch (err) {
2675 0 => return @intCast(i32, rc),
2676 posix.EINTR => continue,
2677 else => return unexpectedErrorPosix(err),
2678
2679 posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
2680 posix.EBADF => unreachable, // always a race condition
2681 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2682 posix.EFAULT => unreachable,
2683 posix.EINVAL => unreachable,
2684 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2685 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2686 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2687 posix.ENOMEM => return PosixAcceptError.SystemResources,
2688 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2689 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2690 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2691 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2692 }
2693 }
2694}
2695
2696/// Returns -1 if would block.
2697pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2698 while (true) {
2699 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2700 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2701 const err = posix.getErrno(rc);
2702 switch (err) {
2703 0 => return @intCast(i32, rc),
2704 posix.EINTR => continue,
2705 else => return unexpectedErrorPosix(err),
2706
2707 posix.EAGAIN => return -1,
2708 posix.EBADF => unreachable, // always a race condition
2709 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2710 posix.EFAULT => unreachable,
2711 posix.EINVAL => unreachable,
2712 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2713 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2714 posix.ENOBUFS => return PosixAcceptError.SystemResources,
2715 posix.ENOMEM => return PosixAcceptError.SystemResources,
2716 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2717 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2718 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2719 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2720 }
2721 }
2722}
2723
2724pub const LinuxEpollCreateError = error{
2725 /// The per-user limit on the number of epoll instances imposed by
2726 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2727 /// details.
2728 /// Or, The per-process limit on the number of open file descriptors has been reached.
2729 ProcessFdQuotaExceeded,
2730
2731 /// The system-wide limit on the total number of open files has been reached.
2732 SystemFdQuotaExceeded,
2733
2734 /// There was insufficient memory to create the kernel object.
2735 SystemResources,
2736
2737 /// See https://github.com/ziglang/zig/issues/1396
2738 Unexpected,
2739};
2740
2741pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2742 const rc = posix.epoll_create1(flags);
2743 const err = posix.getErrno(rc);
2744 switch (err) {
2745 0 => return @intCast(i32, rc),
2746 else => return unexpectedErrorPosix(err),
2747
2748 posix.EINVAL => unreachable,
2749 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2750 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2751 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2752 }
2753}
2754
2755pub const LinuxEpollCtlError = error{
2756 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2757 /// with this epoll instance.
2758 FileDescriptorAlreadyPresentInSet,
2759
2760 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2761 /// circular loop of epoll instances monitoring one another.
2762 OperationCausesCircularLoop,
2763
2764 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2765 /// instance.
2766 FileDescriptorNotRegistered,
2767
2768 /// There was insufficient memory to handle the requested op control operation.
2769 SystemResources,
2770
2771 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2772 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2773 /// See epoll(7) for further details.
2774 UserResourceLimitReached,
2775
2776 /// The target file fd does not support epoll. This error can occur if fd refers to,
2777 /// for example, a regular file or a directory.
2778 FileDescriptorIncompatibleWithEpoll,
2779
2780 /// See https://github.com/ziglang/zig/issues/1396
2781 Unexpected,
2782};
2783
2784pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
2785 const rc = posix.epoll_ctl(epfd, op, fd, event);
2786 const err = posix.getErrno(rc);
2787 switch (err) {
2788 0 => return,
2789 else => return unexpectedErrorPosix(err),
2790
2791 posix.EBADF => unreachable, // always a race condition if this happens
2792 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2793 posix.EINVAL => unreachable,
2794 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2795 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2796 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2797 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2798 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2799 }
2800}
2801
2802pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2803 while (true) {
2804 const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
2805 const err = posix.getErrno(rc);
2806 switch (err) {
2807 0 => return rc,
2808 posix.EINTR => continue,
2809 posix.EBADF => unreachable,
2810 posix.EFAULT => unreachable,
2811 posix.EINVAL => unreachable,
2812 else => unreachable,
2813 }
2814 }
2815}
2816
2817pub const LinuxEventFdError = error{
2818 InvalidFlagValue,
2819 SystemResources,
2820 ProcessFdQuotaExceeded,
2821 SystemFdQuotaExceeded,
2822
2823 /// See https://github.com/ziglang/zig/issues/1396
2824 Unexpected,
2825};
2826
2827pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
2828 const rc = posix.eventfd(initval, flags);
2829 const err = posix.getErrno(rc);
2830 switch (err) {
2831 0 => return @intCast(i32, rc),
2832 else => return unexpectedErrorPosix(err),
2833
2834 posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
2835 posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
2836 posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
2837 posix.ENODEV => return LinuxEventFdError.SystemResources,
2838 posix.ENOMEM => return LinuxEventFdError.SystemResources,
2839 }
2840}
2841
2842pub const PosixGetSockNameError = error{
2843 /// Insufficient resources were available in the system to perform the operation.
2844 SystemResources,
2845
2846 /// See https://github.com/ziglang/zig/issues/1396
2847 Unexpected,
2848};
2849
2850pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2851 var addr: posix.sockaddr = undefined;
2852 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2853 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2854 const err = posix.getErrno(rc);
2855 switch (err) {
2856 0 => return addr,
2857 else => return unexpectedErrorPosix(err),
2858
2859 posix.EBADF => unreachable,
2860 posix.EFAULT => unreachable,
2861 posix.EINVAL => unreachable,
2862 posix.ENOTSOCK => unreachable,
2863 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2864 }
2865}
2866
2867pub const PosixConnectError = error{
2868 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2869 /// file, or search permission is denied for one of the directories in the path prefix.
2870 /// or
2871 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2872 /// the connection request failed because of a local firewall rule.
2873 PermissionDenied,
2874
2875 /// Local address is already in use.
2876 AddressInUse,
2877
2878 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2879 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2880 /// in the ephemeral port range are currently in use. See the discussion of
2881 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2882 AddressNotAvailable,
2883
2884 /// The passed address didn't have the correct address family in its sa_family field.
2885 AddressFamilyNotSupported,
2886
2887 /// Insufficient entries in the routing cache.
2888 SystemResources,
2889
2890 /// A connect() on a stream socket found no one listening on the remote address.
2891 ConnectionRefused,
2892
2893 /// Network is unreachable.
2894 NetworkUnreachable,
2895
2896 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2897 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2898 ConnectionTimedOut,
2899
2900 /// See https://github.com/ziglang/zig/issues/1396
2901 Unexpected,
2902};
2903
2904pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
2905 while (true) {
2906 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2907 const err = posix.getErrno(rc);
2908 switch (err) {
2909 0 => return,
2910 else => return unexpectedErrorPosix(err),
2911
2912 posix.EACCES => return PosixConnectError.PermissionDenied,
2913 posix.EPERM => return PosixConnectError.PermissionDenied,
2914 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2915 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2916 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2917 posix.EAGAIN => return PosixConnectError.SystemResources,
2918 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2919 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2920 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2921 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2922 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2923 posix.EINTR => continue,
2924 posix.EISCONN => unreachable, // The socket is already connected.
2925 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2926 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2927 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2928 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2929 }
2930 }
2931}
2932
2933/// Same as posixConnect except it is for blocking socket file descriptors.
2934/// It expects to receive EINPROGRESS.
2935pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
2936 while (true) {
2937 const rc = posix.connect(sockfd, sockaddr, len);
2938 const err = posix.getErrno(rc);
2939 switch (err) {
2940 0, posix.EINPROGRESS => return,
2941 else => return unexpectedErrorPosix(err),
2942
2943 posix.EACCES => return PosixConnectError.PermissionDenied,
2944 posix.EPERM => return PosixConnectError.PermissionDenied,
2945 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2946 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2947 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2948 posix.EAGAIN => return PosixConnectError.SystemResources,
2949 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2950 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2951 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2952 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2953 posix.EINTR => continue,
2954 posix.EISCONN => unreachable, // The socket is already connected.
2955 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2956 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2957 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2958 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2959 }
2960 }
2961}
2962
2963pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2964 var err_code: i32 = undefined;
2965 var size: u32 = @sizeOf(i32);
2966 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
2967 assert(size == 4);
2968 const err = posix.getErrno(rc);
2969 switch (err) {
2970 0 => switch (err_code) {
2971 0 => return,
2972 else => return unexpectedErrorPosix(err),
2973
2974 posix.EACCES => return PosixConnectError.PermissionDenied,
2975 posix.EPERM => return PosixConnectError.PermissionDenied,
2976 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2977 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2978 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2979 posix.EAGAIN => return PosixConnectError.SystemResources,
2980 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2981 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2982 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2983 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2984 posix.EISCONN => unreachable, // The socket is already connected.
2985 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2986 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2987 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2988 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2989 },
2990 else => return unexpectedErrorPosix(err),
2991 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2992 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2993 posix.EINVAL => unreachable,
2994 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2995 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2996 }
2997}
2998
29991431pub const Thread = struct {
30001432 data: Data,
30011433
......@@ -3123,7 +1555,6 @@ pub const SpawnThreadError = error{
31231555 /// Not enough userland memory to spawn the thread.
31241556 OutOfMemory,
31251557
3126 /// See https://github.com/ziglang/zig/issues/1396
31271558 Unexpected,
31281559};
31291560
......@@ -3301,47 +1732,16 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
33011732 }
33021733}
33031734
3304pub fn posixWait(pid: i32) i32 {
3305 var status: i32 = undefined;
3306 while (true) {
3307 const err = posix.getErrno(posix.waitpid(pid, &status, 0));
3308 switch (err) {
3309 0 => return status,
3310 posix.EINTR => continue,
3311 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
3312 posix.EINVAL => unreachable, // The options argument was invalid
3313 else => unreachable,
3314 }
3315 }
3316}
3317
3318pub fn posixFStat(fd: i32) !posix.Stat {
3319 var stat: posix.Stat = undefined;
3320 const err = posix.getErrno(posix.fstat(fd, &stat));
3321 if (err > 0) {
3322 return switch (err) {
3323 // We do not make this an error code because if you get EBADF it's always a bug,
3324 // since the fd could have been reused.
3325 posix.EBADF => unreachable,
3326 posix.ENOMEM => error.SystemResources,
3327 else => os.unexpectedErrorPosix(err),
3328 };
3329 }
3330
3331 return stat;
3332}
3333
33341735pub const CpuCountError = error{
33351736 OutOfMemory,
33361737 PermissionDenied,
33371738
3338 /// See https://github.com/ziglang/zig/issues/1396
33391739 Unexpected,
33401740};
33411741
33421742pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
33431743 switch (builtin.os) {
3344 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
1744 .macosx, .freebsd, .netbsd => {
33451745 var count: c_int = undefined;
33461746 var count_len: usize = @sizeOf(c_int);
33471747 const rc = posix.sysctlbyname(switch (builtin.os) {
......@@ -3361,7 +1761,7 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
33611761 else => return os.unexpectedErrorPosix(err),
33621762 }
33631763 },
3364 builtin.Os.linux => {
1764 .linux => {
33651765 const usize_count = 16;
33661766 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
33671767
......@@ -3393,7 +1793,7 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
33931793 }
33941794 }
33951795 },
3396 builtin.Os.windows => {
1796 .windows => {
33971797 var system_info: windows.SYSTEM_INFO = undefined;
33981798 windows.GetSystemInfo(&system_info);
33991799 return @intCast(usize, system_info.dwNumberOfProcessors);
......@@ -3401,128 +1801,3 @@ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
34011801 else => @compileError("unsupported OS"),
34021802 }
34031803}
3404
3405pub const BsdKQueueError = error{
3406 /// The per-process limit on the number of open file descriptors has been reached.
3407 ProcessFdQuotaExceeded,
3408
3409 /// The system-wide limit on the total number of open files has been reached.
3410 SystemFdQuotaExceeded,
3411
3412 /// See https://github.com/ziglang/zig/issues/1396
3413 Unexpected,
3414};
3415
3416pub fn bsdKQueue() BsdKQueueError!i32 {
3417 const rc = posix.kqueue();
3418 const err = posix.getErrno(rc);
3419 switch (err) {
3420 0 => return @intCast(i32, rc),
3421 posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
3422 posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
3423 else => return unexpectedErrorPosix(err),
3424 }
3425}
3426
3427pub const BsdKEventError = error{
3428 /// The process does not have permission to register a filter.
3429 AccessDenied,
3430
3431 /// The event could not be found to be modified or deleted.
3432 EventNotFound,
3433
3434 /// No memory was available to register the event.
3435 SystemResources,
3436
3437 /// The specified process to attach to does not exist.
3438 ProcessNotFound,
3439};
3440
3441pub fn bsdKEvent(
3442 kq: i32,
3443 changelist: []const posix.Kevent,
3444 eventlist: []posix.Kevent,
3445 timeout: ?*const posix.timespec,
3446) BsdKEventError!usize {
3447 while (true) {
3448 const rc = posix.kevent(kq, changelist, eventlist, timeout);
3449 const err = posix.getErrno(rc);
3450 switch (err) {
3451 0 => return rc,
3452 posix.EACCES => return BsdKEventError.AccessDenied,
3453 posix.EFAULT => unreachable,
3454 posix.EBADF => unreachable,
3455 posix.EINTR => continue,
3456 posix.EINVAL => unreachable,
3457 posix.ENOENT => return BsdKEventError.EventNotFound,
3458 posix.ENOMEM => return BsdKEventError.SystemResources,
3459 posix.ESRCH => return BsdKEventError.ProcessNotFound,
3460 else => unreachable,
3461 }
3462 }
3463}
3464
3465pub fn linuxINotifyInit1(flags: u32) !i32 {
3466 const rc = linux.inotify_init1(flags);
3467 const err = posix.getErrno(rc);
3468 switch (err) {
3469 0 => return @intCast(i32, rc),
3470 posix.EINVAL => unreachable,
3471 posix.EMFILE => return error.ProcessFdQuotaExceeded,
3472 posix.ENFILE => return error.SystemFdQuotaExceeded,
3473 posix.ENOMEM => return error.SystemResources,
3474 else => return unexpectedErrorPosix(err),
3475 }
3476}
3477
3478pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
3479 const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
3480 const err = posix.getErrno(rc);
3481 switch (err) {
3482 0 => return @intCast(i32, rc),
3483 posix.EACCES => return error.AccessDenied,
3484 posix.EBADF => unreachable,
3485 posix.EFAULT => unreachable,
3486 posix.EINVAL => unreachable,
3487 posix.ENAMETOOLONG => return error.NameTooLong,
3488 posix.ENOENT => return error.FileNotFound,
3489 posix.ENOMEM => return error.SystemResources,
3490 posix.ENOSPC => return error.UserResourceLimitReached,
3491 else => return unexpectedErrorPosix(err),
3492 }
3493}
3494
3495pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
3496 const rc = linux.inotify_rm_watch(inotify_fd, wd);
3497 const err = posix.getErrno(rc);
3498 switch (err) {
3499 0 => return rc,
3500 posix.EBADF => unreachable,
3501 posix.EINVAL => unreachable,
3502 else => unreachable,
3503 }
3504}
3505
3506pub const MProtectError = error{
3507 AccessDenied,
3508 OutOfMemory,
3509 Unexpected,
3510};
3511
3512/// address and length must be page-aligned
3513pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {
3514 const negative_page_size = @bitCast(usize, -isize(page_size));
3515 const aligned_address = address & negative_page_size;
3516 const aligned_end = (address + length + page_size - 1) & negative_page_size;
3517 assert(address == aligned_address);
3518 assert(length == aligned_end - aligned_address);
3519 const rc = posix.mprotect(address, length, protection);
3520 const err = posix.getErrno(rc);
3521 switch (err) {
3522 0 => return,
3523 posix.EINVAL => unreachable,
3524 posix.EACCES => return error.AccessDenied,
3525 posix.ENOMEM => return error.OutOfMemory,
3526 else => return unexpectedErrorPosix(err),
3527 }
3528}
std/os/child_process.zig+1-1
......@@ -415,7 +415,7 @@ pub const ChildProcess = struct {
415415 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
416416 }
417417
418 os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
418 os.posix.execve(self.allocator, self.argv, env_map) catch |err| forkChildErrReport(err_pipe[1], err);
419419 }
420420
421421 // we are the parent
std/os/darwin.zig+8-1
......@@ -1,9 +1,16 @@
1const builtin = @import("builtin");
12const std = @import("../std.zig");
23const c = std.c;
34const assert = std.debug.assert;
45const maxInt = std.math.maxInt;
56
6pub use @import("darwin/errno.zig");
7pub const is_the_target = switch (builtin.os) {
8 .ios, .macosx, .watchos, .tvos => true,
9 else => false,
10};
11
12pub const errno_codes = @import("darwin/errno.zig");
13pub use errno_codes;
714
815pub const PATH_MAX = 1024;
916
std/os/file.zig+30-33
......@@ -223,9 +223,18 @@ pub const File = struct {
223223 os.close(self.handle);
224224 }
225225
226 /// Calls `os.isTty` on `self.handle`.
226 /// Test whether the file refers to a terminal.
227 /// See also `supportsAnsiEscapeCodes`.
227228 pub fn isTty(self: File) bool {
228 return os.isTty(self.handle);
229 return posix.isatty(self.handle);
230 }
231
232 /// Test whether ANSI escape codes will be treated as such.
233 pub fn supportsAnsiEscapeCodes(self: File) bool {
234 if (windows.is_the_target) {
235 return posix.isCygwinPty(self.handle);
236 }
237 return self.isTty();
229238 }
230239
231240 pub const SeekError = error{
......@@ -389,43 +398,16 @@ pub const File = struct {
389398 }
390399 }
391400
392 pub const ReadError = os.WindowsReadError || os.PosixReadError;
401 pub const ReadError = posix.ReadError;
393402
394403 pub fn read(self: File, buffer: []u8) ReadError!usize {
395 if (is_posix) {
396 return os.posixRead(self.handle, buffer);
397 } else if (is_windows) {
398 var index: usize = 0;
399 while (index < buffer.len) {
400 const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(maxInt(windows.DWORD)), buffer.len - index));
401 var amt_read: windows.DWORD = undefined;
402 if (windows.ReadFile(self.handle, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
403 const err = windows.GetLastError();
404 return switch (err) {
405 windows.ERROR.OPERATION_ABORTED => continue,
406 windows.ERROR.BROKEN_PIPE => return index,
407 else => os.unexpectedErrorWindows(err),
408 };
409 }
410 if (amt_read == 0) return index;
411 index += amt_read;
412 }
413 return index;
414 } else {
415 @compileError("Unsupported OS");
416 }
404 return posix.read(self.handle, buffer);
417405 }
418406
419 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
407 pub const WriteError = posix.WriteError;
420408
421409 pub fn write(self: File, bytes: []const u8) WriteError!void {
422 if (is_posix) {
423 try os.posixWrite(self.handle, bytes);
424 } else if (is_windows) {
425 try os.windowsWrite(self.handle, bytes);
426 } else {
427 @compileError("Unsupported OS");
428 }
410 return posix.write(self.handle, bytes);
429411 }
430412
431413 pub fn inStream(file: File) InStream {
......@@ -509,4 +491,19 @@ pub const File = struct {
509491 return self.file.getPos();
510492 }
511493 };
494
495 pub fn stdout() !File {
496 const handle = try posix.GetStdHandle(posix.STD_OUTPUT_HANDLE);
497 return openHandle(handle);
498 }
499
500 pub fn stderr() !File {
501 const handle = try posix.GetStdHandle(posix.STD_ERROR_HANDLE);
502 return openHandle(handle);
503 }
504
505 pub fn stdin() !File {
506 const handle = try posix.GetStdHandle(posix.STD_INPUT_HANDLE);
507 return openHandle(handle);
508 }
512509};
std/os/linux.zig+9-18
......@@ -12,7 +12,12 @@ pub use switch (builtin.arch) {
1212 builtin.Arch.aarch64 => @import("linux/arm64.zig"),
1313 else => @compileError("unsupported arch"),
1414};
15pub use @import("linux/errno.zig");
15pub const is_the_target = builtin.os == .linux;
16pub const errno_codes = @import("linux/errno.zig");
17pub use errno_codes;
18
19/// See `std.os.posix.getauxval`.
20pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
1621
1722pub const PATH_MAX = 4096;
1823pub const IOV_MAX = 1024;
......@@ -697,9 +702,9 @@ pub const winsize = extern struct {
697702};
698703
699704/// Get the errno from a syscall return value, or 0 for no error.
700pub fn getErrno(r: usize) usize {
705pub fn getErrno(r: usize) u12 {
701706 const signed_r = @bitCast(isize, r);
702 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
707 return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0;
703708}
704709
705710pub fn dup2(old: i32, new: i32) usize {
......@@ -766,11 +771,6 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
766771 return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
767772}
768773
769pub fn isatty(fd: i32) bool {
770 var wsz: winsize = undefined;
771 return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
772}
773
774774// TODO https://github.com/ziglang/zig/issues/265
775775pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
776776 return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
......@@ -1137,15 +1137,6 @@ pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
11371137pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
11381138pub const empty_sigset = []usize{0} ** sigset_t.len;
11391139
1140pub fn raise(sig: i32) usize {
1141 var set: sigset_t = undefined;
1142 blockAppSignals(&set);
1143 const tid = syscall0(SYS_gettid);
1144 const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
1145 restoreSignals(&set);
1146 return ret;
1147}
1148
11491140fn blockAllSignals(set: *sigset_t) void {
11501141 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
11511142}
......@@ -1672,7 +1663,7 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
16721663}
16731664
16741665test "import" {
1675 if (builtin.os == builtin.Os.linux) {
1666 if (is_the_target) {
16761667 _ = @import("linux/test.zig");
16771668 }
16781669}
std/os/linux/tls.zig+1-1
......@@ -126,7 +126,7 @@ pub fn initTLS() void {
126126 var tls_phdr: ?*elf.Phdr = null;
127127 var img_base: usize = 0;
128128
129 const auxv = std.os.linux_elf_aux_maybe.?;
129 const auxv = std.os.linux.elf_aux_maybe.?;
130130 var at_phent: usize = undefined;
131131 var at_phnum: usize = undefined;
132132 var at_phdr: usize = undefined;
std/os/posix.zig created+2159
......@@ -0,0 +1,2159 @@
1// This is the "Zig-flavored POSIX" API layer.
2// The purpose is not to match POSIX as closely as possible. Instead,
3// the goal is to provide a very specific layer of abstraction:
4// * Implement the POSIX functions, types, and definitions where possible,
5// using lower-level target-specific API. For example, on Linux `rename` might call
6// SYS_renameat or SYS_rename depending on the architecture.
7// * When null-terminated byte buffers are required, provide APIs which accept
8// slices as well as APIs which accept null-terminated byte buffers. Same goes
9// for UTF-16LE encoding.
10// * Convert "errno"-style error codes into Zig errors.
11// * Work around kernel bugs and limitations. For example, if a function accepts
12// a `usize` number of bytes to write, but the kernel can only handle maxInt(u32)
13// number of bytes, this API layer should introduce a loop to make multiple
14// syscalls so that the full `usize` number of bytes are written.
15// * Implement the OS-specific functions, types, and definitions that the Zig
16// standard library needs, at the same API abstraction layer as outlined above.
17// this includes, for example Windows functions.
18// * When there exists a corresponding libc function and linking libc, call the
19// libc function.
20// Note: The Zig standard library does not support POSIX thread cancellation, and
21// in general EINTR is handled by trying again.
22
23const std = @import("../std.zig");
24const builtin = @import("builtin");
25const assert = std.debug.assert;
26const os = @import("../os.zig");
27const system = os.system;
28const mem = std.mem;
29const BufMap = std.BufMap;
30const Allocator = mem.Allocator;
31const windows = os.windows;
32const wasi = os.wasi;
33const linux = os.linux;
34const testing = std.testing;
35
36pub const FileHandle = if (windows.is_the_target) windows.HANDLE else if (wasi.is_the_target) wasi.fd_t else i32;
37pub use system.errno_codes;
38
39pub const PATH_MAX = system.PATH_MAX;
40
41/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
42/// > prefix may be expanded to a longer string by the system at run time, and
43/// > this expansion applies to the total length.
44/// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
45pub const PATH_MAX_WIDE = 32767;
46
47pub const iovec = system.iovec;
48pub const iovec_const = system.iovec_const;
49
50/// See also `getenv`.
51pub var environ: [][*]u8 = undefined;
52
53/// To obtain errno, call this function with the return value of the
54/// system function call. For some systems this will obtain the value directly
55/// from the return code; for others it will use a thread-local errno variable.
56/// Therefore, this function only returns a well-defined value when it is called
57/// directly after the system function call which one wants to learn the errno
58/// value of.
59pub const errno = system.getErrno;
60
61/// Closes the file handle.
62/// This function is not capable of returning any indication of failure. An
63/// application which wants to ensure writes have succeeded before closing
64/// must call `fsync` before `close`.
65/// Note: The Zig standard library does not support POSIX thread cancellation.
66pub fn close(handle: FileHandle) void {
67 if (windows.is_the_target and !builtin.link_libc) {
68 assert(windows.CloseHandle(handle) != 0);
69 return;
70 }
71 if (wasi.is_the_target) {
72 switch (wasi.fd_close(handle)) {
73 0 => return,
74 else => |err| return unexpectedErrno(err),
75 }
76 }
77 switch (system.getErrno(system.close(handle))) {
78 EBADF => unreachable, // Always a race condition.
79 EINTR => return, // This is still a success. See https://github.com/ziglang/zig/issues/2425
80 else => return,
81 }
82}
83
84pub const GetRandomError = error{};
85
86/// Obtain a series of random bytes. These bytes can be used to seed user-space
87/// random number generators or for cryptographic purposes.
88/// When linking against libc, this calls the
89/// appropriate OS-specific library call. Otherwise it uses the zig standard
90/// library implementation.
91pub fn getrandom(buf: []u8) GetRandomError!void {
92 if (windows.is_the_target) {
93 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
94 // https://github.com/rust-lang-nursery/rand/issues/111
95 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
96 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
97 const err = windows.GetLastError();
98 return switch (err) {
99 else => unexpectedErrorWindows(err),
100 };
101 }
102 return;
103 }
104 if (linux.is_the_target) {
105 while (true) {
106 switch (system.getErrno(system.getrandom(buf.ptr, buf.len, 0))) {
107 0 => return,
108 EINVAL => unreachable,
109 EFAULT => unreachable,
110 EINTR => continue,
111 ENOSYS => return getRandomBytesDevURandom(buf),
112 else => |err| return unexpectedErrno(err),
113 }
114 }
115 }
116 if (wasi.is_the_target) {
117 switch (os.wasi.random_get(buf.ptr, buf.len)) {
118 0 => return,
119 else => |err| return unexpectedErrno(err),
120 }
121 }
122 return getRandomBytesDevURandom(buf);
123}
124
125fn getRandomBytesDevURandom(buf: []u8) !void {
126 const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
127 defer close(fd);
128
129 const stream = &os.File.openHandle(fd).inStream().stream;
130 stream.readNoEof(buf) catch return error.Unexpected;
131}
132
133test "os.getRandomBytes" {
134 var buf_a: [50]u8 = undefined;
135 var buf_b: [50]u8 = undefined;
136 try getRandomBytes(&buf_a);
137 try getRandomBytes(&buf_b);
138 // If this test fails the chance is significantly higher that there is a bug than
139 // that two sets of 50 bytes were equal.
140 testing.expect(!mem.eql(u8, buf_a, buf_b));
141}
142
143/// Causes abnormal process termination.
144/// If linking against libc, this calls the abort() libc function. Otherwise
145/// it raises SIGABRT followed by SIGKILL and finally lo
146pub fn abort() noreturn {
147 @setCold(true);
148 if (builtin.link_libc) {
149 c.abort();
150 }
151 if (windows.is_the_target) {
152 if (builtin.mode == .Debug) {
153 @breakpoint();
154 }
155 windows.ExitProcess(3);
156 }
157 if (builtin.os == .uefi) {
158 // TODO there must be a better thing to do here than loop forever
159 while (true) {}
160 }
161
162 raise(SIGABRT);
163
164 // TODO the rest of the implementation of abort() from musl libc here
165
166 raise(SIGKILL);
167 exit(127);
168}
169
170pub const RaiseError = error{};
171
172pub fn raise(sig: u8) RaiseError!void {
173 if (builtin.link_libc) {
174 switch (system.getErrno(system.raise(sig))) {
175 0 => return,
176 else => |err| return unexpectedErrno(err),
177 }
178 }
179
180 if (wasi.is_the_target) {
181 switch (wasi.proc_raise(SIGABRT)) {
182 0 => return,
183 else => |err| return unexpectedErrno(err),
184 }
185 }
186
187 if (windows.is_the_target) {
188 @compileError("TODO implement std.posix.raise for Windows");
189 }
190
191 var set: system.sigset_t = undefined;
192 system.blockAppSignals(&set);
193 const tid = system.syscall0(system.SYS_gettid);
194 const rc = system.syscall2(system.SYS_tkill, tid, sig);
195 system.restoreSignals(&set);
196 switch (system.getErrno(rc)) {
197 0 => return,
198 else => |err| return unexpectedErrno(err),
199 }
200}
201
202/// Exits the program cleanly with the specified status code.
203pub fn exit(status: u8) noreturn {
204 if (builtin.link_libc) {
205 std.c.exit(status);
206 }
207 if (windows.is_the_target) {
208 windows.ExitProcess(status);
209 }
210 if (wasi.is_the_target) {
211 wasi.proc_exit(status);
212 }
213 if (linux.is_the_target and !builtin.single_threaded) {
214 linux.exit_group(status);
215 }
216 system.exit(status);
217}
218
219pub const ReadError = error{
220 InputOutput,
221 SystemResources,
222 IsDir,
223 OperationAborted,
224 BrokenPipe,
225 Unexpected,
226};
227
228/// Returns the number of bytes that were read, which can be less than
229/// buf.len. If 0 bytes were read, that means EOF.
230/// This function is for blocking file descriptors only. For non-blocking, see
231/// `readAsync`.
232pub fn read(fd: FileHandle, buf: []u8) ReadError!usize {
233 if (windows.is_the_target and !builtin.link_libc) {
234 var index: usize = 0;
235 while (index < buffer.len) {
236 const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(math.maxInt(windows.DWORD)), buffer.len - index));
237 var amt_read: windows.DWORD = undefined;
238 if (windows.ReadFile(fd, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
239 const err = windows.GetLastError();
240 return switch (err) {
241 windows.ERROR.OPERATION_ABORTED => continue,
242 windows.ERROR.BROKEN_PIPE => return index,
243 else => unexpectedErrorWindows(err),
244 };
245 }
246 if (amt_read == 0) return index;
247 index += amt_read;
248 }
249 return index;
250 }
251
252 if (wasi.is_the_target and !builtin.link_libc) {
253 const iovs = [1]was.iovec_t{wasi.iovec_t{
254 .buf = buf.ptr,
255 .buf_len = buf.len,
256 }};
257
258 var nread: usize = undefined;
259 switch (fd_read(fd, &iovs, iovs.len, &nread)) {
260 0 => return nread,
261 else => |err| return unexpectedErrno(err),
262 }
263 }
264
265 // Linux can return EINVAL when read amount is > 0x7ffff000
266 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
267 const max_buf_len = 0x7ffff000;
268
269 var index: usize = 0;
270 while (index < buf.len) {
271 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
272 const rc = system.read(fd, buf.ptr + index, want_to_read);
273 switch (system.getErrno(rc)) {
274 0 => {
275 index += rc;
276 if (rc == want_to_read) continue;
277 // Read returned less than buf.len.
278 return index;
279 },
280 EINTR => continue,
281 EINVAL => unreachable,
282 EFAULT => unreachable,
283 EAGAIN => unreachable, // This function is for blocking reads.
284 EBADF => unreachable, // Always a race condition.
285 EIO => return error.InputOutput,
286 EISDIR => return error.IsDir,
287 ENOBUFS => return error.SystemResources,
288 ENOMEM => return error.SystemResources,
289 else => |err| return unexpectedErrno(err),
290 }
291 }
292 return index;
293}
294
295/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
296/// This function is for blocking file descriptors only. For non-blocking, see
297/// `preadvAsync`.
298pub fn preadv(fd: FileHandle, iov: [*]const iovec, count: usize, offset: u64) ReadError!usize {
299 if (os.darwin.is_the_target) {
300 // Darwin does not have preadv but it does have pread.
301 var off: usize = 0;
302 var iov_i: usize = 0;
303 var inner_off: usize = 0;
304 while (true) {
305 const v = iov[iov_i];
306 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
307 const err = darwin.getErrno(rc);
308 switch (err) {
309 0 => {
310 off += rc;
311 inner_off += rc;
312 if (inner_off == v.iov_len) {
313 iov_i += 1;
314 inner_off = 0;
315 if (iov_i == count) {
316 return off;
317 }
318 }
319 if (rc == 0) return off; // EOF
320 continue;
321 },
322 EINTR => continue,
323 EINVAL => unreachable,
324 EFAULT => unreachable,
325 ESPIPE => unreachable, // fd is not seekable
326 EAGAIN => unreachable, // This function is for blocking reads.
327 EBADF => unreachable, // always a race condition
328 EIO => return error.InputOutput,
329 EISDIR => return error.IsDir,
330 ENOBUFS => return error.SystemResources,
331 ENOMEM => return error.SystemResources,
332 else => return unexpectedErrno(err),
333 }
334 }
335 }
336 while (true) {
337 const rc = system.preadv(fd, iov, count, offset);
338 const err = system.getErrno(rc);
339 switch (err) {
340 0 => return rc,
341 EINTR => continue,
342 EINVAL => unreachable,
343 EFAULT => unreachable,
344 EAGAIN => unreachable, // This function is for blocking reads.
345 EBADF => unreachable, // always a race condition
346 EIO => return error.InputOutput,
347 EISDIR => return error.IsDir,
348 ENOBUFS => return error.SystemResources,
349 ENOMEM => return error.SystemResources,
350 else => return unexpectedErrno(err),
351 }
352 }
353}
354
355pub const WriteError = error{
356 DiskQuota,
357 FileTooBig,
358 InputOutput,
359 NoSpaceLeft,
360 AccessDenied,
361 BrokenPipe,
362 SystemResources,
363 OperationAborted,
364 Unexpected,
365};
366
367/// Write to a file descriptor. Keeps trying if it gets interrupted.
368/// This function is for blocking file descriptors only. For non-blocking, see
369/// `writeAsync`.
370pub fn write(fd: FileHandle, bytes: []const u8) WriteError!void {
371 if (windows.is_the_target and !builtin.link_libc) {
372 var bytes_written: windows.DWORD = undefined;
373 // TODO replace this @intCast with a loop that writes all the bytes
374 if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
375 switch (windows.GetLastError()) {
376 windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources,
377 windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
378 windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
379 windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
380 windows.ERROR.IO_PENDING => unreachable,
381 windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
382 else => |err| return unexpectedErrorWindows(err),
383 }
384 }
385 }
386
387 if (wasi.is_the_target and !builtin.link_libc) {
388 const ciovs = [1]wasi.ciovec_t{wasi.ciovec_t{
389 .buf = bytes.ptr,
390 .buf_len = bytes.len,
391 }};
392 var nwritten: usize = undefined;
393 switch (fd_write(fd, &ciovs, ciovs.len, &nwritten)) {
394 0 => return,
395 else => |err| return unexpectedErrno(err),
396 }
397 }
398
399 // Linux can return EINVAL when write amount is > 0x7ffff000
400 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
401 const max_bytes_len = 0x7ffff000;
402
403 var index: usize = 0;
404 while (index < bytes.len) {
405 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
406 const rc = system.write(fd, bytes.ptr + index, amt_to_write);
407 const write_err = system.getErrno(rc);
408 switch (write_err) {
409 0 => {
410 index += rc;
411 continue;
412 },
413 EINTR => continue,
414 EINVAL => unreachable,
415 EFAULT => unreachable,
416 EAGAIN => unreachable, // This function is for blocking writes.
417 EBADF => unreachable, // Always a race condition.
418 EDESTADDRREQ => unreachable, // `connect` was never called.
419 EDQUOT => return error.DiskQuota,
420 EFBIG => return error.FileTooBig,
421 EIO => return error.InputOutput,
422 ENOSPC => return error.NoSpaceLeft,
423 EPERM => return error.AccessDenied,
424 EPIPE => return error.BrokenPipe,
425 else => return unexpectedErrno(write_err),
426 }
427 }
428}
429
430/// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted.
431/// This function is for blocking file descriptors only. For non-blocking, see
432/// `pwritevAsync`.
433pub fn pwritev(fd: FileHandle, iov: [*]const iovec_const, count: usize, offset: u64) WriteError!void {
434 if (darwin.is_the_target) {
435 // Darwin does not have pwritev but it does have pwrite.
436 var off: usize = 0;
437 var iov_i: usize = 0;
438 var inner_off: usize = 0;
439 while (true) {
440 const v = iov[iov_i];
441 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
442 const err = darwin.getErrno(rc);
443 switch (err) {
444 0 => {
445 off += rc;
446 inner_off += rc;
447 if (inner_off == v.iov_len) {
448 iov_i += 1;
449 inner_off = 0;
450 if (iov_i == count) {
451 return;
452 }
453 }
454 continue;
455 },
456 EINTR => continue,
457 ESPIPE => unreachable, // `fd` is not seekable.
458 EINVAL => unreachable,
459 EFAULT => unreachable,
460 EAGAIN => unreachable, // This function is for blocking writes.
461 EBADF => unreachable, // Always a race condition.
462 EDESTADDRREQ => unreachable, // `connect` was never called.
463 EDQUOT => return error.DiskQuota,
464 EFBIG => return error.FileTooBig,
465 EIO => return error.InputOutput,
466 ENOSPC => return error.NoSpaceLeft,
467 EPERM => return error.AccessDenied,
468 EPIPE => return error.BrokenPipe,
469 else => return unexpectedErrno(err),
470 }
471 }
472 }
473
474 while (true) {
475 const rc = system.pwritev(fd, iov, count, offset);
476 const err = system.getErrno(rc);
477 switch (err) {
478 0 => return,
479 EINTR => continue,
480 EINVAL => unreachable,
481 EFAULT => unreachable,
482 EAGAIN => unreachable, // This function is for blocking writes.
483 EBADF => unreachable, // Always a race condition.
484 EDESTADDRREQ => unreachable, // `connect` was never called.
485 EDQUOT => return error.DiskQuota,
486 EFBIG => return error.FileTooBig,
487 EIO => return error.InputOutput,
488 ENOSPC => return error.NoSpaceLeft,
489 EPERM => return error.AccessDenied,
490 EPIPE => return error.BrokenPipe,
491 else => return unexpectedErrno(err),
492 }
493 }
494}
495
496pub const OpenError = error{
497 AccessDenied,
498 FileTooBig,
499 IsDir,
500 SymLinkLoop,
501 ProcessFdQuotaExceeded,
502 NameTooLong,
503 SystemFdQuotaExceeded,
504 NoDevice,
505 FileNotFound,
506 SystemResources,
507 NoSpaceLeft,
508 NotDir,
509 PathAlreadyExists,
510 DeviceBusy,
511 Unexpected,
512};
513
514/// Open and possibly create a file. Keeps trying if it gets interrupted.
515/// `file_path` needs to be copied in memory to add a null terminating byte.
516/// See also `openC`.
517pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!FileHandle {
518 const file_path_c = try toPosixPath(file_path);
519 return openC(&file_path_c, flags, perm);
520}
521
522/// Open and possibly create a file. Keeps trying if it gets interrupted.
523/// See also `open`.
524/// TODO https://github.com/ziglang/zig/issues/265
525pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!FileHandle {
526 while (true) {
527 const rc = system.open(file_path, flags, perm);
528 switch (system.getErrno(rc)) {
529 0 => return @intCast(FileHandle, rc),
530 EINTR => continue,
531
532 EFAULT => unreachable,
533 EINVAL => unreachable,
534 EACCES => return error.AccessDenied,
535 EFBIG => return error.FileTooBig,
536 EOVERFLOW => return error.FileTooBig,
537 EISDIR => return error.IsDir,
538 ELOOP => return error.SymLinkLoop,
539 EMFILE => return error.ProcessFdQuotaExceeded,
540 ENAMETOOLONG => return error.NameTooLong,
541 ENFILE => return error.SystemFdQuotaExceeded,
542 ENODEV => return error.NoDevice,
543 ENOENT => return error.FileNotFound,
544 ENOMEM => return error.SystemResources,
545 ENOSPC => return error.NoSpaceLeft,
546 ENOTDIR => return error.NotDir,
547 EPERM => return error.AccessDenied,
548 EEXIST => return error.PathAlreadyExists,
549 EBUSY => return error.DeviceBusy,
550 else => |err| return unexpectedErrno(err),
551 }
552 }
553}
554
555pub const WindowsOpenError = error{
556 SharingViolation,
557 PathAlreadyExists,
558
559 /// When any of the path components can not be found or the file component can not
560 /// be found. Some operating systems distinguish between path components not found and
561 /// file components not found, but they are collapsed into FileNotFound to gain
562 /// consistency across operating systems.
563 FileNotFound,
564
565 AccessDenied,
566 PipeBusy,
567 NameTooLong,
568
569 /// On Windows, file paths must be valid Unicode.
570 InvalidUtf8,
571
572 /// On Windows, file paths cannot contain these characters:
573 /// '/', '*', '?', '"', '<', '>', '|'
574 BadPathName,
575
576 Unexpected,
577};
578
579pub fn openWindows(
580 file_path: []const u8,
581 desired_access: windows.DWORD,
582 share_mode: windows.DWORD,
583 creation_disposition: windows.DWORD,
584 flags_and_attrs: windows.DWORD,
585) WindowsOpenError!FileHandle {
586 const file_path_w = try sliceToPrefixedFileW(file_path);
587 return openW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
588}
589
590pub fn openW(
591 file_path_w: [*]const u16,
592 desired_access: windows.DWORD,
593 share_mode: windows.DWORD,
594 creation_disposition: windows.DWORD,
595 flags_and_attrs: windows.DWORD,
596) WindowsOpenError!windows.HANDLE {
597 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
598
599 if (result == windows.INVALID_HANDLE_VALUE) {
600 const err = windows.GetLastError();
601 switch (err) {
602 windows.ERROR.SHARING_VIOLATION => return error.SharingViolation,
603 windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
604 windows.ERROR.FILE_EXISTS => return error.PathAlreadyExists,
605 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
606 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
607 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
608 windows.ERROR.PIPE_BUSY => return error.PipeBusy,
609 else => return unexpectedErrorWindows(err),
610 }
611 }
612
613 return result;
614}
615
616pub fn dup2(old_fd: FileHandle, new_fd: FileHandle) !void {
617 while (true) {
618 switch (system.getErrno(system.dup2(old_fd, new_fd))) {
619 0 => return,
620 EBUSY, EINTR => continue,
621 EMFILE => return error.ProcessFdQuotaExceeded,
622 EINVAL => unreachable,
623 else => |err| return unexpectedErrno(err),
624 }
625 }
626}
627
628/// This function must allocate memory to add a null terminating bytes on path and each arg.
629/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
630/// pointers after the args and after the environment variables.
631/// `argv[0]` is the executable path.
632/// This function also uses the PATH environment variable to get the full path to the executable.
633pub fn execve(allocator: *Allocator, argv: []const []const u8, env_map: *const BufMap) !void {
634 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
635 mem.set(?[*]u8, argv_buf, null);
636 defer {
637 for (argv_buf) |arg| {
638 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
639 allocator.free(arg_buf);
640 }
641 allocator.free(argv_buf);
642 }
643 for (argv) |arg, i| {
644 const arg_buf = try allocator.alloc(u8, arg.len + 1);
645 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
646 arg_buf[arg.len] = 0;
647
648 argv_buf[i] = arg_buf.ptr;
649 }
650 argv_buf[argv.len] = null;
651
652 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
653 defer freeNullDelimitedEnvMap(allocator, envp_buf);
654
655 const exe_path = argv[0];
656 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
657 return execveErrnoToErr(system.getErrno(system.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
658 }
659
660 const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
661 // PATH.len because it is >= the largest search_path
662 // +1 for the / to join the search path and exe_path
663 // +1 for the null terminating byte
664 const path_buf = try allocator.alloc(u8, PATH.len + exe_path.len + 2);
665 defer allocator.free(path_buf);
666 var it = mem.tokenize(PATH, ":");
667 var seen_eacces = false;
668 var err: usize = undefined;
669 while (it.next()) |search_path| {
670 mem.copy(u8, path_buf, search_path);
671 path_buf[search_path.len] = '/';
672 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
673 path_buf[search_path.len + exe_path.len + 1] = 0;
674 err = system.getErrno(system.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
675 assert(err > 0);
676 if (err == EACCES) {
677 seen_eacces = true;
678 } else if (err != ENOENT) {
679 return execveErrnoToErr(err);
680 }
681 }
682 if (seen_eacces) {
683 err = EACCES;
684 }
685 return execveErrnoToErr(err);
686}
687
688pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
689 const envp_count = env_map.count();
690 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
691 mem.set(?[*]u8, envp_buf, null);
692 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
693 {
694 var it = env_map.iterator();
695 var i: usize = 0;
696 while (it.next()) |pair| : (i += 1) {
697 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
698 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
699 env_buf[pair.key.len] = '=';
700 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
701 env_buf[env_buf.len - 1] = 0;
702
703 envp_buf[i] = env_buf.ptr;
704 }
705 assert(i == envp_count);
706 }
707 assert(envp_buf[envp_count] == null);
708 return envp_buf;
709}
710
711pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
712 for (envp_buf) |env| {
713 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
714 allocator.free(env_buf);
715 }
716 allocator.free(envp_buf);
717}
718
719pub const ExecveError = error{
720 SystemResources,
721 AccessDenied,
722 InvalidExe,
723 FileSystem,
724 IsDir,
725 FileNotFound,
726 NotDir,
727 FileBusy,
728
729 Unexpected,
730};
731
732fn execveErrnoToErr(err: usize) ExecveError {
733 assert(err > 0);
734 switch (err) {
735 EFAULT => unreachable,
736 E2BIG => return error.SystemResources,
737 EMFILE => return error.ProcessFdQuotaExceeded,
738 ENAMETOOLONG => return error.NameTooLong,
739 ENFILE => return error.SystemFdQuotaExceeded,
740 ENOMEM => return error.SystemResources,
741 EACCES => return error.AccessDenied,
742 EPERM => return error.AccessDenied,
743 EINVAL => return error.InvalidExe,
744 ENOEXEC => return error.InvalidExe,
745 EIO => return error.FileSystem,
746 ELOOP => return error.FileSystem,
747 EISDIR => return error.IsDir,
748 ENOENT => return error.FileNotFound,
749 ENOTDIR => return error.NotDir,
750 ETXTBSY => return error.FileBusy,
751 else => return unexpectedErrno(err),
752 }
753}
754
755/// Get an environment variable.
756/// See also `getenvC`.
757/// TODO make this go through libc when we have it
758pub fn getenv(key: []const u8) ?[]const u8 {
759 for (environ) |ptr| {
760 var line_i: usize = 0;
761 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
762 const this_key = ptr[0..line_i];
763 if (!mem.eql(u8, key, this_key)) continue;
764
765 var end_i: usize = line_i;
766 while (ptr[end_i] != 0) : (end_i += 1) {}
767 const this_value = ptr[line_i + 1 .. end_i];
768
769 return this_value;
770 }
771 return null;
772}
773
774/// Get an environment variable with a null-terminated name.
775/// See also `getenv`.
776/// TODO https://github.com/ziglang/zig/issues/265
777pub fn getenvC(key: [*]const u8) ?[]const u8 {
778 if (builtin.link_libc) {
779 const value = std.c.getenv(key) orelse return null;
780 return mem.toSliceConst(u8, value);
781 }
782 return getenv(mem.toSliceConst(u8, key));
783}
784
785/// See std.elf for the constants.
786pub fn getauxval(index: usize) usize {
787 if (builtin.link_libc) {
788 return usize(std.c.getauxval(index));
789 } else if (linux.elf_aux_maybe) |auxv| {
790 var i: usize = 0;
791 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
792 if (auxv[i].a_type == index)
793 return auxv[i].a_un.a_val;
794 }
795 }
796 return 0;
797}
798
799pub const GetCwdError = error{
800 NameTooLong,
801 CurrentWorkingDirectoryUnlinked,
802 Unexpected,
803};
804
805/// The result is a slice of out_buffer, indexed from 0.
806pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
807 if (windows.is_the_target and !builtin.link_libc) {
808 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
809 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
810 const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
811 const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
812 if (result == 0) {
813 const err = windows.GetLastError();
814 switch (err) {
815 else => return unexpectedErrorWindows(err),
816 }
817 }
818 assert(result <= utf16le_buf.len);
819 const utf16le_slice = utf16le_buf[0..result];
820 // Trust that Windows gives us valid UTF-16LE.
821 var end_index: usize = 0;
822 var it = std.unicode.Utf16LeIterator.init(utf16le);
823 while (it.nextCodepoint() catch unreachable) |codepoint| {
824 if (end_index + std.unicode.utf8CodepointSequenceLength(codepoint) >= out_buffer.len)
825 return error.NameTooLong;
826 end_index += utf8Encode(codepoint, out_buffer[end_index..]) catch unreachable;
827 }
828 return out_buffer[0..end_index];
829 }
830
831 const err = if (builtin.link_libc) blk: {
832 break :blk if (std.c.getcwd(out_buffer.ptr, out_buffer.len)) |_| 0 else std.c._errno().*;
833 } else blk: {
834 break :blk system.getErrno(system.getcwd(out_buffer, out_buffer.len));
835 };
836 switch (err) {
837 0 => return mem.toSlice(u8, out_buffer),
838 EFAULT => unreachable,
839 EINVAL => unreachable,
840 ENOENT => return error.CurrentWorkingDirectoryUnlinked,
841 ERANGE => return error.NameTooLong,
842 else => |err| return unexpectedErrno(err),
843 }
844}
845
846test "getcwd" {
847 // at least call it so it gets compiled
848 var buf: [os.MAX_PATH_BYTES]u8 = undefined;
849 _ = getcwd(&buf) catch {};
850}
851
852pub const SymLinkError = error{
853 AccessDenied,
854 DiskQuota,
855 PathAlreadyExists,
856 FileSystem,
857 SymLinkLoop,
858 FileNotFound,
859 SystemResources,
860 NoSpaceLeft,
861 ReadOnlyFileSystem,
862 NotDir,
863 NameTooLong,
864 InvalidUtf8,
865 BadPathName,
866 Unexpected,
867};
868
869/// Creates a symbolic link named `new_path` which contains the string `target_path`.
870/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
871/// one; the latter case is known as a dangling link.
872/// If `new_path` exists, it will not be overwritten.
873/// See also `symlinkC` and `symlinkW`.
874pub fn symlink(target_path: []const u8, new_path: []const u8) SymLinkError!void {
875 if (windows.is_the_target and !builtin.link_libc) {
876 const target_path_w = try cStrToPrefixedFileW(target_path);
877 const new_path_w = try cStrToPrefixedFileW(new_path);
878 return symlinkW(&target_path_w, &new_path_w);
879 } else {
880 const target_path_c = try toPosixPath(target_path);
881 const new_path_c = try toPosixPath(new_path);
882 return symlinkC(&target_path_c, &new_path_c);
883 }
884}
885
886pub fn symlinkat(target_path: []const u8, newdirfd: FileHandle, new_path: []const u8) SymLinkError!void {
887 const target_path_c = try toPosixPath(target_path);
888 const new_path_c = try toPosixPath(new_path);
889 return symlinkatC(target_path_c, newdirfd, new_path_c);
890}
891
892pub fn symlinkatC(target_path: [*]const u8, newdirfd: FileHandle, new_path: [*]const u8) SymLinkError!void {
893 const err = blk: {
894 if (builtin.link_libc) {
895 break :blk if (std.c.symlinkat(target_path, newdirfd, new_path) == -1) errno().* else 0;
896 } else {
897 break :blk system.getErrno(system.symlinkat(target_path, newdirfd, new_path));
898 }
899 };
900 switch (err) {
901 0 => return,
902 EFAULT => unreachable,
903 EINVAL => unreachable,
904 EACCES => return error.AccessDenied,
905 EPERM => return error.AccessDenied,
906 EDQUOT => return error.DiskQuota,
907 EEXIST => return error.PathAlreadyExists,
908 EIO => return error.FileSystem,
909 ELOOP => return error.SymLinkLoop,
910 ENAMETOOLONG => return error.NameTooLong,
911 ENOENT => return error.FileNotFound,
912 ENOTDIR => return error.NotDir,
913 ENOMEM => return error.SystemResources,
914 ENOSPC => return error.NoSpaceLeft,
915 EROFS => return error.ReadOnlyFileSystem,
916 else => return unexpectedErrno(err),
917 }
918}
919
920/// This is the same as `symlink` except the parameters are null-terminated pointers.
921/// See also `symlink` and `symlinkW`.
922pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!void {
923 if (windows.is_the_target and !builtin.link_libc) {
924 const target_path_w = try cStrToPrefixedFileW(target_path);
925 const new_path_w = try cStrToPrefixedFileW(new_path);
926 return symlinkW(&target_path_w, &new_path_w);
927 }
928 const err = if (builtin.link_libc) blk: {
929 break :blk if (std.c.symlink(target_path, new_path) == -1) errno().* else 0;
930 } else if (@hasDecl(system, "symlink")) blk: {
931 break :blk system.getErrno(system.symlink(target_path, new_path));
932 } else blk: {
933 break :blk system.getErrno(system.symlinkat(target_path, AT_FDCWD, new_path));
934 };
935 switch (err) {
936 0 => return,
937 EFAULT => unreachable,
938 EINVAL => unreachable,
939 EACCES => return error.AccessDenied,
940 EPERM => return error.AccessDenied,
941 EDQUOT => return error.DiskQuota,
942 EEXIST => return error.PathAlreadyExists,
943 EIO => return error.FileSystem,
944 ELOOP => return error.SymLinkLoop,
945 ENAMETOOLONG => return error.NameTooLong,
946 ENOENT => return error.FileNotFound,
947 ENOTDIR => return error.NotDir,
948 ENOMEM => return error.SystemResources,
949 ENOSPC => return error.NoSpaceLeft,
950 EROFS => return error.ReadOnlyFileSystem,
951 else => return unexpectedErrno(err),
952 }
953}
954
955/// This is the same as `symlink` except the parameters are null-terminated pointers to
956/// UTF-16LE encoded strings.
957/// See also `symlink` and `symlinkC`.
958/// TODO handle when linking libc
959pub fn symlinkW(target_path_w: [*]const u16, new_path_w: [*]const u16) SymLinkError!void {
960 if (windows.CreateSymbolicLinkW(target_path_w, new_path_w, 0) == 0) {
961 const err = windows.GetLastError();
962 switch (err) {
963 else => return unexpectedErrorWindows(err),
964 }
965 }
966}
967
968pub const UnlinkError = error{
969 FileNotFound,
970 AccessDenied,
971 FileBusy,
972 FileSystem,
973 IsDir,
974 SymLinkLoop,
975 NameTooLong,
976 NotDir,
977 SystemResources,
978 ReadOnlyFileSystem,
979 Unexpected,
980
981 /// On Windows, file paths must be valid Unicode.
982 InvalidUtf8,
983
984 /// On Windows, file paths cannot contain these characters:
985 /// '/', '*', '?', '"', '<', '>', '|'
986 BadPathName,
987};
988
989/// Delete a name and possibly the file it refers to.
990pub fn unlink(file_path: []const u8) UnlinkError!void {
991 if (windows.is_the_target and !builtin.link_libc) {
992 const file_path_w = try sliceToPrefixedFileW(file_path);
993 return unlinkW(&file_path_w);
994 } else {
995 const file_path_c = try toPosixPath(file_path);
996 return unlinkC(&file_path_c);
997 }
998}
999
1000/// Same as `unlink` except the parameter is a UTF16LE-encoded string.
1001/// TODO handle when linking libc
1002pub fn unlinkW(file_path: [*]const u16) UnlinkError!void {
1003 if (windows.unlinkW(file_path) == 0) {
1004 const err = windows.GetLastError();
1005 switch (err) {
1006 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1007 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1008 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1009 windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
1010 else => return unexpectedErrorWindows(err),
1011 }
1012 }
1013}
1014
1015/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
1016pub fn unlinkC(file_path: [*]const u8) UnlinkError!void {
1017 if (windows.is_the_target and !builtin.link_libc) {
1018 const file_path_w = try cStrToPrefixedFileW(file_path);
1019 return unlinkW(&file_path_w);
1020 }
1021 const err = if (builtin.link_libc) blk: {
1022 break :blk if (std.c.unlink(file_path) == -1) errno().* else 0;
1023 } else if (@hasDecl(system, "unlink")) blk: {
1024 break :blk system.getErrno(system.unlink(file_path));
1025 } else blk: {
1026 break :blk system.getErrno(system.unlinkat(AT_FDCWD, file_path, 0));
1027 };
1028 switch (err) {
1029 0 => return,
1030 EACCES => return error.AccessDenied,
1031 EPERM => return error.AccessDenied,
1032 EBUSY => return error.FileBusy,
1033 EFAULT => unreachable,
1034 EINVAL => unreachable,
1035 EIO => return error.FileSystem,
1036 EISDIR => return error.IsDir,
1037 ELOOP => return error.SymLinkLoop,
1038 ENAMETOOLONG => return error.NameTooLong,
1039 ENOENT => return error.FileNotFound,
1040 ENOTDIR => return error.NotDir,
1041 ENOMEM => return error.SystemResources,
1042 EROFS => return error.ReadOnlyFileSystem,
1043 else => return unexpectedErrno(err),
1044 }
1045}
1046
1047const RenameError = error{}; // TODO
1048
1049/// Change the name or location of a file.
1050pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
1051 if (windows.is_the_target and !builtin.link_libc) {
1052 const old_path_w = try sliceToPrefixedFileW(old_path);
1053 const new_path_w = try sliceToPrefixedFileW(new_path);
1054 return renameW(&old_path_w, &new_path_w);
1055 } else {
1056 const old_path_c = try toPosixPath(old_path);
1057 const new_path_c = try toPosixPath(new_path);
1058 return renameC(&old_path_c, &new_path_c);
1059 }
1060}
1061
1062/// Same as `rename` except the parameters are null-terminated byte arrays.
1063pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
1064 if (windows.is_the_target and !builtin.link_libc) {
1065 const old_path_w = try cStrToPrefixedFileW(old_path);
1066 const new_path_w = try cStrToPrefixedFileW(new_path);
1067 return renameW(&old_path_w, &new_path_w);
1068 }
1069 const err = if (builtin.link_libc) blk: {
1070 break :blk if (std.c.rename(old_path, new_path) == -1) errno().* else 0;
1071 } else if (@hasDecl(system, "rename")) blk: {
1072 break :blk system.getErrno(system.rename(old_path, new_path));
1073 } else if (@hasDecl(system, "renameat")) blk: {
1074 break :blk system.getErrno(system.renameat(AT_FDCWD, old_path, AT_FDCWD, new_path));
1075 } else blk: {
1076 break :blk system.getErrno(system.renameat2(AT_FDCWD, old_path, AT_FDCWD, new_path, 0));
1077 };
1078 switch (err) {
1079 0 => return,
1080 EACCES => return error.AccessDenied,
1081 EPERM => return error.AccessDenied,
1082 EBUSY => return error.FileBusy,
1083 EDQUOT => return error.DiskQuota,
1084 EFAULT => unreachable,
1085 EINVAL => unreachable,
1086 EISDIR => return error.IsDir,
1087 ELOOP => return error.SymLinkLoop,
1088 EMLINK => return error.LinkQuotaExceeded,
1089 ENAMETOOLONG => return error.NameTooLong,
1090 ENOENT => return error.FileNotFound,
1091 ENOTDIR => return error.NotDir,
1092 ENOMEM => return error.SystemResources,
1093 ENOSPC => return error.NoSpaceLeft,
1094 EEXIST => return error.PathAlreadyExists,
1095 ENOTEMPTY => return error.PathAlreadyExists,
1096 EROFS => return error.ReadOnlyFileSystem,
1097 EXDEV => return error.RenameAcrossMountPoints,
1098 else => return unexpectedErrno(err),
1099 }
1100}
1101
1102/// Same as `rename` except the parameters are null-terminated UTF16LE-encoded strings.
1103/// TODO handle when linking libc
1104pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
1105 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
1106 if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
1107 const err = windows.GetLastError();
1108 switch (err) {
1109 else => return unexpectedErrorWindows(err),
1110 }
1111 }
1112}
1113
1114pub const MakeDirError = error{};
1115
1116/// Create a directory.
1117/// `mode` is ignored on Windows.
1118pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
1119 if (windows.is_the_target and !builtin.link_libc) {
1120 const dir_path_w = try sliceToPrefixedFileW(dir_path);
1121 return mkdirW(&dir_path_w, mode);
1122 } else {
1123 const dir_path_c = try toPosixPath(dir_path);
1124 return mkdirC(&dir_path_c, mode);
1125 }
1126}
1127
1128/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
1129pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void {
1130 if (windows.is_the_target and !builtin.link_libc) {
1131 const dir_path_w = try cStrToPrefixedFileW(dir_path);
1132 return mkdirW(&dir_path_w, mode);
1133 }
1134 const err = if (builtin.link_libc) blk: {
1135 break :blk if (std.c.mkdir(dir_path, mode) == -1) errno().* else 0;
1136 } else if (@hasDecl(system, "mkdir")) blk: {
1137 break :blk system.getErrno(system.mkdir(dir_path, mode));
1138 } else blk: {
1139 break :blk system.getErrno(system.mkdirat(AT_FDCWD, dir_path, mode));
1140 };
1141 switch (err) {
1142 0 => return,
1143 EACCES => return error.AccessDenied,
1144 EPERM => return error.AccessDenied,
1145 EDQUOT => return error.DiskQuota,
1146 EEXIST => return error.PathAlreadyExists,
1147 EFAULT => unreachable,
1148 ELOOP => return error.SymLinkLoop,
1149 EMLINK => return error.LinkQuotaExceeded,
1150 ENAMETOOLONG => return error.NameTooLong,
1151 ENOENT => return error.FileNotFound,
1152 ENOMEM => return error.SystemResources,
1153 ENOSPC => return error.NoSpaceLeft,
1154 ENOTDIR => return error.NotDir,
1155 EROFS => return error.ReadOnlyFileSystem,
1156 else => return unexpectedErrno(err),
1157 }
1158}
1159
1160/// Same as `mkdir` but the parameter is a null-terminated UTF16LE-encoded string.
1161pub fn mkdirW(dir_path: []const u8, mode: u32) MakeDirError!void {
1162 const dir_path_w = try sliceToPrefixedFileW(dir_path);
1163
1164 if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
1165 const err = windows.GetLastError();
1166 switch (err) {
1167 windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
1168 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1169 else => return unexpectedErrorWindows(err),
1170 }
1171 }
1172}
1173
1174pub const DeleteDirError = error{
1175 AccessDenied,
1176 FileBusy,
1177 SymLinkLoop,
1178 NameTooLong,
1179 FileNotFound,
1180 SystemResources,
1181 NotDir,
1182 DirNotEmpty,
1183 ReadOnlyFileSystem,
1184 InvalidUtf8,
1185 BadPathName,
1186 Unexpected,
1187};
1188
1189/// Deletes an empty directory.
1190pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
1191 if (windows.is_the_target and !builtin.link_libc) {
1192 const dir_path_w = try sliceToPrefixedFileW(dir_path);
1193 return rmdirW(&dir_path_w);
1194 } else {
1195 const dir_path_c = try toPosixPath(dir_path);
1196 return rmdirC(&dir_path_c);
1197 }
1198}
1199
1200/// Same as `rmdir` except the parameter is a null-terminated UTF8-encoded string.
1201pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void {
1202 if (windows.is_the_target and !builtin.link_libc) {
1203 const dir_path_w = try cStrToPrefixedFileW(dir_path);
1204 return rmdirW(&dir_path_w);
1205 }
1206 const err = if (builtin.link_libc) blk: {
1207 break :blk if (std.c.rmdir(dir_path) == -1) errno().* else 0;
1208 } else if (@hasDecl(system, "rmdir")) blk: {
1209 break :blk system.getErrno(system.rmdir(dir_path));
1210 } else blk: {
1211 break :blk system.getErrno(system.unlinkat(AT_FDCWD, dir_path, AT_REMOVEDIR));
1212 };
1213 switch (err) {
1214 0 => return,
1215 EACCES => return error.AccessDenied,
1216 EPERM => return error.AccessDenied,
1217 EBUSY => return error.FileBusy,
1218 EFAULT => unreachable,
1219 EINVAL => unreachable,
1220 ELOOP => return error.SymLinkLoop,
1221 ENAMETOOLONG => return error.NameTooLong,
1222 ENOENT => return error.FileNotFound,
1223 ENOMEM => return error.SystemResources,
1224 ENOTDIR => return error.NotDir,
1225 EEXIST => return error.DirNotEmpty,
1226 ENOTEMPTY => return error.DirNotEmpty,
1227 EROFS => return error.ReadOnlyFileSystem,
1228 else => return unexpectedErrno(err),
1229 }
1230}
1231
1232/// Same as `rmdir` except the parameter is a null-terminated UTF16LE-encoded string.
1233/// TODO handle linking libc
1234pub fn rmdirW(dir_path_w: [*]const u16) DeleteDirError!void {
1235 if (windows.RemoveDirectoryW(dir_path_w) == 0) {
1236 const err = windows.GetLastError();
1237 switch (err) {
1238 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1239 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1240 else => return unexpectedErrorWindows(err),
1241 }
1242 }
1243}
1244
1245pub const ChangeCurDirError = error{};
1246
1247/// Changes the current working directory of the calling process.
1248/// `dir_path` is recommended to be a UTF-8 encoded string.
1249pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
1250 if (windows.is_the_target and !builtin.link_libc) {
1251 const dir_path_w = try sliceToPrefixedFileW(dir_path);
1252 return chdirW(&dir_path_w);
1253 } else {
1254 const dir_path_c = try toPosixPath(dir_path);
1255 return chdirC(&dir_path_c);
1256 }
1257}
1258
1259/// Same as `chdir` except the parameter is null-terminated.
1260pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void {
1261 if (windows.is_the_target and !builtin.link_libc) {
1262 const dir_path_w = try cStrToPrefixedFileW(dir_path);
1263 return chdirW(&dir_path_w);
1264 }
1265 const err = if (builtin.link_libc) blk: {
1266 break :blk if (std.c.chdir(dir_path) == -1) errno().* else 0;
1267 } else blk: {
1268 break :blk system.getErrno(system.chdir(dir_path));
1269 };
1270 switch (err) {
1271 0 => return,
1272 EACCES => return error.AccessDenied,
1273 EFAULT => unreachable,
1274 EIO => return error.FileSystem,
1275 ELOOP => return error.SymLinkLoop,
1276 ENAMETOOLONG => return error.NameTooLong,
1277 ENOENT => return error.FileNotFound,
1278 ENOMEM => return error.SystemResources,
1279 ENOTDIR => return error.NotDir,
1280 else => return unexpectedErrno(err),
1281 }
1282}
1283
1284/// Same as `chdir` except the parameter is a null-terminated, UTF16LE-encoded string.
1285/// TODO handle linking libc
1286pub fn chdirW(dir_path: [*]const u16) ChangeCurDirError!void {
1287 @compileError("TODO implement chdir for Windows");
1288}
1289
1290pub const ReadLinkError = error{};
1291
1292/// Read value of a symbolic link.
1293/// The return value is a slice of `out_buffer` from index 0.
1294pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
1295 if (windows.is_the_target and !builtin.link_libc) {
1296 const file_path_w = try sliceToPrefixedFileW(file_path);
1297 return readlinkW(&file_path_w, out_buffer);
1298 } else {
1299 const file_path_c = try toPosixPath(file_path);
1300 return readlinkC(&file_path_c, out_buffer);
1301 }
1302}
1303
1304/// Same as `readlink` except `file_path` is null-terminated.
1305pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
1306 if (windows.is_the_target and !builtin.link_libc) {
1307 const file_path_w = try cStrToPrefixedFileW(file_path);
1308 return readlinkW(&file_path_w, out_buffer);
1309 }
1310 const err = if (builtin.link_libc) blk: {
1311 break :blk if (std.c.readlink(file_path, out_buffer.ptr, out_buffer.len) == -1) errno().* else 0;
1312 } else if (@hasDecl(system, "readlink")) blk: {
1313 break :blk system.getErrno(system.readlink(file_path, out_buffer.ptr, out_buffer.len));
1314 } else blk: {
1315 break :blk system.getErrno(system.readlinkat(AT_FDCWD, file_path, out_buffer.ptr, out_buffer.len));
1316 };
1317 const rc = system.readlink(file_path, out_buffer, out_buffer.len);
1318 switch (system.getErrno(rc)) {
1319 0 => return out_buffer[0..rc],
1320 EACCES => return error.AccessDenied,
1321 EFAULT => unreachable,
1322 EINVAL => unreachable,
1323 EIO => return error.FileSystem,
1324 ELOOP => return error.SymLinkLoop,
1325 ENAMETOOLONG => return error.NameTooLong,
1326 ENOENT => return error.FileNotFound,
1327 ENOMEM => return error.SystemResources,
1328 ENOTDIR => return error.NotDir,
1329 else => |err| return unexpectedErrno(err),
1330 }
1331}
1332
1333pub const SetIdError = error{
1334 ResourceLimitReached,
1335 InvalidUserId,
1336 PermissionDenied,
1337 Unexpected,
1338};
1339
1340pub fn setuid(uid: u32) SetIdError!void {
1341 switch (system.getErrno(system.setuid(uid))) {
1342 0 => return,
1343 EAGAIN => return error.ResourceLimitReached,
1344 EINVAL => return error.InvalidUserId,
1345 EPERM => return error.PermissionDenied,
1346 else => |err| return unexpectedErrno(err),
1347 }
1348}
1349
1350pub fn setreuid(ruid: u32, euid: u32) SetIdError!void {
1351 switch (system.getErrno(system.setreuid(ruid, euid))) {
1352 0 => return,
1353 EAGAIN => return error.ResourceLimitReached,
1354 EINVAL => return error.InvalidUserId,
1355 EPERM => return error.PermissionDenied,
1356 else => |err| return unexpectedErrno(err),
1357 }
1358}
1359
1360pub fn setgid(gid: u32) SetIdError!void {
1361 switch (system.getErrno(system.setgid(gid))) {
1362 0 => return,
1363 EAGAIN => return error.ResourceLimitReached,
1364 EINVAL => return error.InvalidUserId,
1365 EPERM => return error.PermissionDenied,
1366 else => |err| return unexpectedErrno(err),
1367 }
1368}
1369
1370pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
1371 switch (system.getErrno(system.setregid(rgid, egid))) {
1372 0 => return,
1373 EAGAIN => return error.ResourceLimitReached,
1374 EINVAL => return error.InvalidUserId,
1375 EPERM => return error.PermissionDenied,
1376 else => |err| return unexpectedErrno(err),
1377 }
1378}
1379
1380pub const GetStdHandleError = error{
1381 NoStandardHandleAttached,
1382 Unexpected,
1383};
1384
1385pub fn GetStdHandle(handle_id: windows.DWORD) GetStdHandleError!FileHandle {
1386 if (windows.is_the_target) {
1387 const handle = windows.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached;
1388 if (handle == windows.INVALID_HANDLE_VALUE) {
1389 switch (windows.GetLastError()) {
1390 else => |err| unexpectedErrorWindows(err),
1391 }
1392 }
1393 return handle;
1394 }
1395
1396 switch (handle_id) {
1397 windows.STD_ERROR_HANDLE => return STDERR_FILENO,
1398 windows.STD_OUTPUT_HANDLE => return STDOUT_FILENO,
1399 windows.STD_INPUT_HANDLE => return STDIN_FILENO,
1400 else => unreachable,
1401 }
1402}
1403
1404/// Test whether a file descriptor refers to a terminal.
1405pub fn isatty(handle: FileHandle) bool {
1406 if (builtin.link_libc) {
1407 return c.isatty(handle) != 0;
1408 }
1409 if (windows.is_the_target) {
1410 if (isCygwinPty(handle))
1411 return true;
1412
1413 var out: windows.DWORD = undefined;
1414 return windows.GetConsoleMode(handle, &out) != 0;
1415 }
1416 if (wasi.is_the_target) {
1417 @compileError("TODO implement std.os.posix.isatty for WASI");
1418 }
1419
1420 var wsz: system.winsize = undefined;
1421 return system.syscall3(system.SYS_ioctl, @bitCast(usize, isize(handle)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
1422}
1423
1424pub fn isCygwinPty(handle: FileHandle) bool {
1425 if (!windows.is_the_target) return false;
1426
1427 const size = @sizeOf(windows.FILE_NAME_INFO);
1428 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
1429
1430 if (windows.GetFileInformationByHandleEx(
1431 handle,
1432 windows.FileNameInfo,
1433 @ptrCast(*c_void, &name_info_bytes[0]),
1434 @intCast(u32, name_info_bytes.len),
1435 ) == 0) {
1436 return false;
1437 }
1438
1439 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
1440 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
1441 const name_wide = @bytesToSlice(u16, name_bytes);
1442 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
1443 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
1444}
1445
1446pub const SocketError = error{
1447 /// Permission to create a socket of the specified type and/or
1448 /// pro‐tocol is denied.
1449 PermissionDenied,
1450
1451 /// The implementation does not support the specified address family.
1452 AddressFamilyNotSupported,
1453
1454 /// Unknown protocol, or protocol family not available.
1455 ProtocolFamilyNotAvailable,
1456
1457 /// The per-process limit on the number of open file descriptors has been reached.
1458 ProcessFdQuotaExceeded,
1459
1460 /// The system-wide limit on the total number of open files has been reached.
1461 SystemFdQuotaExceeded,
1462
1463 /// Insufficient memory is available. The socket cannot be created until sufficient
1464 /// resources are freed.
1465 SystemResources,
1466
1467 /// The protocol type or the specified protocol is not supported within this domain.
1468 ProtocolNotSupported,
1469
1470 Unexpected,
1471};
1472
1473pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 {
1474 const rc = system.socket(domain, socket_type, protocol);
1475 switch (system.getErrno(rc)) {
1476 0 => return @intCast(i32, rc),
1477 EACCES => return error.PermissionDenied,
1478 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1479 EINVAL => return error.ProtocolFamilyNotAvailable,
1480 EMFILE => return error.ProcessFdQuotaExceeded,
1481 ENFILE => return error.SystemFdQuotaExceeded,
1482 ENOBUFS, ENOMEM => return error.SystemResources,
1483 EPROTONOSUPPORT => return error.ProtocolNotSupported,
1484 else => |err| return unexpectedErrno(err),
1485 }
1486}
1487
1488pub const BindError = error{
1489 /// The address is protected, and the user is not the superuser.
1490 /// For UNIX domain sockets: Search permission is denied on a component
1491 /// of the path prefix.
1492 AccessDenied,
1493
1494 /// The given address is already in use, or in the case of Internet domain sockets,
1495 /// The port number was specified as zero in the socket
1496 /// address structure, but, upon attempting to bind to an ephemeral port, it was
1497 /// determined that all port numbers in the ephemeral port range are currently in
1498 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
1499 AddressInUse,
1500
1501 /// A nonexistent interface was requested or the requested address was not local.
1502 AddressNotAvailable,
1503
1504 /// Too many symbolic links were encountered in resolving addr.
1505 SymLinkLoop,
1506
1507 /// addr is too long.
1508 NameTooLong,
1509
1510 /// A component in the directory prefix of the socket pathname does not exist.
1511 FileNotFound,
1512
1513 /// Insufficient kernel memory was available.
1514 SystemResources,
1515
1516 /// A component of the path prefix is not a directory.
1517 NotDir,
1518
1519 /// The socket inode would reside on a read-only filesystem.
1520 ReadOnlyFileSystem,
1521
1522 Unexpected,
1523};
1524
1525/// addr is `*const T` where T is one of the sockaddr
1526pub fn bind(fd: i32, addr: *const sockaddr) BindError!void {
1527 const rc = system.bind(fd, system, @sizeOf(sockaddr));
1528 switch (system.getErrno(rc)) {
1529 0 => return,
1530 EACCES => return error.AccessDenied,
1531 EADDRINUSE => return error.AddressInUse,
1532 EBADF => unreachable, // always a race condition if this error is returned
1533 EINVAL => unreachable,
1534 ENOTSOCK => unreachable,
1535 EADDRNOTAVAIL => return error.AddressNotAvailable,
1536 EFAULT => unreachable,
1537 ELOOP => return error.SymLinkLoop,
1538 ENAMETOOLONG => return error.NameTooLong,
1539 ENOENT => return error.FileNotFound,
1540 ENOMEM => return error.SystemResources,
1541 ENOTDIR => return error.NotDir,
1542 EROFS => return error.ReadOnlyFileSystem,
1543 else => |err| return unexpectedErrno(err),
1544 }
1545}
1546
1547const ListenError = error{
1548 /// Another socket is already listening on the same port.
1549 /// For Internet domain sockets, the socket referred to by sockfd had not previously
1550 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
1551 /// was determined that all port numbers in the ephemeral port range are currently in
1552 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
1553 AddressInUse,
1554
1555 /// The file descriptor sockfd does not refer to a socket.
1556 FileDescriptorNotASocket,
1557
1558 /// The socket is not of a type that supports the listen() operation.
1559 OperationNotSupported,
1560
1561 Unexpected,
1562};
1563
1564pub fn listen(sockfd: i32, backlog: u32) ListenError!void {
1565 const rc = system.listen(sockfd, backlog);
1566 switch (system.getErrno(rc)) {
1567 0 => return,
1568 EADDRINUSE => return error.AddressInUse,
1569 EBADF => unreachable,
1570 ENOTSOCK => return error.FileDescriptorNotASocket,
1571 EOPNOTSUPP => return error.OperationNotSupported,
1572 else => |err| return unexpectedErrno(err),
1573 }
1574}
1575
1576pub const AcceptError = error{
1577 ConnectionAborted,
1578
1579 /// The per-process limit on the number of open file descriptors has been reached.
1580 ProcessFdQuotaExceeded,
1581
1582 /// The system-wide limit on the total number of open files has been reached.
1583 SystemFdQuotaExceeded,
1584
1585 /// Not enough free memory. This often means that the memory allocation is limited
1586 /// by the socket buffer limits, not by the system memory.
1587 SystemResources,
1588
1589 /// The file descriptor sockfd does not refer to a socket.
1590 FileDescriptorNotASocket,
1591
1592 /// The referenced socket is not of type SOCK_STREAM.
1593 OperationNotSupported,
1594
1595 ProtocolFailure,
1596
1597 /// Firewall rules forbid connection.
1598 BlockedByFirewall,
1599
1600 Unexpected,
1601};
1602
1603/// Accept a connection on a socket. `fd` must be opened in blocking mode.
1604/// See also `accept4_async`.
1605pub fn accept4(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
1606 while (true) {
1607 var sockaddr_size = u32(@sizeOf(sockaddr));
1608 const rc = system.accept4(fd, addr, &sockaddr_size, flags);
1609 switch (system.getErrno(rc)) {
1610 0 => return @intCast(i32, rc),
1611 EINTR => continue,
1612 else => |err| return unexpectedErrno(err),
1613
1614 EAGAIN => unreachable, // This function is for blocking only.
1615 EBADF => unreachable, // always a race condition
1616 ECONNABORTED => return error.ConnectionAborted,
1617 EFAULT => unreachable,
1618 EINVAL => unreachable,
1619 EMFILE => return error.ProcessFdQuotaExceeded,
1620 ENFILE => return error.SystemFdQuotaExceeded,
1621 ENOBUFS => return error.SystemResources,
1622 ENOMEM => return error.SystemResources,
1623 ENOTSOCK => return error.FileDescriptorNotASocket,
1624 EOPNOTSUPP => return error.OperationNotSupported,
1625 EPROTO => return error.ProtocolFailure,
1626 EPERM => return error.BlockedByFirewall,
1627 }
1628 }
1629}
1630
1631/// This is the same as `accept4` except `fd` is expected to be non-blocking.
1632/// Returns -1 if would block.
1633pub fn accept4_async(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
1634 while (true) {
1635 var sockaddr_size = u32(@sizeOf(sockaddr));
1636 const rc = system.accept4(fd, addr, &sockaddr_size, flags);
1637 switch (system.getErrno(rc)) {
1638 0 => return @intCast(i32, rc),
1639 EINTR => continue,
1640 else => |err| return unexpectedErrno(err),
1641
1642 EAGAIN => return -1,
1643 EBADF => unreachable, // always a race condition
1644 ECONNABORTED => return error.ConnectionAborted,
1645 EFAULT => unreachable,
1646 EINVAL => unreachable,
1647 EMFILE => return error.ProcessFdQuotaExceeded,
1648 ENFILE => return error.SystemFdQuotaExceeded,
1649 ENOBUFS => return error.SystemResources,
1650 ENOMEM => return error.SystemResources,
1651 ENOTSOCK => return error.FileDescriptorNotASocket,
1652 EOPNOTSUPP => return error.OperationNotSupported,
1653 EPROTO => return error.ProtocolFailure,
1654 EPERM => return error.BlockedByFirewall,
1655 }
1656 }
1657}
1658
1659pub const EpollCreateError = error{
1660 /// The per-user limit on the number of epoll instances imposed by
1661 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
1662 /// details.
1663 /// Or, The per-process limit on the number of open file descriptors has been reached.
1664 ProcessFdQuotaExceeded,
1665
1666 /// The system-wide limit on the total number of open files has been reached.
1667 SystemFdQuotaExceeded,
1668
1669 /// There was insufficient memory to create the kernel object.
1670 SystemResources,
1671
1672 Unexpected,
1673};
1674
1675pub fn epoll_create1(flags: u32) EpollCreateError!i32 {
1676 const rc = system.epoll_create1(flags);
1677 switch (system.getErrno(rc)) {
1678 0 => return @intCast(i32, rc),
1679 else => |err| return unexpectedErrno(err),
1680
1681 EINVAL => unreachable,
1682 EMFILE => return error.ProcessFdQuotaExceeded,
1683 ENFILE => return error.SystemFdQuotaExceeded,
1684 ENOMEM => return error.SystemResources,
1685 }
1686}
1687
1688pub const EpollCtlError = error{
1689 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
1690 /// with this epoll instance.
1691 FileDescriptorAlreadyPresentInSet,
1692
1693 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
1694 /// circular loop of epoll instances monitoring one another.
1695 OperationCausesCircularLoop,
1696
1697 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
1698 /// instance.
1699 FileDescriptorNotRegistered,
1700
1701 /// There was insufficient memory to handle the requested op control operation.
1702 SystemResources,
1703
1704 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
1705 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
1706 /// See epoll(7) for further details.
1707 UserResourceLimitReached,
1708
1709 /// The target file fd does not support epoll. This error can occur if fd refers to,
1710 /// for example, a regular file or a directory.
1711 FileDescriptorIncompatibleWithEpoll,
1712
1713 Unexpected,
1714};
1715
1716pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: *epoll_event) EpollCtlError!void {
1717 const rc = system.epoll_ctl(epfd, op, fd, event);
1718 switch (system.getErrno(rc)) {
1719 0 => return,
1720 else => |err| return unexpectedErrno(err),
1721
1722 EBADF => unreachable, // always a race condition if this happens
1723 EEXIST => return error.FileDescriptorAlreadyPresentInSet,
1724 EINVAL => unreachable,
1725 ELOOP => return error.OperationCausesCircularLoop,
1726 ENOENT => return error.FileDescriptorNotRegistered,
1727 ENOMEM => return error.SystemResources,
1728 ENOSPC => return error.UserResourceLimitReached,
1729 EPERM => return error.FileDescriptorIncompatibleWithEpoll,
1730 }
1731}
1732
1733/// Waits for an I/O event on an epoll file descriptor.
1734/// Returns the number of file descriptors ready for the requested I/O,
1735/// or zero if no file descriptor became ready during the requested timeout milliseconds.
1736pub fn epoll_wait(epfd: i32, events: []epoll_event, timeout: i32) usize {
1737 while (true) {
1738 // TODO get rid of the @intCast
1739 const rc = system.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
1740 switch (system.getErrno(rc)) {
1741 0 => return rc,
1742 EINTR => continue,
1743 EBADF => unreachable,
1744 EFAULT => unreachable,
1745 EINVAL => unreachable,
1746 else => unreachable,
1747 }
1748 }
1749}
1750
1751pub const EventFdError = error{
1752 SystemResources,
1753 ProcessFdQuotaExceeded,
1754 SystemFdQuotaExceeded,
1755 Unexpected,
1756};
1757
1758pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
1759 const rc = system.eventfd(initval, flags);
1760 switch (system.getErrno(rc)) {
1761 0 => return @intCast(i32, rc),
1762 else => |err| return unexpectedErrno(err),
1763
1764 EINVAL => unreachable, // invalid parameters
1765 EMFILE => return error.ProcessFdQuotaExceeded,
1766 ENFILE => return error.SystemFdQuotaExceeded,
1767 ENODEV => return error.SystemResources,
1768 ENOMEM => return error.SystemResources,
1769 }
1770}
1771
1772pub const GetSockNameError = error{
1773 /// Insufficient resources were available in the system to perform the operation.
1774 SystemResources,
1775
1776 Unexpected,
1777};
1778
1779pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr {
1780 var addr: sockaddr = undefined;
1781 var addrlen: socklen_t = @sizeOf(sockaddr);
1782 switch (system.getErrno(system.getsockname(sockfd, &addr, &addrlen))) {
1783 0 => return addr,
1784 else => |err| return unexpectedErrno(err),
1785
1786 EBADF => unreachable, // always a race condition
1787 EFAULT => unreachable,
1788 EINVAL => unreachable, // invalid parameters
1789 ENOTSOCK => unreachable,
1790 ENOBUFS => return error.SystemResources,
1791 }
1792}
1793
1794pub const ConnectError = error{
1795 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
1796 /// file, or search permission is denied for one of the directories in the path prefix.
1797 /// or
1798 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
1799 /// the connection request failed because of a local firewall rule.
1800 PermissionDenied,
1801
1802 /// Local address is already in use.
1803 AddressInUse,
1804
1805 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
1806 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
1807 /// in the ephemeral port range are currently in use. See the discussion of
1808 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
1809 AddressNotAvailable,
1810
1811 /// The passed address didn't have the correct address family in its sa_family field.
1812 AddressFamilyNotSupported,
1813
1814 /// Insufficient entries in the routing cache.
1815 SystemResources,
1816
1817 /// A connect() on a stream socket found no one listening on the remote address.
1818 ConnectionRefused,
1819
1820 /// Network is unreachable.
1821 NetworkUnreachable,
1822
1823 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
1824 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
1825 ConnectionTimedOut,
1826
1827 Unexpected,
1828};
1829
1830/// Initiate a connection on a socket.
1831/// This is for blocking file descriptors only.
1832/// For non-blocking, see `connect_async`.
1833pub fn connect(sockfd: i32, sockaddr: *const sockaddr) ConnectError!void {
1834 while (true) {
1835 switch (system.getErrno(system.connect(sockfd, sockaddr, @sizeOf(sockaddr)))) {
1836 0 => return,
1837 else => |err| return unexpectedErrno(err),
1838
1839 EACCES => return error.PermissionDenied,
1840 EPERM => return error.PermissionDenied,
1841 EADDRINUSE => return error.AddressInUse,
1842 EADDRNOTAVAIL => return error.AddressNotAvailable,
1843 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1844 EAGAIN => return error.SystemResources,
1845 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1846 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1847 ECONNREFUSED => return error.ConnectionRefused,
1848 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1849 EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
1850 EINTR => continue,
1851 EISCONN => unreachable, // The socket is already connected.
1852 ENETUNREACH => return error.NetworkUnreachable,
1853 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1854 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1855 ETIMEDOUT => return error.ConnectionTimedOut,
1856 }
1857 }
1858}
1859
1860/// Same as `connect` except it is for blocking socket file descriptors.
1861/// It expects to receive EINPROGRESS`.
1862pub fn connect_async(sockfd: i32, sockaddr: *const c_void, len: u32) ConnectError!void {
1863 while (true) {
1864 switch (system.getErrno(system.connect(sockfd, sockaddr, len))) {
1865 0, EINPROGRESS => return,
1866 EINTR => continue,
1867 else => return unexpectedErrno(err),
1868
1869 EACCES => return error.PermissionDenied,
1870 EPERM => return error.PermissionDenied,
1871 EADDRINUSE => return error.AddressInUse,
1872 EADDRNOTAVAIL => return error.AddressNotAvailable,
1873 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1874 EAGAIN => return error.SystemResources,
1875 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1876 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1877 ECONNREFUSED => return error.ConnectionRefused,
1878 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1879 EISCONN => unreachable, // The socket is already connected.
1880 ENETUNREACH => return error.NetworkUnreachable,
1881 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1882 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1883 ETIMEDOUT => return error.ConnectionTimedOut,
1884 }
1885 }
1886}
1887
1888pub fn getsockoptError(sockfd: i32) ConnectError!void {
1889 var err_code: i32 = undefined;
1890 var size: u32 = @sizeOf(i32);
1891 const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);
1892 assert(size == 4);
1893 switch (system.getErrno(rc)) {
1894 0 => switch (err_code) {
1895 0 => return,
1896 EACCES => return error.PermissionDenied,
1897 EPERM => return error.PermissionDenied,
1898 EADDRINUSE => return error.AddressInUse,
1899 EADDRNOTAVAIL => return error.AddressNotAvailable,
1900 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1901 EAGAIN => return error.SystemResources,
1902 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1903 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1904 ECONNREFUSED => return error.ConnectionRefused,
1905 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1906 EISCONN => unreachable, // The socket is already connected.
1907 ENETUNREACH => return error.NetworkUnreachable,
1908 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1909 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1910 ETIMEDOUT => return error.ConnectionTimedOut,
1911 else => |err| return unexpectedErrno(err),
1912 },
1913 EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
1914 EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
1915 EINVAL => unreachable,
1916 ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
1917 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1918 else => |err| return unexpectedErrno(err),
1919 }
1920}
1921
1922pub fn wait(pid: i32) i32 {
1923 var status: i32 = undefined;
1924 while (true) {
1925 switch (system.getErrno(system.waitpid(pid, &status, 0))) {
1926 0 => return status,
1927 EINTR => continue,
1928 ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
1929 EINVAL => unreachable, // The options argument was invalid
1930 else => unreachable,
1931 }
1932 }
1933}
1934
1935pub fn fstat(fd: FileHandle) !Stat {
1936 var stat: Stat = undefined;
1937 switch (system.getErrno(system.fstat(fd, &stat))) {
1938 0 => return stat,
1939 EBADF => unreachable, // Always a race condition.
1940 ENOMEM => return error.SystemResources,
1941 else => |err| return unexpectedErrno(err),
1942 }
1943
1944 return stat;
1945}
1946
1947pub const KQueueError = error{
1948 /// The per-process limit on the number of open file descriptors has been reached.
1949 ProcessFdQuotaExceeded,
1950
1951 /// The system-wide limit on the total number of open files has been reached.
1952 SystemFdQuotaExceeded,
1953
1954 Unexpected,
1955};
1956
1957pub fn kqueue() KQueueError!i32 {
1958 const rc = system.kqueue();
1959 switch (system.getErrno(rc)) {
1960 0 => return @intCast(i32, rc),
1961 EMFILE => return error.ProcessFdQuotaExceeded,
1962 ENFILE => return error.SystemFdQuotaExceeded,
1963 else => |err| return unexpectedErrno(err),
1964 }
1965}
1966
1967pub const KEventError = error{
1968 /// The process does not have permission to register a filter.
1969 AccessDenied,
1970
1971 /// The event could not be found to be modified or deleted.
1972 EventNotFound,
1973
1974 /// No memory was available to register the event.
1975 SystemResources,
1976
1977 /// The specified process to attach to does not exist.
1978 ProcessNotFound,
1979};
1980
1981pub fn kevent(
1982 kq: i32,
1983 changelist: []const Kevent,
1984 eventlist: []Kevent,
1985 timeout: ?*const timespec,
1986) KEventError!usize {
1987 while (true) {
1988 const rc = system.kevent(kq, changelist, eventlist, timeout);
1989 switch (system.getErrno(rc)) {
1990 0 => return rc,
1991 EACCES => return error.AccessDenied,
1992 EFAULT => unreachable,
1993 EBADF => unreachable, // Always a race condition.
1994 EINTR => continue,
1995 EINVAL => unreachable,
1996 ENOENT => return error.EventNotFound,
1997 ENOMEM => return error.SystemResources,
1998 ESRCH => return error.ProcessNotFound,
1999 else => unreachable,
2000 }
2001 }
2002}
2003
2004pub const INotifyInitError = error{
2005 ProcessFdQuotaExceeded,
2006 SystemFdQuotaExceeded,
2007 SystemResources,
2008 Unexpected,
2009};
2010
2011/// initialize an inotify instance
2012pub fn inotify_init1(flags: u32) INotifyInitError!i32 {
2013 const rc = system.inotify_init1(flags);
2014 switch (system.getErrno(rc)) {
2015 0 => return @intCast(i32, rc),
2016 EINVAL => unreachable,
2017 EMFILE => return error.ProcessFdQuotaExceeded,
2018 ENFILE => return error.SystemFdQuotaExceeded,
2019 ENOMEM => return error.SystemResources,
2020 else => |err| return unexpectedErrno(err),
2021 }
2022}
2023
2024pub const INotifyAddWatchError = error{
2025 AccessDenied,
2026 NameTooLong,
2027 FileNotFound,
2028 SystemResources,
2029 UserResourceLimitReached,
2030 Unexpected,
2031};
2032
2033/// add a watch to an initialized inotify instance
2034pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 {
2035 const pathname_c = try toPosixPath(pathname);
2036 return inotify_add_watchC(inotify_fd, &pathname_c, mask);
2037}
2038
2039/// Same as `inotify_add_watch` except pathname is null-terminated.
2040pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 {
2041 const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
2042 switch (system.getErrno(rc)) {
2043 0 => return @intCast(i32, rc),
2044 EACCES => return error.AccessDenied,
2045 EBADF => unreachable,
2046 EFAULT => unreachable,
2047 EINVAL => unreachable,
2048 ENAMETOOLONG => return error.NameTooLong,
2049 ENOENT => return error.FileNotFound,
2050 ENOMEM => return error.SystemResources,
2051 ENOSPC => return error.UserResourceLimitReached,
2052 else => |err| return unexpectedErrno(err),
2053 }
2054}
2055
2056/// remove an existing watch from an inotify instance
2057pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
2058 switch (system.getErrno(system.inotify_rm_watch(inotify_fd, wd))) {
2059 0 => return,
2060 EBADF => unreachable,
2061 EINVAL => unreachable,
2062 else => unreachable,
2063 }
2064}
2065
2066pub const MProtectError = error{
2067 AccessDenied,
2068 OutOfMemory,
2069 Unexpected,
2070};
2071
2072/// address and length must be page-aligned
2073pub fn mprotect(address: usize, length: usize, protection: u32) MProtectError!void {
2074 const negative_page_size = @bitCast(usize, -isize(page_size));
2075 const aligned_address = address & negative_page_size;
2076 const aligned_end = (address + length + page_size - 1) & negative_page_size;
2077 assert(address == aligned_address);
2078 assert(length == aligned_end - aligned_address);
2079 switch (system.getErrno(system.mprotect(address, length, protection))) {
2080 0 => return,
2081 EINVAL => unreachable,
2082 EACCES => return error.AccessDenied,
2083 ENOMEM => return error.OutOfMemory,
2084 else => return unexpectedErrno(err),
2085 }
2086}
2087
2088/// Used to convert a slice to a null terminated slice on the stack.
2089/// TODO https://github.com/ziglang/zig/issues/287
2090pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
2091 var path_with_null: [PATH_MAX]u8 = undefined;
2092 // >= rather than > to make room for the null byte
2093 if (file_path.len >= PATH_MAX) return error.NameTooLong;
2094 mem.copy(u8, &path_with_null, file_path);
2095 path_with_null[file_path.len] = 0;
2096 return path_with_null;
2097}
2098
2099const unexpected_error_tracing = builtin.mode == .Debug;
2100const UnexpectedError = error{
2101 /// The Operating System returned an undocumented error code.
2102 Unexpected,
2103};
2104
2105/// Call this when you made a syscall or something that sets errno
2106/// and you get an unexpected error.
2107pub fn unexpectedErrno(errno: usize) UnexpectedError {
2108 if (unexpected_error_tracing) {
2109 std.debug.warn("unexpected errno: {}\n", errno);
2110 std.debug.dumpCurrentStackTrace(null);
2111 }
2112 return error.Unexpected;
2113}
2114
2115/// Call this when you made a windows DLL call or something that does SetLastError
2116/// and you get an unexpected error.
2117pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2118 if (unexpected_error_tracing) {
2119 std.debug.warn("unexpected GetLastError(): {}\n", err);
2120 std.debug.dumpCurrentStackTrace(null);
2121 }
2122 return error.Unexpected;
2123}
2124
2125pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
2126 return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
2127}
2128
2129pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
2130 return sliceToPrefixedSuffixedFileW(s, []u16{0});
2131}
2132
2133pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
2134 // TODO well defined copy elision
2135 var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
2136
2137 // > File I/O functions in the Windows API convert "/" to "\" as part of
2138 // > converting the name to an NT-style name, except when using the "\\?\"
2139 // > prefix as detailed in the following sections.
2140 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
2141 // Because we want the larger maximum path length for absolute paths, we
2142 // disallow forward slashes in zig std lib file functions on Windows.
2143 for (s) |byte| {
2144 switch (byte) {
2145 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
2146 else => {},
2147 }
2148 }
2149 const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
2150 const prefix = []u16{ '\\', '\\', '?', '\\' };
2151 mem.copy(u16, result[0..], prefix);
2152 break :blk prefix.len;
2153 };
2154 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
2155 assert(end_index <= result.len);
2156 if (end_index + suffix.len > result.len) return error.NameTooLong;
2157 mem.copy(u16, result[end_index..], suffix);
2158 return result;
2159}
std/os/wasi.zig+381-30
......@@ -1,42 +1,393 @@
1pub use @import("wasi/core.zig");
1// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
2// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
3const std = @import("std");
4const assert = std.debug.assert;
5
6pub const is_the_target = @import("builtin").os == .wasi;
27
38pub const STDIN_FILENO = 0;
49pub const STDOUT_FILENO = 1;
510pub const STDERR_FILENO = 2;
611
7pub fn getErrno(r: usize) usize {
8 const signed_r = @bitCast(isize, r);
9 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
12comptime {
13 assert(@alignOf(i8) == 1);
14 assert(@alignOf(u8) == 1);
15 assert(@alignOf(i16) == 2);
16 assert(@alignOf(u16) == 2);
17 assert(@alignOf(i32) == 4);
18 assert(@alignOf(u32) == 4);
19 assert(@alignOf(i64) == 8);
20 assert(@alignOf(u64) == 8);
1021}
1122
12pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
13 var nwritten: usize = undefined;
23pub const advice_t = u8;
24pub const ADVICE_NORMAL: advice_t = 0;
25pub const ADVICE_SEQUENTIAL: advice_t = 1;
26pub const ADVICE_RANDOM: advice_t = 2;
27pub const ADVICE_WILLNEED: advice_t = 3;
28pub const ADVICE_DONTNEED: advice_t = 4;
29pub const ADVICE_NOREUSE: advice_t = 5;
1430
15 const ciovs = ciovec_t{
16 .buf = buf,
17 .buf_len = count,
18 };
31pub const ciovec_t = extern struct {
32 buf: [*]const u8,
33 buf_len: usize,
34};
1935
20 const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten);
21 if (err == ESUCCESS) {
22 return nwritten;
23 } else {
24 return @bitCast(usize, -isize(err));
25 }
26}
36pub const clockid_t = u32;
37pub const CLOCK_REALTIME: clockid_t = 0;
38pub const CLOCK_MONOTONIC: clockid_t = 1;
39pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
40pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
2741
28pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
29 var nread: usize = undefined;
42pub const device_t = u64;
3043
31 const iovs = iovec_t{
32 .buf = buf,
33 .buf_len = nbyte,
34 };
44pub const dircookie_t = u64;
45pub const DIRCOOKIE_START: dircookie_t = 0;
3546
36 const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread);
37 if (err == ESUCCESS) {
38 return nread;
39 } else {
40 return @bitCast(usize, -isize(err));
41 }
42}
47pub const dirent_t = extern struct {
48 d_next: dircookie_t,
49 d_ino: inode_t,
50 d_namlen: u32,
51 d_type: filetype_t,
52};
53
54pub const errno_t = u16;
55pub const ESUCCESS: errno_t = 0;
56pub const E2BIG: errno_t = 1;
57pub const EACCES: errno_t = 2;
58pub const EADDRINUSE: errno_t = 3;
59pub const EADDRNOTAVAIL: errno_t = 4;
60pub const EAFNOSUPPORT: errno_t = 5;
61pub const EAGAIN: errno_t = 6;
62pub const EALREADY: errno_t = 7;
63pub const EBADF: errno_t = 8;
64pub const EBADMSG: errno_t = 9;
65pub const EBUSY: errno_t = 10;
66pub const ECANCELED: errno_t = 11;
67pub const ECHILD: errno_t = 12;
68pub const ECONNABORTED: errno_t = 13;
69pub const ECONNREFUSED: errno_t = 14;
70pub const ECONNRESET: errno_t = 15;
71pub const EDEADLK: errno_t = 16;
72pub const EDESTADDRREQ: errno_t = 17;
73pub const EDOM: errno_t = 18;
74pub const EDQUOT: errno_t = 19;
75pub const EEXIST: errno_t = 20;
76pub const EFAULT: errno_t = 21;
77pub const EFBIG: errno_t = 22;
78pub const EHOSTUNREACH: errno_t = 23;
79pub const EIDRM: errno_t = 24;
80pub const EILSEQ: errno_t = 25;
81pub const EINPROGRESS: errno_t = 26;
82pub const EINTR: errno_t = 27;
83pub const EINVAL: errno_t = 28;
84pub const EIO: errno_t = 29;
85pub const EISCONN: errno_t = 30;
86pub const EISDIR: errno_t = 31;
87pub const ELOOP: errno_t = 32;
88pub const EMFILE: errno_t = 33;
89pub const EMLINK: errno_t = 34;
90pub const EMSGSIZE: errno_t = 35;
91pub const EMULTIHOP: errno_t = 36;
92pub const ENAMETOOLONG: errno_t = 37;
93pub const ENETDOWN: errno_t = 38;
94pub const ENETRESET: errno_t = 39;
95pub const ENETUNREACH: errno_t = 40;
96pub const ENFILE: errno_t = 41;
97pub const ENOBUFS: errno_t = 42;
98pub const ENODEV: errno_t = 43;
99pub const ENOENT: errno_t = 44;
100pub const ENOEXEC: errno_t = 45;
101pub const ENOLCK: errno_t = 46;
102pub const ENOLINK: errno_t = 47;
103pub const ENOMEM: errno_t = 48;
104pub const ENOMSG: errno_t = 49;
105pub const ENOPROTOOPT: errno_t = 50;
106pub const ENOSPC: errno_t = 51;
107pub const ENOSYS: errno_t = 52;
108pub const ENOTCONN: errno_t = 53;
109pub const ENOTDIR: errno_t = 54;
110pub const ENOTEMPTY: errno_t = 55;
111pub const ENOTRECOVERABLE: errno_t = 56;
112pub const ENOTSOCK: errno_t = 57;
113pub const ENOTSUP: errno_t = 58;
114pub const ENOTTY: errno_t = 59;
115pub const ENXIO: errno_t = 60;
116pub const EOVERFLOW: errno_t = 61;
117pub const EOWNERDEAD: errno_t = 62;
118pub const EPERM: errno_t = 63;
119pub const EPIPE: errno_t = 64;
120pub const EPROTO: errno_t = 65;
121pub const EPROTONOSUPPORT: errno_t = 66;
122pub const EPROTOTYPE: errno_t = 67;
123pub const ERANGE: errno_t = 68;
124pub const EROFS: errno_t = 69;
125pub const ESPIPE: errno_t = 70;
126pub const ESRCH: errno_t = 71;
127pub const ESTALE: errno_t = 72;
128pub const ETIMEDOUT: errno_t = 73;
129pub const ETXTBSY: errno_t = 74;
130pub const EXDEV: errno_t = 75;
131pub const ENOTCAPABLE: errno_t = 76;
132
133pub const event_t = extern struct {
134 userdata: userdata_t,
135 @"error": errno_t,
136 @"type": eventtype_t,
137 u: extern union {
138 fd_readwrite: extern struct {
139 nbytes: filesize_t,
140 flags: eventrwflags_t,
141 },
142 },
143};
144
145pub const eventrwflags_t = u16;
146pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
147
148pub const eventtype_t = u8;
149pub const EVENTTYPE_CLOCK: eventtype_t = 0;
150pub const EVENTTYPE_FD_READ: eventtype_t = 1;
151pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
152
153pub const exitcode_t = u32;
154
155pub const fd_t = u32;
156
157pub const fdflags_t = u16;
158pub const FDFLAG_APPEND: fdflags_t = 0x0001;
159pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
160pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
161pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
162pub const FDFLAG_SYNC: fdflags_t = 0x0010;
163
164const fdstat_t = extern struct {
165 fs_filetype: filetype_t,
166 fs_flags: fdflags_t,
167 fs_rights_base: rights_t,
168 fs_rights_inheriting: rights_t,
169};
170
171pub const filedelta_t = i64;
172
173pub const filesize_t = u64;
174
175pub const filestat_t = extern struct {
176 st_dev: device_t,
177 st_ino: inode_t,
178 st_filetype: filetype_t,
179 st_nlink: linkcount_t,
180 st_size: filesize_t,
181 st_atim: timestamp_t,
182 st_mtim: timestamp_t,
183 st_ctim: timestamp_t,
184};
185
186pub const filetype_t = u8;
187pub const FILETYPE_UNKNOWN: filetype_t = 0;
188pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
189pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
190pub const FILETYPE_DIRECTORY: filetype_t = 3;
191pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
192pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
193pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
194pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
195
196pub const fstflags_t = u16;
197pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
198pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
199pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
200pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
201
202pub const inode_t = u64;
203
204pub const iovec_t = extern struct {
205 buf: [*]u8,
206 buf_len: usize,
207};
208
209pub const linkcount_t = u32;
210
211pub const lookupflags_t = u32;
212pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
213
214pub const oflags_t = u16;
215pub const O_CREAT: oflags_t = 0x0001;
216pub const O_DIRECTORY: oflags_t = 0x0002;
217pub const O_EXCL: oflags_t = 0x0004;
218pub const O_TRUNC: oflags_t = 0x0008;
219
220pub const preopentype_t = u8;
221pub const PREOPENTYPE_DIR: preopentype_t = 0;
222
223pub const prestat_t = extern struct {
224 pr_type: preopentype_t,
225 u: extern union {
226 dir: extern struct {
227 pr_name_len: usize,
228 },
229 },
230};
231
232pub const riflags_t = u16;
233pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
234pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
235
236pub const rights_t = u64;
237pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
238pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
239pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
240pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
241pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
242pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
243pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
244pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
245pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
246pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
247pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
248pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
249pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
250pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
251pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
252pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
253pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
254pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
255pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
256pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
257pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
258pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
259pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
260pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
261pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
262pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
263pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
264pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
265pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
266
267pub const roflags_t = u16;
268pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
269
270pub const sdflags_t = u8;
271pub const SHUT_RD: sdflags_t = 0x01;
272pub const SHUT_WR: sdflags_t = 0x02;
273
274pub const siflags_t = u16;
275
276pub const signal_t = u8;
277pub const SIGHUP: signal_t = 1;
278pub const SIGINT: signal_t = 2;
279pub const SIGQUIT: signal_t = 3;
280pub const SIGILL: signal_t = 4;
281pub const SIGTRAP: signal_t = 5;
282pub const SIGABRT: signal_t = 6;
283pub const SIGBUS: signal_t = 7;
284pub const SIGFPE: signal_t = 8;
285pub const SIGKILL: signal_t = 9;
286pub const SIGUSR1: signal_t = 10;
287pub const SIGSEGV: signal_t = 11;
288pub const SIGUSR2: signal_t = 12;
289pub const SIGPIPE: signal_t = 13;
290pub const SIGALRM: signal_t = 14;
291pub const SIGTERM: signal_t = 15;
292pub const SIGCHLD: signal_t = 16;
293pub const SIGCONT: signal_t = 17;
294pub const SIGSTOP: signal_t = 18;
295pub const SIGTSTP: signal_t = 19;
296pub const SIGTTIN: signal_t = 20;
297pub const SIGTTOU: signal_t = 21;
298pub const SIGURG: signal_t = 22;
299pub const SIGXCPU: signal_t = 23;
300pub const SIGXFSZ: signal_t = 24;
301pub const SIGVTALRM: signal_t = 25;
302pub const SIGPROF: signal_t = 26;
303pub const SIGWINCH: signal_t = 27;
304pub const SIGPOLL: signal_t = 28;
305pub const SIGPWR: signal_t = 29;
306pub const SIGSYS: signal_t = 30;
307
308pub const subclockflags_t = u16;
309pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
310
311pub const subscription_t = extern struct {
312 userdata: userdata_t,
313 @"type": eventtype_t,
314 u: extern union {
315 clock: extern struct {
316 identifier: userdata_t,
317 clock_id: clockid_t,
318 timeout: timestamp_t,
319 precision: timestamp_t,
320 flags: subclockflags_t,
321 },
322 fd_readwrite: extern struct {
323 fd: fd_t,
324 },
325 },
326};
327
328pub const timestamp_t = u64;
329
330pub const userdata_t = u64;
331
332pub const whence_t = u8;
333pub const WHENCE_CUR: whence_t = 0;
334pub const WHENCE_END: whence_t = 1;
335pub const WHENCE_SET: whence_t = 2;
336
337pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
338pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
339
340pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
341pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
342
343pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
344pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
345
346pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
347pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
348pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
349pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
350pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
351pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
352pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, nread: *usize) errno_t;
353pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
354pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
355pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
356pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
357pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
358pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
359
360pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
361pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
362pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
363
364pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
365pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
366pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
367
368pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
369pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
370
371pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
372pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
373pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
374pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
375pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
376pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
377pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
378pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
379pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
380pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
381
382pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
383
384pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
385pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
386
387pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
388
389pub extern "wasi_unstable" fn sched_yield() errno_t;
390
391pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
392pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
393pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/wasi/core.zig deleted-374
......@@ -1,374 +0,0 @@
1// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
2// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
3
4pub const advice_t = u8;
5pub const ADVICE_NORMAL: advice_t = 0;
6pub const ADVICE_SEQUENTIAL: advice_t = 1;
7pub const ADVICE_RANDOM: advice_t = 2;
8pub const ADVICE_WILLNEED: advice_t = 3;
9pub const ADVICE_DONTNEED: advice_t = 4;
10pub const ADVICE_NOREUSE: advice_t = 5;
11
12pub const ciovec_t = extern struct {
13 buf: [*]const u8,
14 buf_len: usize,
15};
16
17pub const clockid_t = u32;
18pub const CLOCK_REALTIME: clockid_t = 0;
19pub const CLOCK_MONOTONIC: clockid_t = 1;
20pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
21pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
22
23pub const device_t = u64;
24
25pub const dircookie_t = u64;
26pub const DIRCOOKIE_START: dircookie_t = 0;
27
28pub const dirent_t = extern struct {
29 d_next: dircookie_t,
30 d_ino: inode_t,
31 d_namlen: u32,
32 d_type: filetype_t,
33};
34
35pub const errno_t = u16;
36pub const ESUCCESS: errno_t = 0;
37pub const E2BIG: errno_t = 1;
38pub const EACCES: errno_t = 2;
39pub const EADDRINUSE: errno_t = 3;
40pub const EADDRNOTAVAIL: errno_t = 4;
41pub const EAFNOSUPPORT: errno_t = 5;
42pub const EAGAIN: errno_t = 6;
43pub const EALREADY: errno_t = 7;
44pub const EBADF: errno_t = 8;
45pub const EBADMSG: errno_t = 9;
46pub const EBUSY: errno_t = 10;
47pub const ECANCELED: errno_t = 11;
48pub const ECHILD: errno_t = 12;
49pub const ECONNABORTED: errno_t = 13;
50pub const ECONNREFUSED: errno_t = 14;
51pub const ECONNRESET: errno_t = 15;
52pub const EDEADLK: errno_t = 16;
53pub const EDESTADDRREQ: errno_t = 17;
54pub const EDOM: errno_t = 18;
55pub const EDQUOT: errno_t = 19;
56pub const EEXIST: errno_t = 20;
57pub const EFAULT: errno_t = 21;
58pub const EFBIG: errno_t = 22;
59pub const EHOSTUNREACH: errno_t = 23;
60pub const EIDRM: errno_t = 24;
61pub const EILSEQ: errno_t = 25;
62pub const EINPROGRESS: errno_t = 26;
63pub const EINTR: errno_t = 27;
64pub const EINVAL: errno_t = 28;
65pub const EIO: errno_t = 29;
66pub const EISCONN: errno_t = 30;
67pub const EISDIR: errno_t = 31;
68pub const ELOOP: errno_t = 32;
69pub const EMFILE: errno_t = 33;
70pub const EMLINK: errno_t = 34;
71pub const EMSGSIZE: errno_t = 35;
72pub const EMULTIHOP: errno_t = 36;
73pub const ENAMETOOLONG: errno_t = 37;
74pub const ENETDOWN: errno_t = 38;
75pub const ENETRESET: errno_t = 39;
76pub const ENETUNREACH: errno_t = 40;
77pub const ENFILE: errno_t = 41;
78pub const ENOBUFS: errno_t = 42;
79pub const ENODEV: errno_t = 43;
80pub const ENOENT: errno_t = 44;
81pub const ENOEXEC: errno_t = 45;
82pub const ENOLCK: errno_t = 46;
83pub const ENOLINK: errno_t = 47;
84pub const ENOMEM: errno_t = 48;
85pub const ENOMSG: errno_t = 49;
86pub const ENOPROTOOPT: errno_t = 50;
87pub const ENOSPC: errno_t = 51;
88pub const ENOSYS: errno_t = 52;
89pub const ENOTCONN: errno_t = 53;
90pub const ENOTDIR: errno_t = 54;
91pub const ENOTEMPTY: errno_t = 55;
92pub const ENOTRECOVERABLE: errno_t = 56;
93pub const ENOTSOCK: errno_t = 57;
94pub const ENOTSUP: errno_t = 58;
95pub const ENOTTY: errno_t = 59;
96pub const ENXIO: errno_t = 60;
97pub const EOVERFLOW: errno_t = 61;
98pub const EOWNERDEAD: errno_t = 62;
99pub const EPERM: errno_t = 63;
100pub const EPIPE: errno_t = 64;
101pub const EPROTO: errno_t = 65;
102pub const EPROTONOSUPPORT: errno_t = 66;
103pub const EPROTOTYPE: errno_t = 67;
104pub const ERANGE: errno_t = 68;
105pub const EROFS: errno_t = 69;
106pub const ESPIPE: errno_t = 70;
107pub const ESRCH: errno_t = 71;
108pub const ESTALE: errno_t = 72;
109pub const ETIMEDOUT: errno_t = 73;
110pub const ETXTBSY: errno_t = 74;
111pub const EXDEV: errno_t = 75;
112pub const ENOTCAPABLE: errno_t = 76;
113
114pub const event_t = extern struct {
115 userdata: userdata_t,
116 @"error": errno_t,
117 @"type": eventtype_t,
118 u: extern union {
119 fd_readwrite: extern struct {
120 nbytes: filesize_t,
121 flags: eventrwflags_t,
122 },
123 },
124};
125
126pub const eventrwflags_t = u16;
127pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
128
129pub const eventtype_t = u8;
130pub const EVENTTYPE_CLOCK: eventtype_t = 0;
131pub const EVENTTYPE_FD_READ: eventtype_t = 1;
132pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
133
134pub const exitcode_t = u32;
135
136pub const fd_t = u32;
137
138pub const fdflags_t = u16;
139pub const FDFLAG_APPEND: fdflags_t = 0x0001;
140pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
141pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
142pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
143pub const FDFLAG_SYNC: fdflags_t = 0x0010;
144
145const fdstat_t = extern struct {
146 fs_filetype: filetype_t,
147 fs_flags: fdflags_t,
148 fs_rights_base: rights_t,
149 fs_rights_inheriting: rights_t,
150};
151
152pub const filedelta_t = i64;
153
154pub const filesize_t = u64;
155
156pub const filestat_t = extern struct {
157 st_dev: device_t,
158 st_ino: inode_t,
159 st_filetype: filetype_t,
160 st_nlink: linkcount_t,
161 st_size: filesize_t,
162 st_atim: timestamp_t,
163 st_mtim: timestamp_t,
164 st_ctim: timestamp_t,
165};
166
167pub const filetype_t = u8;
168pub const FILETYPE_UNKNOWN: filetype_t = 0;
169pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
170pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
171pub const FILETYPE_DIRECTORY: filetype_t = 3;
172pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
173pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
174pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
175pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
176
177pub const fstflags_t = u16;
178pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
179pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
180pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
181pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
182
183pub const inode_t = u64;
184
185pub const iovec_t = extern struct {
186 buf: [*]u8,
187 buf_len: usize,
188};
189
190pub const linkcount_t = u32;
191
192pub const lookupflags_t = u32;
193pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
194
195pub const oflags_t = u16;
196pub const O_CREAT: oflags_t = 0x0001;
197pub const O_DIRECTORY: oflags_t = 0x0002;
198pub const O_EXCL: oflags_t = 0x0004;
199pub const O_TRUNC: oflags_t = 0x0008;
200
201pub const preopentype_t = u8;
202pub const PREOPENTYPE_DIR: preopentype_t = 0;
203
204pub const prestat_t = extern struct {
205 pr_type: preopentype_t,
206 u: extern union {
207 dir: extern struct {
208 pr_name_len: usize,
209 },
210 },
211};
212
213pub const riflags_t = u16;
214pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
215pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
216
217pub const rights_t = u64;
218pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
219pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
220pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
221pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
222pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
223pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
224pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
225pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
226pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
227pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
228pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
229pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
230pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
231pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
232pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
233pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
234pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
235pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
236pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
237pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
238pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
239pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
240pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
241pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
242pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
243pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
244pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
245pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
246pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
247
248pub const roflags_t = u16;
249pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
250
251pub const sdflags_t = u8;
252pub const SHUT_RD: sdflags_t = 0x01;
253pub const SHUT_WR: sdflags_t = 0x02;
254
255pub const siflags_t = u16;
256
257pub const signal_t = u8;
258pub const SIGHUP: signal_t = 1;
259pub const SIGINT: signal_t = 2;
260pub const SIGQUIT: signal_t = 3;
261pub const SIGILL: signal_t = 4;
262pub const SIGTRAP: signal_t = 5;
263pub const SIGABRT: signal_t = 6;
264pub const SIGBUS: signal_t = 7;
265pub const SIGFPE: signal_t = 8;
266pub const SIGKILL: signal_t = 9;
267pub const SIGUSR1: signal_t = 10;
268pub const SIGSEGV: signal_t = 11;
269pub const SIGUSR2: signal_t = 12;
270pub const SIGPIPE: signal_t = 13;
271pub const SIGALRM: signal_t = 14;
272pub const SIGTERM: signal_t = 15;
273pub const SIGCHLD: signal_t = 16;
274pub const SIGCONT: signal_t = 17;
275pub const SIGSTOP: signal_t = 18;
276pub const SIGTSTP: signal_t = 19;
277pub const SIGTTIN: signal_t = 20;
278pub const SIGTTOU: signal_t = 21;
279pub const SIGURG: signal_t = 22;
280pub const SIGXCPU: signal_t = 23;
281pub const SIGXFSZ: signal_t = 24;
282pub const SIGVTALRM: signal_t = 25;
283pub const SIGPROF: signal_t = 26;
284pub const SIGWINCH: signal_t = 27;
285pub const SIGPOLL: signal_t = 28;
286pub const SIGPWR: signal_t = 29;
287pub const SIGSYS: signal_t = 30;
288
289pub const subclockflags_t = u16;
290pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
291
292pub const subscription_t = extern struct {
293 userdata: userdata_t,
294 @"type": eventtype_t,
295 u: extern union {
296 clock: extern struct {
297 identifier: userdata_t,
298 clock_id: clockid_t,
299 timeout: timestamp_t,
300 precision: timestamp_t,
301 flags: subclockflags_t,
302 },
303 fd_readwrite: extern struct {
304 fd: fd_t,
305 },
306 },
307};
308
309pub const timestamp_t = u64;
310
311pub const userdata_t = u64;
312
313pub const whence_t = u8;
314pub const WHENCE_CUR: whence_t = 0;
315pub const WHENCE_END: whence_t = 1;
316pub const WHENCE_SET: whence_t = 2;
317
318pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
319pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
320
321pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
322pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
323
324pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
325pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
326
327pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
328pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
329pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
330pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
331pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
332pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
333pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t;
334pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
335pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
336pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
337pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
338pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
339pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
340
341pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
342pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
343pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
344
345pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
346pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
347pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
348
349pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
350pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
351
352pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
353pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
354pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
355pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
356pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
357pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
358pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
359pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
360pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
361pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
362
363pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
364
365pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
366pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
367
368pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
369
370pub extern "wasi_unstable" fn sched_yield() errno_t;
371
372pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
373pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
374pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/windows.zig+9-1
......@@ -2,6 +2,11 @@ const std = @import("../std.zig");
22const assert = std.debug.assert;
33const maxInt = std.math.maxInt;
44
5pub const is_the_target = switch (builtin.os) {
6 .windows => true,
7 else => false,
8};
9
510pub use @import("windows/advapi32.zig");
611pub use @import("windows/kernel32.zig");
712pub use @import("windows/ntdll.zig");
......@@ -9,10 +14,13 @@ pub use @import("windows/ole32.zig");
914pub use @import("windows/shell32.zig");
1015
1116test "import" {
12 _ = @import("windows/util.zig");
17 if (is_the_target) {
18 _ = @import("windows/util.zig");
19 }
1320}
1421
1522pub const ERROR = @import("windows/error.zig");
23pub const errno_codes = @import("windows/errno.zig");
1624
1725pub const SHORT = c_short;
1826pub const BOOL = c_int;
std/os/windows/errno.zig created+1
......@@ -0,0 +1 @@
1// TODO get these values from msvcrt
std/os/windows/util.zig-167
......@@ -8,12 +8,6 @@ const mem = std.mem;
88const BufMap = std.BufMap;
99const cstr = std.cstr;
1010
11// > The maximum path of 32,767 characters is approximate, because the "\\?\"
12// > prefix may be expanded to a longer string by the system at run time, and
13// > this expansion applies to the total length.
14// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
15pub const PATH_MAX_WIDE = 32767;
16
1711pub const WaitError = error{
1812 WaitAbandoned,
1913 WaitTimeOut,
......@@ -38,131 +32,6 @@ pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) Wa
3832 };
3933}
4034
41pub fn windowsClose(handle: windows.HANDLE) void {
42 assert(windows.CloseHandle(handle) != 0);
43}
44
45pub const ReadError = error{
46 OperationAborted,
47 BrokenPipe,
48 Unexpected,
49};
50
51pub const WriteError = error{
52 SystemResources,
53 OperationAborted,
54 BrokenPipe,
55
56 /// See https://github.com/ziglang/zig/issues/1396
57 Unexpected,
58};
59
60pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
61 var bytes_written: windows.DWORD = undefined;
62 if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
63 const err = windows.GetLastError();
64 return switch (err) {
65 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
66 windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
67 windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
68 windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
69 windows.ERROR.IO_PENDING => unreachable,
70 windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
71 else => os.unexpectedErrorWindows(err),
72 };
73 }
74}
75
76pub fn windowsIsTty(handle: windows.HANDLE) bool {
77 if (windowsIsCygwinPty(handle))
78 return true;
79
80 var out: windows.DWORD = undefined;
81 return windows.GetConsoleMode(handle, &out) != 0;
82}
83
84pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
85 const size = @sizeOf(windows.FILE_NAME_INFO);
86 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
87
88 if (windows.GetFileInformationByHandleEx(
89 handle,
90 windows.FileNameInfo,
91 @ptrCast(*c_void, &name_info_bytes[0]),
92 @intCast(u32, name_info_bytes.len),
93 ) == 0) {
94 return false;
95 }
96
97 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
98 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
99 const name_wide = @bytesToSlice(u16, name_bytes);
100 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
101 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
102}
103
104pub const OpenError = error{
105 SharingViolation,
106 PathAlreadyExists,
107
108 /// When any of the path components can not be found or the file component can not
109 /// be found. Some operating systems distinguish between path components not found and
110 /// file components not found, but they are collapsed into FileNotFound to gain
111 /// consistency across operating systems.
112 FileNotFound,
113
114 AccessDenied,
115 PipeBusy,
116 NameTooLong,
117
118 /// On Windows, file paths must be valid Unicode.
119 InvalidUtf8,
120
121 /// On Windows, file paths cannot contain these characters:
122 /// '/', '*', '?', '"', '<', '>', '|'
123 BadPathName,
124
125 /// See https://github.com/ziglang/zig/issues/1396
126 Unexpected,
127};
128
129pub fn windowsOpenW(
130 file_path_w: [*]const u16,
131 desired_access: windows.DWORD,
132 share_mode: windows.DWORD,
133 creation_disposition: windows.DWORD,
134 flags_and_attrs: windows.DWORD,
135) OpenError!windows.HANDLE {
136 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
137
138 if (result == windows.INVALID_HANDLE_VALUE) {
139 const err = windows.GetLastError();
140 switch (err) {
141 windows.ERROR.SHARING_VIOLATION => return OpenError.SharingViolation,
142 windows.ERROR.ALREADY_EXISTS => return OpenError.PathAlreadyExists,
143 windows.ERROR.FILE_EXISTS => return OpenError.PathAlreadyExists,
144 windows.ERROR.FILE_NOT_FOUND => return OpenError.FileNotFound,
145 windows.ERROR.PATH_NOT_FOUND => return OpenError.FileNotFound,
146 windows.ERROR.ACCESS_DENIED => return OpenError.AccessDenied,
147 windows.ERROR.PIPE_BUSY => return OpenError.PipeBusy,
148 else => return os.unexpectedErrorWindows(err),
149 }
150 }
151
152 return result;
153}
154
155pub fn windowsOpen(
156 file_path: []const u8,
157 desired_access: windows.DWORD,
158 share_mode: windows.DWORD,
159 creation_disposition: windows.DWORD,
160 flags_and_attrs: windows.DWORD,
161) OpenError!windows.HANDLE {
162 const file_path_w = try sliceToPrefixedFileW(file_path);
163 return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
164}
165
16635/// Caller must free result.
16736pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
16837 // count bytes needed
......@@ -278,39 +147,3 @@ pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_t
278147 }
279148 return WindowsWaitResult.Normal;
280149}
281
282pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
283 return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
284}
285
286pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
287 return sliceToPrefixedSuffixedFileW(s, []u16{0});
288}
289
290pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
291 // TODO well defined copy elision
292 var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
293
294 // > File I/O functions in the Windows API convert "/" to "\" as part of
295 // > converting the name to an NT-style name, except when using the "\\?\"
296 // > prefix as detailed in the following sections.
297 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
298 // Because we want the larger maximum path length for absolute paths, we
299 // disallow forward slashes in zig std lib file functions on Windows.
300 for (s) |byte| {
301 switch (byte) {
302 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
303 else => {},
304 }
305 }
306 const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
307 const prefix = []u16{ '\\', '\\', '?', '\\' };
308 mem.copy(u16, result[0..], prefix);
309 break :blk prefix.len;
310 };
311 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
312 assert(end_index <= result.len);
313 if (end_index + suffix.len > result.len) return error.NameTooLong;
314 mem.copy(u16, result[end_index..], suffix);
315 return result;
316}
std/special/bootstrap.zig+2-2
......@@ -81,7 +81,7 @@ fn posixCallMainAndExit() noreturn {
8181 if (builtin.os == builtin.Os.linux) {
8282 // Find the beginning of the auxiliary vector
8383 const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
84 std.os.linux_elf_aux_maybe = auxv;
84 std.os.linux.elf_aux_maybe = auxv;
8585 // Initialize the TLS area
8686 std.os.linux.tls.initTLS();
8787
......@@ -99,7 +99,7 @@ fn posixCallMainAndExit() noreturn {
9999// and we want fewer call frames in stack traces.
100100inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
101101 std.os.ArgIteratorPosix.raw = argv[0..argc];
102 std.os.posix_environ_raw = envp;
102 std.os.posix.environ = envp;
103103 return callMain();
104104}
105105