commit 43375866f18b7576e3368039af7edaa7617f0e13
parent 51543047bdb9dcf7a8206a5eeb0c1e0e3cae1fae
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 9 Mar 2021 14:40:03 -0500
fs, os: unify open & create semantics
Diffstat:
5 files changed, 119 insertions(+), 114 deletions(-)
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -10,18 +10,30 @@ export fn close(fs: *fs) void = {
};
// Opens a file.
-export fn open(fs: *fs, path: path::path, mode: io::mode) (*io::stream | error) = {
+//
+// If no flags are provided, the default read/write mode is RDONLY.
+export fn open(
+ fs: *fs,
+ path: path::path,
+ flags: flags...
+) (*io::stream | error) = {
return match (fs.open) {
null => io::unsupported,
- f: *openfunc => f(fs, path, mode),
+ f: *openfunc => f(fs, path, flags...),
};
};
-// Creates a new file. The default file permissions are implementation defined.
-export fn create(fs: *fs, path: path::path, mode: io::mode) (*io::stream | error) = {
+// 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(
+ fs: *fs,
+ path: path::path,
+ mode: uint,
+ flags: flags...
+) (*io::stream | error) = {
return match (fs.create) {
null => io::unsupported,
- f: *createfunc => f(fs, path, mode),
+ f: *createfunc => f(fs, path, mode, flags...),
};
};
diff --git a/fs/types.ha b/fs/types.ha
@@ -139,9 +139,27 @@ export fn dirent_free(e: dirent) void = match (e.name) {
b: []u8 => free(b),
};
+// 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,
+ TRUNC = 0o1000,
+ APPEND = 0o2000,
+ NONBLOCK = 0o4000,
+ DSYNC = 0o10000,
+ SYNC = 0o4010000,
+ RSYNC = 0o4010000,
+ DIRECTORY = 0o200000,
+ NOFOLLOW = 0o400000,
+ CLOEXEC = 0o2000000,
+};
+
export type closefunc = fn(fs: *fs) void;
-export type openfunc = fn(fs: *fs, path: path::path, mode: io::mode) (*io::stream | error);
-export type createfunc = fn(fs: *fs, path: path::path, mode: io::mode) (*io::stream | error);
export type iterfunc = fn(fs: *fs, path: path::path) (*iterator | error);
export type statfunc = fn(fs: *fs, path: path::path) (filestat | error);
export type subdirfunc = fn(fs: *fs, path: path::path) (*fs | error);
@@ -149,6 +167,19 @@ export type mkdirfunc = fn(fs: *fs, path: path::path) (void | error);
export type mksubdirfunc = fn(fs: *fs, path: path::path) (*fs | error);
export type resolvefunc = fn(fs: *fs, path: path::path) path::path;
+export type openfunc = fn(
+ fs: *fs,
+ path: path::path,
+ flags: flags...
+) (*io::stream | error);
+
+export type createfunc = fn(
+ fs: *fs,
+ path: path::path,
+ mode: uint,
+ flags: flags...
+) (*io::stream | error);
+
// An abstract implementation of a filesystem. To create a custom stream, embed
// this type as the first member of a struct with user-specific data and fill
// out these fields as appropriate.
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -167,7 +167,7 @@ fn scan_file(
path: path::path,
deps: *[]ast::ident,
) ([]u8 | error) = {
- let f = fs::open(ctx.fs, path, io::mode::READ)?;
+ let f = fs::open(ctx.fs, path)?;
defer io::close(f);
let sha = sha256::sha256();
//defer! hash::close(sha);
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -60,6 +60,11 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = {
// Opens a file descriptor as an [fs::fs]. This file descriptor must be a
// directory file. The file will be closed when the fs is closed.
+//
+// If no other flags are provided to [fs::open] and [fs::create] when used with
+// a dirfdfs, [fs::flags::NOCTTY] and [fs::flags::CLOEXEC] are used when opening
+// the file. If you pass your own flags, it is recommended that you add these
+// unless you know that you do not want them.
export fn dirfdopen(fd: int, resolve: resolve...) *fs::fs = {
let ofs = alloc(os_filesystem { ... });
let fs = static_dirfdopen(fd, ofs);
@@ -118,38 +123,69 @@ fn _fs_open(
return fdopen(fd, name, mode);
};
-fn fs_open(fs: *fs::fs, path: path::path, mode: io::mode) (*io::stream | fs::error) = {
- let oflags = rt::O_NOCTTY | rt::O_CLOEXEC;
- if (mode & io::mode::RDWR == io::mode::RDWR) {
- oflags |= rt::O_RDWR;
- } else if (mode & io::mode::READ == io::mode::READ) {
- oflags |= rt::O_RDONLY;
- } else if (mode & io::mode::WRITE == io::mode::WRITE) {
- oflags |= rt::O_WRONLY;
+fn fs_open(
+ fs: *fs::fs,
+ path: path::path,
+ flags: fs::flags...
+) (*io::stream | fs::error) = {
+ let oflags = 0;
+ let iomode = io::mode::NONE;
+ if (len(flags) == 0z) {
+ oflags |= (fs::flags::NOCTTY
+ | fs::flags::CLOEXEC
+ | fs::flags::RDONLY): int;
+ };
+ for (let i = 0z; i < len(flags); i += 1z) {
+ oflags |= flags[i]: int;
+ };
+
+ if (oflags: fs::flags & fs::flags::RDWR == fs::flags::RDWR) {
+ iomode = io::mode::RDWR;
+ } else if (oflags: fs::flags & fs::flags::RDONLY == fs::flags::RDONLY) {
+ iomode = io::mode::READ;
+ } else if (oflags: fs::flags & fs::flags::RDONLY == fs::flags::RDONLY) {
+ iomode = io::mode::WRITE;
};
let oh = rt::open_how {
flags = oflags: u64,
...
};
- return _fs_open(fs, path, mode, &oh);
+ return _fs_open(fs, path, iomode, &oh);
};
-fn fs_create(fs: *fs::fs, path: path::path, mode: io::mode) (*io::stream | fs::error) = {
- let oflags = rt::O_NOCTTY | rt::O_CLOEXEC | rt::O_CREATE;
- if (mode & io::mode::RDWR == io::mode::RDWR) {
- oflags |= rt::O_RDWR;
- } else if (mode & io::mode::READ == io::mode::READ) {
- oflags |= rt::O_RDONLY;
- } else if (mode & io::mode::WRITE == io::mode::WRITE) {
- oflags |= rt::O_WRONLY;
+fn fs_create(
+ fs: *fs::fs,
+ path: path::path,
+ mode: uint,
+ flags: fs::flags...
+) (*io::stream | fs::error) = {
+ let oflags = 0;
+ let iomode = io::mode::NONE;
+ if (len(flags) == 0z) {
+ oflags |= (fs::flags::NOCTTY
+ | fs::flags::CLOEXEC
+ | fs::flags::WRONLY): int;
+ };
+ for (let i = 0z; i < len(flags); i += 1z) {
+ oflags |= flags[i]: int;
+ };
+ oflags |= fs::flags::CREATE: int;
+
+ if (oflags: fs::flags & fs::flags::RDWR == fs::flags::RDWR) {
+ iomode = io::mode::RDWR;
+ } else if (oflags: fs::flags & fs::flags::RDONLY == fs::flags::RDONLY) {
+ iomode = io::mode::READ;
+ } else if (oflags: fs::flags & fs::flags::RDONLY == fs::flags::RDONLY) {
+ iomode = io::mode::WRITE;
};
let oh = rt::open_how {
flags = oflags: u64,
+ mode = mode: u64,
...
};
- return _fs_open(fs, path, mode, &oh);
+ return _fs_open(fs, path, iomode, &oh);
};
fn fs_stat(fs: *fs::fs, path: path::path) (fs::filestat | fs::error) = {
diff --git a/os/+linux/open.ha b/os/+linux/open.ha
@@ -1,100 +1,26 @@
use fs;
use io;
use path;
-use rt;
-use strings;
-
-// 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,
- TRUNC = 0o1000,
- APPEND = 0o2000,
- NONBLOCK = 0o4000,
- DSYNC = 0o10000,
- SYNC = 0o4010000,
- RSYNC = 0o4010000,
- DIRECTORY = 0o200000,
- NOFOLLOW = 0o400000,
- CLOEXEC = 0o2000000,
-};
// Opens a file from the filesystem.
//
-// If no flags are provided, the default for +linux is RDONLY | NOCTTY | CLOEXEC.
+// If no flags are provided, [fs::flags::RDONLY], [fs::flags::NOCTTY],
+// [fs::flags::CLOEXEC] are used when opening the file. If you pass your own
+// flags, it is recommended that you add the latter two unless you know that you
+// do not want them.
export fn open(
path: path::path,
- flag: flags...
-) (*io::stream | io::error) = {
- 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;
- };
+ flags: fs::flags...
+) (*io::stream | fs::error) = fs::open(cwd, path, flags...);
- let fd: int = match (rt::open(path, 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.
+// Opens a file from the filesystem.
+//
+// If no flags are provided, [fs::flags::WRONLY], [fs::flags::NOCTTY],
+// [fs::flags::CLOEXEC] are used when opening the file. If you pass your own
+// flags, it is recommended that you add the latter two unless you know that you
+// do not want them.
export fn create(
path: path::path,
mode: uint,
- flag: flags...
-) (*io::stream | io::error) = {
- 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::WRONLY): int;
- };
- for (let i = 0z; i < len(flag); i += 1z) {
- 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(path, oflags, mode)) {
- err: rt::errno => return errno_to_io(err),
- n: int => n,
- };
-
- return fdopen(fd, name, iomode);
-};
+ flags: fs::flags...
+) (*io::stream | fs::error) = fs::create(cwd, path, mode, flags...);