hare

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

commit b31e1448a36dec44480b3414a7da3b56f9048fc9
parent 00cb3797fb9c4f4be58f2d9dc24c70b1661e4fd3
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 25 Feb 2021 13:21:36 -0500

os::dirfdfs: implement stat

Diffstat:
Mfs/types.ha | 2++
Mos/+linux/dirfdfs.ha | 46+++++++++++++++++++++++++++++-----------------
Mos/+linux/open.ha | 17+++++------------
Mrt/+linux/types.ha | 1-
4 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/fs/types.ha b/fs/types.ha @@ -87,6 +87,7 @@ export type stat_mask = enum uint { UID = 1 << 0, GID = 1 << 1, SIZE = 1 << 2, + INODE = 1 << 3, }; // Information about a file or directory. The mask field defines what other @@ -97,6 +98,7 @@ export type filestat = struct { uid: uint, gid: uint, sz: size, + inode: u64, // TODO: atime et al }; diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha @@ -54,6 +54,14 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = { return &filesystem.fs; }; +fn pathbytes(path: fs::path) *const char = { + let p = match (path) { + s: str => strings::to_utf8(s), + b: []u8 => b, + }; + return p: *[*]u8: *const char; +}; + // 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. export fn dirfdopen(fd: int, resolve: resolve...) *fs::fs = { @@ -101,16 +109,12 @@ fn _fs_open( oh.resolve |= rt::RESOLVE_NO_XDEV; }; - 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 fd = match (rt::openat2(fs.dirfd, p: *[*]u8: *const char, + let fd = match (rt::openat2(fs.dirfd, pathbytes(path), oh, size(rt::open_how))) { err: rt::errno => return errno_to_io(err), fd: int => fd, @@ -154,22 +158,34 @@ fn fs_create(fs: *fs::fs, path: fs::path, mode: io::mode) (*io::stream | fs::err }; fn fs_stat(fs: *fs::fs, path: fs::path) (fs::filestat | fs::error) = { - abort(); // TODO + let fs = fs: *os_filesystem; + let st = rt::st { ... }; + match (rt::fstatat(fs.dirfd, pathbytes(path), + &st, rt::AT_SYMLINK_NOFOLLOW)) { + err: rt::errno => return errno_to_io(err), + void => void, + }; + return fs::filestat { + mask = fs::stat_mask::UID + | fs::stat_mask::GID + | fs::stat_mask::SIZE + | fs::stat_mask::INODE, + mode = st.mode: fs::mode, + uid = st.uid, + uid = st.gid, + sz = st.sz, + inode = st.ino, + }; }; fn fs_subdir(fs: *fs::fs, path: fs::path) (*fs::fs | fs::error) = { let fs = fs: *os_filesystem; - const p: []u8 = match (path) { - s: str => strings::to_utf8(s), - b: []u8 => b, - }; - let oh = rt::open_how { flags = (rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY): u64, ... }; - let fd: int = match (rt::openat2(fs.dirfd, p: *[*]u8: *const char, + let fd: int = match (rt::openat2(fs.dirfd, pathbytes(path), &oh, size(rt::open_how))) { err: rt::errno => return errno_to_io(err), n: int => n, @@ -196,15 +212,11 @@ type os_iterator = struct { fn fs_iter(fs: *fs::fs, path: fs::path) (*fs::iterator | fs::error) = { let fs = fs: *os_filesystem; - const p: []u8 = match (path) { - s: str => strings::to_utf8(s), - b: []u8 => b, - }; let oh = rt::open_how { flags = (rt::O_RDONLY | rt::O_CLOEXEC | rt::O_DIRECTORY): u64, ... }; - let fd: int = match (rt::openat2(fs.dirfd, p: *[*]u8: *const char, + let fd: int = match (rt::openat2(fs.dirfd, pathbytes(path), &oh, size(rt::open_how))) { err: rt::errno => return errno_to_io(err), n: int => n, diff --git a/os/+linux/open.ha b/os/+linux/open.ha @@ -1,3 +1,4 @@ +use fs; use io; use rt; use strings; @@ -26,13 +27,9 @@ export type flags = enum int { // // If no flags are provided, the default for +linux is RDONLY | NOCTTY | CLOEXEC. export fn open( - path: (str | []u8), + path: fs::path, flag: flags... ) (*io::stream | io::error) = { - 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)>", @@ -55,7 +52,7 @@ export fn open( iomode = io::mode::WRITE; }; - let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, 0u)) { + let fd: int = match (rt::open(pathbytes(path), oflags, 0u)) { err: rt::errno => return errno_to_io(err), n: int => n, }; @@ -66,14 +63,10 @@ export fn open( // 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), + path: fs::path, mode: uint, flag: flags... ) (*io::stream | io::error) = { - 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)>", @@ -97,7 +90,7 @@ export fn create( iomode = io::mode::WRITE; }; - let fd: int = match (rt::open(p: *[*]u8: *const char, oflags, mode)) { + let fd: int = match (rt::open(pathbytes(path), oflags, mode)) { err: rt::errno => return errno_to_io(err), n: int => n, }; diff --git a/rt/+linux/types.ha b/rt/+linux/types.ha @@ -80,7 +80,6 @@ type stx = struct { // Note: the st type does not match the kernel API. The kernel API has a stat // buffer which varies from arch to arch, but because we always use statx(2) and // copy the data from the stx type, we don't have to deal with that nonsense. - export type st = struct { dev: dev_t, ino: ino_t,