commit ab15ef5930b0fdccd3323b2bb80e72d8087ac877
parent a4036327707bc4a69d35eeb3f929b32d89cb62da
Author: Alexey Yerin <yyp@disroot.org>
Date: Sun, 21 Mar 2021 16:58:58 +0300
fs: implement chmod
Example usage: os::chmod("harec", fs::mode::USER_RWX);
Diffstat:
5 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -146,6 +146,16 @@ export fn mksubdir(fs: *fs, path: str) (*fs | error) = {
};
};
+// Changes mode flags on a file or directory. Type bits are discared.
+export fn chmod(fs: *fs, path: str, mode: mode) (void | error) = {
+ mode &= 0o755;
+
+ return match (fs.chmod) {
+ f: *chmodfunc => f(fs, path, mode),
+ null => abort(),
+ };
+};
+
// Resolves a path to its absolute, normalized value. This consoldates ./ and
// ../ sequences, roots the path, and returns a new path. The caller must free
// the return value.
diff --git a/fs/types.ha b/fs/types.ha
@@ -179,6 +179,7 @@ export type subdirfunc = fn(fs: *fs, path: str) (*fs | error);
export type mkdirfunc = fn(fs: *fs, path: str) (void | error);
export type rmdirfunc = fn(fs: *fs, path: str) (void | error);
export type mksubdirfunc = fn(fs: *fs, path: str) (*fs | error);
+export type chmodfunc = fn(fs: *fs, path: str, mode: mode) (void | error);
export type resolvefunc = fn(fs: *fs, path: str) str;
export type openfunc = fn(
@@ -233,6 +234,9 @@ export type fs = struct {
// Creates a directory and returns a subdir for it.
mksubdir: nullable *mksubdirfunc,
+ // Changes mode flags on a file or directory.
+ chmod: nullable *chmodfunc,
+
// 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/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -53,6 +53,7 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = {
subdir = &fs_subdir,
mkdir = &fs_mkdir,
rmdir = &fs_rmdir,
+ chmod = &fs_chmod,
resolve = &fs_resolve,
...
},
@@ -277,6 +278,14 @@ fn fs_mkdir(fs: *fs::fs, path: str) (void | fs::error) = {
};
};
+fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = {
+ let fs = fs: *os_filesystem;
+ return match (rt::fchmodat(fs.dirfd, path, mode: uint)) {
+ err: rt::errno => return errno_to_fs(err),
+ void => void,
+ };
+};
+
fn resolve_part(parts: *[]str, part: str) void = {
if (part == ".") {
// no-op
diff --git a/os/fs.ha b/os/fs.ha
@@ -40,6 +40,9 @@ export fn rmdirall(path: str) (void | fs::error) = fs::rmdirall(cwd, path);
// doing this operation atomically, but if not, a fallback is used.
export fn mksubdir(path: str) (*fs::fs | fs::error) = fs::mksubdir(cwd, path);
+// Changes mode flags on a file or directory. Type bits are discared.
+export fn chmod(path: str, mode: fs::mode) (void | fs::error) = fs::chmod(cwd, path, mode);
+
// Resolves a path to its absolute, normalized value. This consoldates ./ and
// ../ sequences, roots the path, and returns a new path. The caller must free
// the return value.
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -81,6 +81,20 @@ export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = {
return;
};
+export fn chmod(path: path, mode: uint) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall3(SYS_fchmodat,
+ AT_FDCWD: u64, path: uintptr: u64, mode: u64));
+ return;
+};
+
+export fn fchmodat(dirfd: int, path: path, mode: uint) (void | errno) = {
+ let path = kpath(path)?;
+ wrap_return(syscall3(SYS_fchmodat,
+ dirfd: u64, path: uintptr: u64, mode: u64))?;
+ return;
+};
+
export fn dup(fd: int) (int | errno) = {
return wrap_return(syscall1(SYS_dup, fd: u64))?: int;
};