commit 6f18f08a09d74f724fb0ffafc4a4618d44933f5b
parent 356b923c76e5abd1b2afb4bef24a8e478791b985
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 2 Jan 2024 12:34:00 +0100
os, fs: add fstat
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
4 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -176,6 +176,16 @@ export fn stat(fs: *fs, path: str) (filestat | error) = {
};
};
+// Obtains information about an [[io::file]].
+export fn fstat(fs: *fs, fd: io::file) (filestat | error) = {
+ match (fs.fstat) {
+ case null =>
+ return errors::unsupported;
+ case let f: *fstatfunc =>
+ return f(fs, fd);
+ };
+};
+
// Returns true if a node exists at the given path, or false if not.
//
// Note that testing for file existence before using the file can often lead to
diff --git a/fs/types.ha b/fs/types.ha
@@ -203,6 +203,7 @@ export type removefunc = fn(fs: *fs, path: str) (void | error);
export type renamefunc = fn(fs: *fs, oldpath: str, newpath: str) (void | error);
export type iterfunc = fn(fs: *fs, path: str) (*iterator | error);
export type statfunc = fn(fs: *fs, path: str) (filestat | error);
+export type fstatfunc = fn(fs: *fs, file: io::file) (filestat | error);
export type mkdirfunc = fn(fs: *fs, path: str, mode: mode) (void | error);
export type rmdirfunc = fn(fs: *fs, path: str) (void | error);
export type chmodfunc = fn(fs: *fs, path: str, mode: mode) (void | error);
@@ -279,6 +280,9 @@ export type fs = struct {
// target.
stat: nullable *statfunc,
+ // Obtains information about an [[io::file]].
+ fstat: nullable *fstatfunc,
+
// Returns the path referred to by a symbolic link. The caller will free
// the return value.
readlink: nullable *readlinkfunc,
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -70,6 +70,7 @@ fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
rename = &fs_rename,
iter = &fs_iter,
stat = &fs_stat,
+ fstat = &fs_fstat,
readlink = &fs_readlink,
mkdir = &fs_mkdir,
rmdir = &fs_rmdir,
@@ -259,6 +260,21 @@ fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = {
return errno_to_fs(err);
case void => void;
};
+ return st_to_filestat(&st);
+};
+
+fn fs_fstat(fs: *fs::fs, fd: io::file) (fs::filestat | fs::error) = {
+ let fs = fs: *os_filesystem;
+ let st = rt::st { ... };
+ match (rt::fstatat(fd, "", &st, rt::AT_EMPTY_PATH)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+ return st_to_filestat(&st);
+};
+
+fn st_to_filestat(st: *rt::st) fs::filestat = {
return fs::filestat {
mask = fs::stat_mask::UID
| fs::stat_mask::GID
diff --git a/os/os.ha b/os/os.ha
@@ -35,6 +35,9 @@ export fn readdir(path: str) ([]fs::dirent | fs::error) = fs::readdir(cwd, path)
// information is returned about the link, not its target.
export fn stat(path: str) (fs::filestat | fs::error) = fs::stat(cwd, path);
+// Returns file information for an [[io::file]].
+export fn fstat(fd: io::file) (fs::filestat | fs::error) = fs::fstat(cwd, fd);
+
// Returns true if a node exists at the given path, or false if not.
//
// Note that testing for file existence before using the file can often lead to