authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2023-07-08 09:17:28-04:00
committergravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2023-08-02 17:39:52-04:00
logb9aa1dcaf1a905682ee4da6b9c37626ed2a552a6
treedc32e96fd947205d49c7e303b01738266303a2c2
parent6293a646e33d2cfe064d4475f42f7d77a3831cf4

plan 9: filesystem support


3 files changed, 74 insertions(+), 24 deletions(-)

lib/std/fs.zig+6-4
...@@ -39,7 +39,7 @@ pub const Watch = @import("fs/watch.zig").Watch;...@@ -39,7 +39,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
39/// fit into a UTF-8 encoded array of this length.39/// fit into a UTF-8 encoded array of this length.
40/// The byte count includes room for a null sentinel byte.40/// The byte count includes room for a null sentinel byte.
41pub const MAX_PATH_BYTES = switch (builtin.os.tag) {41pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
42 .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris => os.PATH_MAX,42 .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .plan9 => os.PATH_MAX,
43 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.43 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
44 // If it would require 4 UTF-8 bytes, then there would be a surrogate44 // If it would require 4 UTF-8 bytes, then there would be a surrogate
45 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.45 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
...@@ -1160,7 +1160,9 @@ pub const Dir = struct {...@@ -1160,7 +1160,9 @@ pub const Dir = struct {
1160 return self.openFileW(path_w.span(), flags);1160 return self.openFileW(path_w.span(), flags);
1161 }1161 }
11621162
1163 var os_flags: u32 = os.O.CLOEXEC;1163 var os_flags: u32 = 0;
1164 if (@hasDecl(os.O, "CLOEXEC")) os_flags = os.O.CLOEXEC;
1165
1164 // Use the O locking flags if the os supports them to acquire the lock1166 // Use the O locking flags if the os supports them to acquire the lock
1165 // atomically.1167 // atomically.
1166 const has_flock_open_flags = @hasDecl(os.O, "EXLOCK");1168 const has_flock_open_flags = @hasDecl(os.O, "EXLOCK");
...@@ -1180,7 +1182,7 @@ pub const Dir = struct {...@@ -1180,7 +1182,7 @@ pub const Dir = struct {
1180 if (@hasDecl(os.O, "LARGEFILE")) {1182 if (@hasDecl(os.O, "LARGEFILE")) {
1181 os_flags |= os.O.LARGEFILE;1183 os_flags |= os.O.LARGEFILE;
1182 }1184 }
1183 if (!flags.allow_ctty) {1185 if (@hasDecl(os.O, "NOCTTY") and !flags.allow_ctty) {
1184 os_flags |= os.O.NOCTTY;1186 os_flags |= os.O.NOCTTY;
1185 }1187 }
1186 os_flags |= switch (flags.mode) {1188 os_flags |= switch (flags.mode) {
...@@ -1196,7 +1198,7 @@ pub const Dir = struct {...@@ -1196,7 +1198,7 @@ pub const Dir = struct {
11961198
1197 // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block1199 // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block
1198 // since it is not compiltime-known and we need to avoid undefined symbol in Wasm.1200 // since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
1199 if (builtin.target.os.tag != .wasi) {1201 if (@hasDecl(os.system, "LOCK") and builtin.target.os.tag != .wasi) {
1200 if (!has_flock_open_flags and flags.lock != .none) {1202 if (!has_flock_open_flags and flags.lock != .none) {
1201 // TODO: integrate async I/O1203 // TODO: integrate async I/O
1202 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0);1204 const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0);
lib/std/os/plan9.zig+60-20
...@@ -1,6 +1,12 @@...@@ -1,6 +1,12 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub const fd_t = i32;
5
6pub const STDIN_FILENO = 0;
7pub const STDOUT_FILENO = 1;
8pub const STDERR_FILENO = 2;
9pub const PATH_MAX = 1023;
4pub const syscall_bits = switch (builtin.cpu.arch) {10pub const syscall_bits = switch (builtin.cpu.arch) {
5 .x86_64 => @import("plan9/x86_64.zig"),11 .x86_64 => @import("plan9/x86_64.zig"),
6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),12 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
...@@ -57,7 +63,8 @@ pub const SIG = struct {...@@ -57,7 +63,8 @@ pub const SIG = struct {
57};63};
58pub const sigset_t = c_long;64pub const sigset_t = c_long;
59pub const empty_sigset = 0;65pub const empty_sigset = 0;
60pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.66pub const siginfo_t = c_long;
67// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.
61pub const Sigaction = extern struct {68pub const Sigaction = extern struct {
62 pub const handler_fn = *const fn (c_int) callconv(.C) void;69 pub const handler_fn = *const fn (c_int) callconv(.C) void;
63 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;70 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
...@@ -69,6 +76,9 @@ pub const Sigaction = extern struct {...@@ -69,6 +76,9 @@ pub const Sigaction = extern struct {
69 mask: sigset_t,76 mask: sigset_t,
70 flags: c_int,77 flags: c_int,
71};78};
79pub const AT = struct {
80 pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
81};
72// TODO implement sigaction82// TODO implement sigaction
73// right now it is just a shim to allow using start.zig code83// right now it is just a shim to allow using start.zig code
74pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {84pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
...@@ -132,20 +142,47 @@ pub const SYS = enum(usize) {...@@ -132,20 +142,47 @@ pub const SYS = enum(usize) {
132 _NSEC = 53,142 _NSEC = 53,
133};143};
134144
135pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {145pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
136 return syscall_bits.syscall4(.PWRITE, fd, @intFromPtr(buf), count, offset);146 return syscall_bits.syscall3(._WRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count);
147}
148pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
149 return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset);
137}150}
138151
139pub fn pread(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {152pub fn read(fd: i32, buf: [*]const u8, count: usize) usize {
140 return syscall_bits.syscall4(.PREAD, fd, @intFromPtr(buf), count, offset);153 return syscall_bits.syscall3(._READ, @bitCast(@as(isize, fd)), @intFromPtr(buf), count);
154}
155pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
156 return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset);
157}
158
159pub fn open(path: [*:0]const u8, omode: mode_t) usize {
160 return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, omode)));
161}
162
163pub fn openat(dirfd: i32, path: [*:0]const u8, _: u32, omode: mode_t) usize {
164 if (dirfd == AT.FDCWD) { // openat(AT_FDCWD, ...) == open(...)
165 return open(path, omode);
166 }
167 var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
168 var total_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined;
169 const rc = fd2path(dirfd, &dir_path_buf, std.fs.MAX_PATH_BYTES);
170 if (rc != 0) return rc;
171 var fba = std.heap.FixedBufferAllocator.init(&total_path_buf);
172 var alloc = fba.allocator();
173 const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf)));
174 const total_path = std.fs.path.join(alloc, &.{ dir_path, std.mem.span(path) }) catch unreachable; // the allocation shouldn't fail because it should not exceed MAX_PATH_BYTES
175 fba.reset();
176 const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed MAX_PATH_BYTES + 1
177 return open(total_path_z.ptr, omode);
141}178}
142179
143pub fn open(path: [*:0]const u8, omode: OpenMode) usize {180pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize {
144 return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @intFromEnum(omode));181 return syscall_bits.syscall3(.FD2PATH, @bitCast(@as(isize, fd)), @intFromPtr(buf), nbuf);
145}182}
146183
147pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize {184pub fn create(path: [*:0]const u8, omode: mode_t, perms: usize) usize {
148 return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @intFromEnum(omode), perms);185 return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @bitCast(@as(isize, omode)), perms);
149}186}
150187
151pub fn exit(status: u8) noreturn {188pub fn exit(status: u8) noreturn {
...@@ -163,16 +200,19 @@ pub fn exits(status: ?[*:0]const u8) noreturn {...@@ -163,16 +200,19 @@ pub fn exits(status: ?[*:0]const u8) noreturn {
163 unreachable;200 unreachable;
164}201}
165202
166pub fn close(fd: usize) usize {203pub fn close(fd: i32) usize {
167 return syscall_bits.syscall1(.CLOSE, fd);204 return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
168}205}
169pub const OpenMode = enum(usize) {206pub const mode_t = i32;
170 OREAD = 0, //* open for read207pub const O = struct {
171 OWRITE = 1, //* write208 pub const READ = 0; // open for read
172 ORDWR = 2, //* read and write209 pub const RDONLY = 0;
173 OEXEC = 3, //* execute, == read but check execute permission210 pub const WRITE = 1; // write
174 OTRUNC = 16, //* or'ed in (except for exec), truncate file first211 pub const WRONLY = 1;
175 OCEXEC = 32, //* or'ed in (per file descriptor), close on exec212 pub const RDWR = 2; // read and write
176 ORCLOSE = 64, //* or'ed in, remove on close213 pub const EXEC = 3; // execute, == read but check execute permission
177 OEXCL = 0x1000, //* or'ed in, exclusive create214 pub const TRUNC = 16; // or'ed in (except for exec), truncate file first
215 pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec
216 pub const RCLOSE = 64; // or'ed in, remove on close
217 pub const EXCL = 0x1000; // or'ed in, exclusive create
178};218};
lib/std/os/plan9/errno.zig+8
...@@ -73,4 +73,12 @@ pub const E = enum(u16) {...@@ -73,4 +73,12 @@ pub const E = enum(u16) {
73 // These added in 1003.1b-199373 // These added in 1003.1b-1993
74 CANCELED = 61,74 CANCELED = 61,
75 INPROGRESS = 62,75 INPROGRESS = 62,
76
77 // We just add these to be compatible with std.os, which uses them,
78 // They should never get used.
79 DQUOT,
80 CONNRESET,
81 OVERFLOW,
82 LOOP,
83 TXTBSY,
76};84};