summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-04-07 11:30:27 +0200
committerJo-Philipp Wich <jo@mein.io>2022-04-07 11:30:27 +0200
commit5ee68d500d71c0dd2aa0dde5c75381969833249a (patch)
tree0b14791fcf8d8c83daf3e6ee16200e5a919e7686
parentdf6b86173c4979aea636907b8f3fb4d0c855ea94 (diff)
fs: implement `fs.readfile()` and `fs.writefile()`
The `fs.readfile()` and `fs.writefile()` functions allow efficient reading and writing of whole files, reducing the required boilerplace code compared to using the `open()`/`read()`/`write()`/`close()` API. - `fs.readfile()` takes two arguments; the path to open and an optional limit value. If limit is omitted, `null` or negative, the entire file contents are read, otherwise the specified amount of bytes. Returns the read file contents as string or `null` on error. - `fs.writefile()` takes three arguments; the path to open/create, the contents to write and an optional limit value. If limit is omitted, the entire content is written, otherwise just the specified amount of bytes. Non-string content arguments are internally converted to strings, `null` is treated as empty string. Returns the amount of bytes written or `null` on error. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--lib/fs.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/fs.c b/lib/fs.c
index 99f6072..30e5540 100644
--- a/lib/fs.c
+++ b/lib/fs.c
@@ -1140,6 +1140,128 @@ uc_fs_access(uc_vm_t *vm, size_t nargs)
return ucv_boolean_new(true);
}
+static uc_value_t *
+uc_fs_readfile(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *path = uc_fn_arg(0);
+ uc_value_t *size = uc_fn_arg(1);
+ uc_value_t *res = NULL;
+ uc_stringbuf_t *buf;
+ ssize_t limit = -1;
+ size_t rlen, blen;
+ FILE *fp;
+
+ if (ucv_type(path) != UC_STRING)
+ err_return(EINVAL);
+
+ if (size) {
+ if (ucv_type(size) != UC_INTEGER)
+ err_return(EINVAL);
+
+ limit = ucv_int64_get(size);
+ }
+
+ fp = fopen(ucv_string_get(path), "r");
+
+ if (!fp)
+ err_return(errno);
+
+ buf = ucv_stringbuf_new();
+
+ while (limit != 0) {
+ blen = 1024;
+
+ if (limit > 0 && blen > (size_t)limit)
+ blen = (size_t)limit;
+
+ printbuf_memset(buf, printbuf_length(buf) + blen - 1, 0, 1);
+
+ buf->bpos -= blen;
+ rlen = fread(buf->buf + buf->bpos, 1, blen, fp);
+ buf->bpos += rlen;
+
+ if (rlen < blen)
+ break;
+
+ if (limit > 0)
+ limit -= rlen;
+ }
+
+ if (ferror(fp)) {
+ fclose(fp);
+ printbuf_free(buf);
+ err_return(errno);
+ }
+
+ fclose(fp);
+
+ /* add sentinel null byte but don't count it towards the string length */
+ printbuf_memappend_fast(buf, "\0", 1);
+ res = ucv_stringbuf_finish(buf);
+ ((uc_string_t *)res)->length--;
+
+ return res;
+}
+
+static uc_value_t *
+uc_fs_writefile(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *path = uc_fn_arg(0);
+ uc_value_t *data = uc_fn_arg(1);
+ uc_value_t *size = uc_fn_arg(2);
+ uc_stringbuf_t *buf = NULL;
+ ssize_t limit = -1;
+ size_t wlen = 0;
+ int err = 0;
+ FILE *fp;
+
+ if (ucv_type(path) != UC_STRING)
+ err_return(EINVAL);
+
+ if (size) {
+ if (ucv_type(size) != UC_INTEGER)
+ err_return(EINVAL);
+
+ limit = ucv_int64_get(size);
+ }
+
+ fp = fopen(ucv_string_get(path), "w");
+
+ if (!fp)
+ err_return(errno);
+
+ if (data && ucv_type(data) != UC_STRING) {
+ buf = xprintbuf_new();
+ ucv_to_stringbuf_formatted(vm, buf, data, 0, '\0', 0);
+
+ if (limit < 0 || limit > printbuf_length(buf))
+ limit = printbuf_length(buf);
+
+ wlen = fwrite(buf->buf, 1, limit, fp);
+
+ if (wlen < (size_t)limit)
+ err = errno;
+
+ printbuf_free(buf);
+ }
+ else if (data) {
+ if (limit < 0 || (size_t)limit > ucv_string_length(data))
+ limit = ucv_string_length(data);
+
+ wlen = fwrite(ucv_string_get(data), 1, limit, fp);
+
+ if (wlen < (size_t)limit)
+ err = errno;
+ }
+
+ fclose(fp);
+
+ if (err)
+ err_return(err);
+
+ return ucv_uint64_new(wlen);
+}
+
static const uc_function_list_t proc_fns[] = {
{ "read", uc_fs_pread },
@@ -1193,6 +1315,8 @@ static const uc_function_list_t global_fns[] = {
{ "lsdir", uc_fs_lsdir },
{ "mkstemp", uc_fs_mkstemp },
{ "access", uc_fs_access },
+ { "readfile", uc_fs_readfile },
+ { "writefile", uc_fs_writefile },
};