|
|
@@ -1,137 +0,0 @@
|
|
|
-From: Felix Fietkau <[email protected]>
|
|
|
-Date: Wed, 8 Oct 2025 23:03:05 +0200
|
|
|
-Subject: [PATCH] fs: add read_nb() method for non-blocking reads
|
|
|
-
|
|
|
-Add file handle method for reading from non-blocking file descriptors.
|
|
|
-Designed for use with uloop, bypasses stdio buffering, handles EAGAIN/EINTR.
|
|
|
-
|
|
|
-Signed-off-by: Felix Fietkau <[email protected]>
|
|
|
----
|
|
|
-
|
|
|
---- a/lib/fs.c
|
|
|
-+++ b/lib/fs.c
|
|
|
-@@ -675,6 +675,116 @@ uc_fs_read(uc_vm_t *vm, size_t nargs)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
-+ * Reads data from a non-blocking file descriptor.
|
|
|
-+ *
|
|
|
-+ * This function is designed for use with uloop file descriptor monitoring.
|
|
|
-+ * When called from within a uloop handle callback (after ULOOP_READ event),
|
|
|
-+ * it reads available data from the non-blocking file descriptor.
|
|
|
-+ *
|
|
|
-+ * Performs a single read() operation directly on the file descriptor,
|
|
|
-+ * bypassing stdio buffering. Properly handles EAGAIN and EINTR errors.
|
|
|
-+ *
|
|
|
-+ * Returns a string containing the data read, up to the specified limit.
|
|
|
-+ *
|
|
|
-+ * Returns an empty string if no data is available (EAGAIN/EWOULDBLOCK).
|
|
|
-+ *
|
|
|
-+ * Returns `null` if an error occurred.
|
|
|
-+ *
|
|
|
-+ * @function module:fs.file#read_nb
|
|
|
-+ *
|
|
|
-+ * @param {number} [limit=4096]
|
|
|
-+ * Maximum number of bytes to read. Defaults to 4096 if not specified.
|
|
|
-+ *
|
|
|
-+ * @returns {?string}
|
|
|
-+ *
|
|
|
-+ * @example
|
|
|
-+ * import * as uloop from 'uloop';
|
|
|
-+ * import { fdopen } from 'fs';
|
|
|
-+ *
|
|
|
-+ * uloop.init();
|
|
|
-+ *
|
|
|
-+ * let sock = connect_socket(...);
|
|
|
-+ * let fp = fdopen(sock, "r");
|
|
|
-+ *
|
|
|
-+ * uloop.handle(fp, (events) => {
|
|
|
-+ * if (events & uloop.ULOOP_READ) {
|
|
|
-+ * let data = fp.read_nb();
|
|
|
-+ * if (data === null) {
|
|
|
-+ * print("Error reading\n");
|
|
|
-+ * } else if (length(data) > 0) {
|
|
|
-+ * print("Received: ", data, "\n");
|
|
|
-+ * }
|
|
|
-+ * }
|
|
|
-+ * }, uloop.ULOOP_READ);
|
|
|
-+ *
|
|
|
-+ * uloop.run();
|
|
|
-+ */
|
|
|
-+static uc_value_t *
|
|
|
-+uc_fs_read_nb(uc_vm_t *vm, size_t nargs)
|
|
|
-+{
|
|
|
-+ uc_value_t *limit_val = uc_fn_arg(0);
|
|
|
-+ FILE **fp = uc_fn_this("fs.file");
|
|
|
-+ char *buf = NULL;
|
|
|
-+ ssize_t n_read;
|
|
|
-+ uc_value_t *rv;
|
|
|
-+ size_t limit = 4096;
|
|
|
-+ int fd;
|
|
|
-+
|
|
|
-+ if (!fp || !*fp)
|
|
|
-+ err_return(EBADF);
|
|
|
-+
|
|
|
-+ if (limit_val) {
|
|
|
-+ int64_t limit_arg;
|
|
|
-+
|
|
|
-+ if (ucv_type(limit_val) != UC_INTEGER)
|
|
|
-+ err_return(EINVAL);
|
|
|
-+
|
|
|
-+ limit_arg = ucv_int64_get(limit_val);
|
|
|
-+
|
|
|
-+ if (limit_arg <= 0)
|
|
|
-+ return NULL;
|
|
|
-+
|
|
|
-+ limit = (size_t)limit_arg;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ fd = fileno(*fp);
|
|
|
-+
|
|
|
-+ if (fd == -1)
|
|
|
-+ err_return(errno);
|
|
|
-+
|
|
|
-+ buf = malloc(limit);
|
|
|
-+
|
|
|
-+ if (!buf)
|
|
|
-+ err_return(ENOMEM);
|
|
|
-+
|
|
|
-+ while (true) {
|
|
|
-+ n_read = read(fd, buf, limit);
|
|
|
-+
|
|
|
-+ if (n_read >= 0)
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ if (errno == EINTR)
|
|
|
-+ continue;
|
|
|
-+
|
|
|
-+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
-+ free(buf);
|
|
|
-+ return ucv_string_new_length("", 0);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ free(buf);
|
|
|
-+ err_return(errno);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!n_read)
|
|
|
-+ return NULL;
|
|
|
-+
|
|
|
-+ rv = ucv_string_new_length(buf, (size_t)n_read);
|
|
|
-+ free(buf);
|
|
|
-+
|
|
|
-+ return rv;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/**
|
|
|
- * Writes a chunk of data to the file handle.
|
|
|
- *
|
|
|
- * In case the given data is not a string, it is converted to a string before
|
|
|
-@@ -2991,6 +3101,7 @@ static const uc_function_list_t proc_fns
|
|
|
-
|
|
|
- static const uc_function_list_t file_fns[] = {
|
|
|
- { "read", uc_fs_read },
|
|
|
-+ { "read_nb", uc_fs_read_nb },
|
|
|
- { "write", uc_fs_write },
|
|
|
- { "seek", uc_fs_seek },
|
|
|
- { "tell", uc_fs_tell },
|