commit b31e1448a36dec44480b3414a7da3b56f9048fc9
parent 00cb3797fb9c4f4be58f2d9dc24c70b1661e4fd3
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 25 Feb 2021 13:21:36 -0500
os::dirfdfs: implement stat
Diffstat:
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,