hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mfs/fs.ha | 30++++++++++++++++++++++++++++++
Mfs/types.ha | 19+++++++++++++++++++
Mos/+linux/dirfdfs.ha | 37++++++++++++++++++++++---------------
Mos/+linux/stdfd.ha | 12++++++------
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;