master
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const math = std.math;
5const fs = std.fs;
6const assert = std.debug.assert;
7const Allocator = mem.Allocator;
8const wasi = std.os.wasi;
9const fd_t = wasi.fd_t;
10const prestat_t = wasi.prestat_t;
11
12pub const Preopens = struct {
13 // Indexed by file descriptor number.
14 names: []const []const u8,
15
16 pub fn find(p: Preopens, name: []const u8) ?std.posix.fd_t {
17 for (p.names, 0..) |elem_name, i| {
18 if (mem.eql(u8, elem_name, name)) {
19 return @intCast(i);
20 }
21 }
22 return null;
23 }
24};
25
26pub fn preopensAlloc(gpa: Allocator) Allocator.Error!Preopens {
27 var names: std.ArrayList([]const u8) = .empty;
28 defer names.deinit(gpa);
29
30 try names.ensureUnusedCapacity(gpa, 3);
31
32 names.appendAssumeCapacity("stdin"); // 0
33 names.appendAssumeCapacity("stdout"); // 1
34 names.appendAssumeCapacity("stderr"); // 2
35 while (true) {
36 const fd = @as(wasi.fd_t, @intCast(names.items.len));
37 var prestat: prestat_t = undefined;
38 switch (wasi.fd_prestat_get(fd, &prestat)) {
39 .SUCCESS => {},
40 .OPNOTSUPP, .BADF => return .{ .names = try names.toOwnedSlice(gpa) },
41 else => @panic("fd_prestat_get: unexpected error"),
42 }
43 try names.ensureUnusedCapacity(gpa, 1);
44 // This length does not include a null byte. Let's keep it this way to
45 // gently encourage WASI implementations to behave properly.
46 const name_len = prestat.u.dir.pr_name_len;
47 const name = try gpa.alloc(u8, name_len);
48 errdefer gpa.free(name);
49 switch (wasi.fd_prestat_dir_name(fd, name.ptr, name.len)) {
50 .SUCCESS => {},
51 else => @panic("fd_prestat_dir_name: unexpected error"),
52 }
53 names.appendAssumeCapacity(name);
54 }
55}