commit 4e7dd2a1e52188e04ab672bb42566fecfec448c1
parent 591bc229a525f211037c00ab6004fe945ee78f17
Author: Curtis Arthaud <uku82@gmx.fr>
Date: Sat, 6 Apr 2024 15:13:15 +0200
os: add chtimes, fchtimes
Signed-off-by: Curtis Arthaud <uku82@gmx.fr>
Diffstat:
6 files changed, 183 insertions(+), 0 deletions(-)
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -4,6 +4,7 @@
use errors;
use io;
use path;
+use time;
// Closes a filesystem. The fs cannot be used after this function is called.
export fn close(fs: *fs) void = {
@@ -273,6 +274,38 @@ export fn chown(fs: *fs, path: str, uid: uint, gid: uint) (void | error) = {
};
};
+// Changes the access and modification time of a file. A void value will leave
+// the corresponding time unchanged.
+export fn chtimes(
+ fs: *fs,
+ path: str,
+ atime: (time::instant | void),
+ mtime: (time::instant | void)
+) (void | error) = {
+ match (fs.chtimes) {
+ case null =>
+ return errors::unsupported;
+ case let f: *chtimesfunc =>
+ return f(fs, path, atime, mtime);
+ };
+};
+
+// Changes the access and modification time of an [[io::file]]. A void value
+// will leave the corresponding time unchanged.
+export fn fchtimes(
+ fs: *fs,
+ fd: io::file,
+ atime: (time::instant | void),
+ mtime: (time::instant | void)
+) (void | error) = {
+ match (fs.fchtimes) {
+ case null =>
+ return errors::unsupported;
+ case let f: *fchtimesfunc =>
+ return f(fd, atime, mtime);
+ };
+};
+
// Resolves a path to its absolute, normalized value. Relative paths will be
// rooted (if supported by the fs implementation), and "." and ".." components
// will be reduced. This function does not follow symlinks; see [[realpath]] if
diff --git a/fs/types.ha b/fs/types.ha
@@ -208,6 +208,10 @@ 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);
export type chownfunc = fn(fs: *fs, path: str, uid: uint, gid: uint) (void | error);
+export type chtimesfunc = fn(fs: *fs, path: str, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | error);
+export type fchtimesfunc = fn(fd: io::file, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | error);
export type resolvefunc = fn(fs: *fs, path: str) str;
export type readlinkfunc = fn(fs: *fs, path: str) (str | error);
export type linkfunc = fn(fs: *fs, old: str, new: str) (void | error);
@@ -299,6 +303,12 @@ export type fs = struct {
// Changes ownership of a file.
chown: nullable *chownfunc,
+ // Changes access and modification time of a file.
+ chtimes: nullable *chtimesfunc,
+
+ // Changes access and modification time of an [[io::file]].
+ fchtimes: nullable *fchtimesfunc,
+
// Resolves a path to its absolute, normalized value. If the fs
// implementation does not provide this, [resolve] presumes that
// relative paths are rooted (i.e. "foo" == "/foo").
diff --git a/os/+freebsd/dirfdfs.ha b/os/+freebsd/dirfdfs.ha
@@ -42,6 +42,8 @@ fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
rmdir = &fs_rmdir,
chmod = &fs_chmod,
chown = &fs_chown,
+ chtimes = &fs_chtimes,
+ fchtimes = &fs_fchtimes,
resolve = &fs_resolve,
...
},
@@ -316,6 +318,45 @@ fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = {
};
};
+fn instant_to_timespec(time: (time::instant | void)) rt::timespec = {
+ match (time) {
+ case let t: time::instant =>
+ return time::instant_to_timespec(t);
+ case void =>
+ return rt::timespec{
+ tv_sec = rt::UTIME_OMIT,
+ tv_nsec = rt::UTIME_OMIT
+ };
+ };
+};
+
+fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ let fs = fs: *os_filesystem;
+ match (rt::utimensat(fs.dirfd, path, &utimes, 0)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_fchtimes(fd: io::file, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ match (rt::futimens(fd, &utimes)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
fn fs_resolve(fs: *fs::fs, path: str) str = {
if (path::abs(path)) {
return path;
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -77,6 +77,8 @@ fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
rmdir = &fs_rmdir,
chmod = &fs_chmod,
chown = &fs_chown,
+ chtimes = &fs_chtimes,
+ fchtimes = &fs_fchtimes,
resolve = &fs_resolve,
link = &fs_link,
symlink = &fs_symlink,
@@ -345,6 +347,45 @@ fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = {
};
};
+fn instant_to_timespec(time: (time::instant | void)) rt::timespec = {
+ match (time) {
+ case let t: time::instant =>
+ return time::instant_to_timespec(t);
+ case void =>
+ return rt::timespec{
+ tv_sec = rt::UTIME_OMIT,
+ tv_nsec = rt::UTIME_OMIT
+ };
+ };
+};
+
+fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ let fs = fs: *os_filesystem;
+ match (rt::utimensat(fs.dirfd, path, &utimes, 0)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_fchtimes(fd: io::file, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ match (rt::futimens(fd, &utimes)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
fn fs_resolve(fs: *fs::fs, path: str) str = {
if (path::abs(path)) {
return path;
diff --git a/os/+openbsd/dirfdfs.ha b/os/+openbsd/dirfdfs.ha
@@ -342,6 +342,45 @@ fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = {
};
};
+fn instant_to_timespec(time: (time::instant | void)) rt::timespec = {
+ match (time) {
+ case let t: time::instant =>
+ return time::instant_to_timespec(t);
+ case void =>
+ return rt::timespec{
+ tv_sec = rt::UTIME_OMIT,
+ tv_nsec = rt::UTIME_OMIT
+ };
+ };
+};
+
+fn fs_chtimes(fs: *fs::fs, path: str, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ let fs = fs: *os_filesystem;
+ match (rt::utimensat(fs.dirfd, path, &utimes, 0)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
+fn fs_fchtimes(fd: io::file, atime: (time::instant | void),
+ mtime: (time::instant | void)) (void | fs::error) = {
+ let utimes: [2]rt::timespec = [
+ instant_to_timespec(atime),
+ instant_to_timespec(mtime),
+ ];
+ match (rt::futimens(fd, &utimes)) {
+ case let err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
+ };
+};
+
// TODO: cannot handle errors, i.e. path too long or cannot resolve.
fn fs_resolve(fs: *fs::fs, path: str) str = {
let fs = fs: *os_filesystem;
@@ -410,6 +449,8 @@ fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
rmdir = &fs_rmdir,
chmod = &fs_chmod,
chown = &fs_chown,
+ chtimes = &fs_chtimes,
+ fchtimes = &fs_fchtimes,
resolve = &fs_resolve,
link = &fs_link,
symlink = &fs_symlink,
diff --git a/os/os.ha b/os/os.ha
@@ -4,6 +4,7 @@
use fs;
use io;
use path;
+use time;
// Provides an implementation of [[fs::fs]] for the current working directory.
export let cwd: *fs::fs = null: *fs::fs;
@@ -64,6 +65,22 @@ export fn chmod(path: str, mode: fs::mode) (void | fs::error) = fs::chmod(cwd, p
// Changes ownership of a file.
export fn chown(path: str, uid: uint, gid: uint) (void | fs::error) = fs::chown(cwd, path, uid, gid);
+// Changes the access and modification time of a file. A void value will leave
+// the corresponding time unchanged.
+export fn chtimes(
+ path: str,
+ atime: (time::instant | void),
+ mtime: (time::instant | void)
+) (void | fs::error) = fs::chtimes(cwd, path, atime, mtime);
+
+// Changes the access and modification time of an [[io::file]]. A void value
+// will leave the corresponding time unchanged.
+export fn fchtimes(
+ fd: io::file,
+ atime: (time::instant | void),
+ mtime: (time::instant | void)
+) (void | fs::error) = fs::fchtimes(cwd, fd, atime, mtime);
+
// Resolves a path to its absolute, normalized value. Relative paths will be
// rooted (if supported by the host filesystem), and "." and ".." components
// will be reduced. This function does not follow symlinks; see [[realpath]] if