commit 31b5c8a01444a2db589a30b0ed81ffb37b547a4c
parent d6bffa900ca7098709078984f7a7e64dc8c0722d
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 4 Sep 2021 10:27:18 +0200
fs: add open_file and create_file
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
4 files changed, 77 insertions(+), 21 deletions(-)
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -19,6 +19,18 @@ export fn open(fs: *fs, path: str, flags: flags...) (*io::stream | error) = {
};
};
+// Opens a file, as an [[io::file]]. This file will be backed by an open file
+// handle on the host operating system, which may not be possible with all
+// filesystem implementations (such cases will return [[io::unsupported]]).
+//
+// If no flags are provided, the default read/write mode is RDONLY.
+export fn open_file(fs: *fs, path: str, flags: flags...) (*io::file | error) = {
+ return match (fs.openfile) {
+ null => errors::unsupported,
+ f: *openfilefunc => f(fs, path, flags...),
+ };
+};
+
// Creates a new file and opens it for writing. If no flags are provided, the
// default read/write mode is WRONLY.
export fn create(
@@ -33,6 +45,24 @@ export fn create(
};
};
+// Creates a new file, as an [[io::file]], and opens it for writing. This file
+// will be backed by an open file handle on the host operating system, which may
+// not be possible with all filesystem implementations (such cases will return
+// [[io::unsupported]]).
+//
+// If no flags are provided, the default read/write mode is WRONLY.
+export fn create_file(
+ fs: *fs,
+ path: str,
+ mode: mode,
+ flags: flags...
+) (*io::file | error) = {
+ return match (fs.createfile) {
+ null => errors::unsupported,
+ f: *createfilefunc => f(fs, path, mode, flags...),
+ };
+};
+
// Removes a file.
export fn remove(fs: *fs, path: str) (void | error) = {
return match (fs.remove) {
diff --git a/fs/types.ha b/fs/types.ha
@@ -183,6 +183,12 @@ export type openfunc = fn(
flags: flags...
) (*io::stream | error);
+export type openfilefunc = fn(
+ fs: *fs,
+ path: str,
+ flags: flags...
+) (*io::file | error);
+
export type createfunc = fn(
fs: *fs,
path: str,
@@ -190,6 +196,13 @@ export type createfunc = fn(
flags: flags...
) (*io::stream | error);
+export type createfilefunc = fn(
+ fs: *fs,
+ path: str,
+ mode: mode,
+ flags: flags...
+) (*io::file | error);
+
// An abstract implementation of a filesystem, which provides common filesystem
// operations such as file creation and deletion, but which may be backed by any
// underlying storage system. See [[os::cwd]] for access to the host filesystem.
@@ -204,9 +217,15 @@ export type fs = struct {
// Opens a file.
open: nullable *openfunc,
+ // Opens a file as an [[io::file]].
+ openfile: nullable *openfilefunc,
+
// Creates a new file.
create: nullable *createfunc,
+ // Creates a new file as an [[io::file]].
+ createfile: nullable *createfilefunc,
+
// Removes a file.
remove: nullable *removefunc,
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -65,7 +65,9 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = {
*filesystem = os_filesystem {
fs = fs::fs {
open = &fs_open,
+ openfile = &fs_open_file,
create = &fs_create,
+ createfile = &fs_create_file,
remove = &fs_remove,
rename = &fs_rename,
iter = &fs_iter,
@@ -124,7 +126,7 @@ fn _fs_open(
path: str,
mode: io::mode,
oh: *rt::open_how,
-) (*io::stream | fs::error) = {
+) (*io::file | fs::error) = {
let fs = fs: *os_filesystem;
oh.resolve = 0u64;
@@ -146,22 +148,14 @@ fn _fs_open(
fd: int => fd,
};
- // XXX: It would be nice to get rid of this allocation, if possible.
- let file = alloc(fdopen(fd, path, mode));
- file.closer = &_fs_file_close;
- return file;
+ return io::fdalloc(fd, path, mode);
};
-fn _fs_file_close(s: *io::stream) void = {
- fd_close(s);
- free(s);
-};
-
-fn fs_open(
+fn fs_open_file(
fs: *fs::fs,
path: str,
flags: fs::flags...
-) (*io::stream | fs::error) = {
+) (*io::file | fs::error) = {
let oflags = 0;
let iomode = io::mode::NONE;
if (len(flags) == 0z) {
@@ -194,12 +188,18 @@ fn fs_open(
return _fs_open(fs, path, iomode, &oh);
};
-fn fs_create(
+fn fs_open(
+ fs: *fs::fs,
+ path: str,
+ flags: fs::flags...
+) (*io::stream | fs::error) = fs_open_file(fs, path, flags...)?;
+
+fn fs_create_file(
fs: *fs::fs,
path: str,
mode: fs::mode,
flags: fs::flags...
-) (*io::stream | fs::error) = {
+) (*io::file | fs::error) = {
let oflags = 0;
let iomode = io::mode::NONE;
if (len(flags) == 0z) {
@@ -225,9 +225,16 @@ fn fs_create(
mode = mode: u64,
...
};
- return _fs_open(fs, path, iomode, &oh);
+ return _fs_open(fs, path, iomode, &oh)?;
};
+fn fs_create(
+ fs: *fs::fs,
+ path: str,
+ mode: fs::mode,
+ flags: fs::flags...
+) (*io::stream | fs::error) = fs_create_file(fs, path, mode, flags...)?;
+
fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = {
let fs = fs: *os_filesystem;
match (rt::unlinkat(fs.dirfd, path, 0)) {
diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha
@@ -1,9 +1,9 @@
use bufio;
use io;
-let static_stdin_fd: fdstream = fdstream { ... };
-let static_stdout_fd: fdstream = fdstream { ... };
-let static_stderr_fd: fdstream = fdstream { ... };
+let static_stdin_fd: io::file = fdstream { ... };
+let static_stdout_fd: io::file = fdstream { ... };
+let static_stderr_fd: io::file = fdstream { ... };
let static_stdin_bufio: bufio::bufstream = bufio::bufstream { ... };
let static_stdout_bufio: bufio::bufstream = bufio::bufstream { ... };
@@ -12,9 +12,9 @@ let static_stdout_bufio: bufio::bufstream = bufio::bufstream { ... };
export def BUFSIZ: size = 4096; // 4 KiB
@init fn init_stdfd() void = {
- static_stdin_fd = fdopen(0, "<stdin>", io::mode::READ);
- static_stdout_fd = fdopen(1, "<stdout>", io::mode::WRITE);
- static_stderr_fd = fdopen(2, "<stderr>", io::mode::WRITE);
+ static_stdin_fd = io::fdopen(0, "<stdin>", io::mode::READ);
+ static_stdout_fd = io::fdopen(1, "<stdout>", io::mode::WRITE);
+ static_stderr_fd = io::fdopen(2, "<stderr>", io::mode::WRITE);
stdin = &static_stdin_fd;
stdout = &static_stdout_fd;
stderr = &static_stderr_fd;