hare

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

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:
Mfs/fs.ha | 33+++++++++++++++++++++++++++++++++
Mfs/types.ha | 10++++++++++
Mos/+freebsd/dirfdfs.ha | 41+++++++++++++++++++++++++++++++++++++++++
Mos/+linux/dirfdfs.ha | 41+++++++++++++++++++++++++++++++++++++++++
Mos/+openbsd/dirfdfs.ha | 41+++++++++++++++++++++++++++++++++++++++++
Mos/os.ha | 17+++++++++++++++++
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