diff options
author | Jo-Philipp Wich <jo@mein.io> | 2022-02-15 11:28:38 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2022-02-15 11:32:43 +0100 |
commit | 4ce69a833cdd588cda621588f95502585cdbc63f (patch) | |
tree | e47ccab3f0879e1b039ca1775b6936cbd263f901 | |
parent | a29bad9454edcc285f7f37410b6822affede44d1 (diff) |
fs: implement access(), mkstemp(), file.flush() and proc.flush()
The `access()` function allows testing the path given in the first argument
for accessibility according to the permissions specified in the second
mode string argument. The mode string characters may be `r`, `w`, `x` or
`f` which correspond to `R_OK` - path is readable, `W_OK` - path is
writable, `X_OK` - path is executable or `F_OK` - path exists respectively.
The `mkstemp()` function creates a secure temporary file, unlinks it and
returns the open file handle. The temporary path is constructed based on
the optional template argument. If the template argument contains a slash,
the path is taken as-is, if it contains no slashes, `/tmp/` is prepended.
If the template does not end with `XXXXXX`, a `.XXXXXX` suffix is appended
to the path. If the template is omitted, `/tmp/XXXXXX` is used.
The `file.flush()` and `proc.flush()` functions call `fflush()` on the
underlying file handle respectively. They take no arguments.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | lib/fs.c | 130 |
1 files changed, 130 insertions, 0 deletions
@@ -173,6 +173,20 @@ uc_fs_write_common(uc_vm_t *vm, size_t nargs, const char *type) } static uc_value_t * +uc_fs_flush_common(uc_vm_t *vm, size_t nargs, const char *type) +{ + FILE **fp = uc_fn_this(type); + + if (!fp || !*fp) + err_return(EBADF); + + if (fflush(*fp) != EOF) + err_return(errno); + + return ucv_boolean_new(true); +} + +static uc_value_t * uc_fs_fileno_common(uc_vm_t *vm, size_t nargs, const char *type) { int fd; @@ -228,6 +242,12 @@ uc_fs_pwrite(uc_vm_t *vm, size_t nargs) } static uc_value_t * +uc_fs_pflush(uc_vm_t *vm, size_t nargs) +{ + return uc_fs_flush_common(vm, nargs, "fs.proc"); +} + +static uc_value_t * uc_fs_pfileno(uc_vm_t *vm, size_t nargs) { return uc_fs_fileno_common(vm, nargs, "fs.proc"); @@ -333,6 +353,12 @@ uc_fs_tell(uc_vm_t *vm, size_t nargs) } static uc_value_t * +uc_fs_flush(uc_vm_t *vm, size_t nargs) +{ + return uc_fs_flush_common(vm, nargs, "fs.file"); +} + +static uc_value_t * uc_fs_fileno(uc_vm_t *vm, size_t nargs) { return uc_fs_fileno_common(vm, nargs, "fs.file"); @@ -1011,11 +1037,112 @@ uc_fs_lsdir(uc_vm_t *vm, size_t nargs) return res; } +static uc_value_t * +uc_fs_mkstemp(uc_vm_t *vm, size_t nargs) +{ + uc_value_t *template = uc_fn_arg(0); + bool ends_with_template = false; + char *path, *t; + FILE *fp; + size_t l; + int fd; + + if (template && ucv_type(template) != UC_STRING) + err_return(EINVAL); + + t = ucv_string_get(template); + l = ucv_string_length(template); + + ends_with_template = (l >= 6 && strcmp(&t[l - 6], "XXXXXX") == 0); + + if (t && strchr(t, '/')) { + if (ends_with_template) + xasprintf(&path, "%s", t); + else + xasprintf(&path, "%s.XXXXXX", t); + } + else if (t) { + if (ends_with_template) + xasprintf(&path, "/tmp/%s", t); + else + xasprintf(&path, "/tmp/%s.XXXXXX", t); + } + else { + xasprintf(&path, "/tmp/XXXXXX"); + } + + do { + fd = mkstemp(path); + } + while (fd == -1 && errno == EINTR); + + if (fd == -1) { + free(path); + err_return(errno); + } + + unlink(path); + free(path); + + fp = fdopen(fd, "r+"); + + if (!fp) { + close(fd); + err_return(errno); + } + + return uc_resource_new(file_type, fp); +} + +static uc_value_t * +uc_fs_access(uc_vm_t *vm, size_t nargs) +{ + uc_value_t *path = uc_fn_arg(0); + uc_value_t *test = uc_fn_arg(1); + int mode = F_OK; + char *p; + + if (ucv_type(path) != UC_STRING) + err_return(EINVAL); + + if (test && ucv_type(test) != UC_STRING) + err_return(EINVAL); + + for (p = ucv_string_get(test); p && *p; p++) { + switch (*p) { + case 'r': + mode |= R_OK; + break; + + case 'w': + mode |= W_OK; + break; + + case 'x': + mode |= X_OK; + break; + + case 'f': + mode |= F_OK; + break; + + default: + err_return(EINVAL); + } + } + + if (access(ucv_string_get(path), mode) == -1) + err_return(errno); + + return ucv_boolean_new(true); +} + static const uc_function_list_t proc_fns[] = { { "read", uc_fs_pread }, { "write", uc_fs_pwrite }, { "close", uc_fs_pclose }, + { "flush", uc_fs_pflush }, { "fileno", uc_fs_pfileno }, { "error", uc_fs_error }, }; @@ -1026,6 +1153,7 @@ static const uc_function_list_t file_fns[] = { { "seek", uc_fs_seek }, { "tell", uc_fs_tell }, { "close", uc_fs_close }, + { "flush", uc_fs_flush }, { "fileno", uc_fs_fileno }, { "error", uc_fs_error }, }; @@ -1060,6 +1188,8 @@ static const uc_function_list_t global_fns[] = { { "dirname", uc_fs_dirname }, { "basename", uc_fs_basename }, { "lsdir", uc_fs_lsdir }, + { "mkstemp", uc_fs_mkstemp }, + { "access", uc_fs_access }, }; |