commit a8d004bdfc29e49420d42fd873669e2f53a3e9ec
parent f0e41c90d0d19f77603d44c4e51dbe3554d6ac82
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 24 Feb 2021 09:20:53 -0500
os: refine the open & create APIs
Diffstat:
5 files changed, 91 insertions(+), 26 deletions(-)
diff --git a/io/types.ha b/io/types.ha
@@ -25,12 +25,15 @@ export fn errstr(err: error) str = {
};
};
-export type mode = enum uint {
- RDONLY = 0,
- WRONLY = 1,
- RDWR = 2,
+// Used to indicate if a stream should be used for reading, or writing, or both.
+export type mode = enum u8 {
+ NONE = 0,
+ READ = 1 << 0,
+ WRITE = 1 << 1,
+ RDWR = READ | WRITE,
};
+// From "whence" a seek operation should occur.
export type whence = enum {
SET = 0,
CUR = 1,
diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha
@@ -20,10 +20,10 @@ fn static_fdopen(
},
fd = fd,
};
- if (mode == io::mode::RDONLY || mode == io::mode::RDWR) {
+ if (mode & io::mode::READ == io::mode::READ) {
stream.stream.reader = &fd_read;
};
- if (mode == io::mode::WRONLY || mode == io::mode::RDWR) {
+ if (mode & io::mode::WRITE == io::mode::WRITE) {
stream.stream.writer = &fd_write;
};
return &stream.stream;
diff --git a/os/+linux/open.ha b/os/+linux/open.ha
@@ -2,8 +2,12 @@ use io;
use rt;
use strings;
-export type flags = enum {
- NONE = 0,
+// Flags to use for opening a file. Not all operating systems support all flags;
+// at a minimum, RDONLY, WRONLY, RDWR, and CREATE will be supported.
+export type flags = enum int {
+ RDONLY = 0,
+ WRONLY = 1,
+ RDWR = 2,
CREATE = 0o100,
EXCLUSIVE = 0o200,
NOCTTY = 0o400,
@@ -20,17 +24,52 @@ export type flags = enum {
// Opens a file from the filesystem.
//
-// If no flags are provided, the default is NOCTTY | CLOEXEC.
+// If no flags are provided, the default for +linux is RDONLY | NOCTTY | CLOEXEC.
export fn open(
path: (str | []u8),
- mode: io::mode,
flag: flags...
) (*io::stream | io::error) = {
- // Verify that these line up with the Linux ABI:
- static assert(io::mode::RDONLY: int == rt::O_RDONLY);
- static assert(io::mode::WRONLY: int == rt::O_WRONLY);
- static assert(io::mode::RDWR: int == rt::O_RDWR);
+ const p: []u8 = match (path) {
+ s: str => strings::to_utf8(s),
+ b: []u8 => b,
+ };
+ const name: str = match (path) {
+ s: str => s,
+ b: []u8 => "<open([]u8)>",
+ };
+
+ let oflags = 0;
+ let iomode = io::mode::NONE;
+ if (len(flag) == 0z) {
+ oflags |= (flags::NOCTTY | flags::CLOEXEC | flags::RDONLY): int;
+ };
+ for (let i = 0z; i < len(flag); i += 1z) {
+ oflags |= flag[i]: int;
+ };
+ if (oflags: flags & flags::RDWR == flags::RDWR) {
+ iomode = io::mode::RDWR;
+ } else if (oflags: flags & flags::RDONLY == flags::RDONLY) {
+ iomode = io::mode::READ;
+ } else if (oflags: flags & flags::RDONLY == flags::RDONLY) {
+ iomode = io::mode::WRITE;
+ };
+
+ let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, 0u)) {
+ err: rt::errno => return errno_to_io(err),
+ n: int => n,
+ };
+
+ return fdopen(fd, name, iomode);
+};
+
+// Equivalent to [open], but allows the caller to specify a file mode for the
+// new file. If no other flag is given, the default read/write mode is WRONLY.
+export fn create(
+ path: (str | []u8),
+ mode: uint,
+ flag: flags...
+) (*io::stream | io::error) = {
const p: []u8 = match (path) {
s: str => strings::to_utf8(s),
b: []u8 => b,
@@ -40,18 +79,28 @@ export fn open(
b: []u8 => "<open([]u8)>",
};
- let m = mode: int;
+ let oflags = 0;
+ let iomode = io::mode::NONE;
if (len(flag) == 0z) {
- m |= flags::NOCTTY: int | flags::CLOEXEC: int;
+ oflags |= (flags::NOCTTY | flags::CLOEXEC | flags::WRONLY): int;
};
for (let i = 0z; i < len(flag); i += 1z) {
- m |= flag[i]: int;
+ oflags |= flag[i]: int;
+ };
+ oflags |= flags::CREATE: int;
+
+ if (oflags: flags & flags::RDWR == flags::RDWR) {
+ iomode = io::mode::RDWR;
+ } else if (oflags: flags & flags::RDONLY == flags::RDONLY) {
+ iomode = io::mode::READ;
+ } else if (oflags: flags & flags::RDONLY == flags::RDONLY) {
+ iomode = io::mode::WRITE;
};
- let fd: int = match (rt::open(p: *[*]u8: *const char, m, 0u)) {
+ let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, mode)) {
err: rt::errno => return errno_to_io(err),
n: int => n,
};
- return fdopen(fd, name, mode);
+ return fdopen(fd, name, iomode);
};
diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha
@@ -5,7 +5,7 @@ let static_stdout: fd_stream = fd_stream { ... };
let static_stderr: fd_stream = fd_stream { ... };
@init fn init_stdfd() void = {
- stdin = static_fdopen(0, "<stdin>", io::mode::RDONLY, &static_stdin);
- stdout = static_fdopen(1, "<stdout>", io::mode::WRONLY, &static_stdout);
- stderr = static_fdopen(2, "<stderr>", io::mode::WRONLY, &static_stderr);
+ stdin = static_fdopen(0, "<stdin>", io::mode::READ, &static_stdin);
+ stdout = static_fdopen(1, "<stdout>", io::mode::WRITE, &static_stdout);
+ stderr = static_fdopen(2, "<stderr>", io::mode::WRITE, &static_stderr);
};
diff --git a/rt/+linux/types.ha b/rt/+linux/types.ha
@@ -30,11 +30,24 @@ export def AT_STATX_FORCE_SYNC: int = 0x2000;
export def AT_STATX_DONT_SYNC: int = 0x4000;
export def AT_RECURSIVE: int = 0x8000;
-export def O_RDONLY: int = 0;
-export def O_WRONLY: int = 1;
-export def O_RDWR: int = 2;
-// TODO: Add the other flags:
+export def O_RDONLY: int = 0o0;
+export def O_WRONLY: int = 0o1;
+export def O_RDWR: int = 0o2;
+export def O_CREATE: int = 0o100;
+export def O_EXCLUSIVE: int = 0o200;
+export def O_NOCTTY: int = 0o400;
+export def O_TRUNC: int = 0o1000;
+export def O_APPEND: int = 0o2000;
+export def O_NONBLOCK: int = 0o4000;
+export def O_DSYNC: int = 0o10000;
+export def O_SYNC: int = 0o4010000;
+export def O_RSYNC: int = 0o4010000;
+export def O_DIRECTORY: int = 0o200000;
+export def O_NOFOLLOW: int = 0o400000;
+export def O_NOATIME: int = 0o1000000;
export def O_CLOEXEC: int = 0o2000000;
+export def O_PATH: int = 0o10000000;
+export def O_TMPFILE: int = 0o20000000;
type statx_timestamp = struct {
tv_sec: i64,