[njs] Fixed fs.readFile() and fs.readFileSync() for files with 0 size.

Dmitry Volyntsev xeioex at nginx.com
Mon Aug 12 18:05:16 UTC 2019


details:   https://hg.nginx.org/njs/rev/355028822e48
branches:  
changeset: 1121:355028822e48
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Aug 12 21:03:24 2019 +0300
description:
Fixed fs.readFile() and fs.readFileSync() for files with 0 size.

diffstat:

 src/njs_fs.c             |  183 +++++++++++++++++++++++++++++++++++-----------
 test/njs_expect_test.exp |   21 +++++
 2 files changed, 160 insertions(+), 44 deletions(-)

diffs (282 lines):

diff -r 33c4966abdda -r 355028822e48 src/njs_fs.c
--- a/src/njs_fs.c	Thu Aug 08 03:52:18 2019 -0400
+++ b/src/njs_fs.c	Mon Aug 12 21:03:24 2019 +0300
@@ -31,6 +31,8 @@ static njs_int_t njs_fs_write_file_inter
 static njs_int_t njs_fs_write_file_sync_internal(njs_vm_t *vm,
     njs_value_t *args, njs_uint_t nargs, int default_flags);
 
+static njs_int_t njs_fs_fd_read(njs_vm_t *vm, njs_value_t *path, int fd,
+    njs_str_t *data);
 static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall,
     const char *description, njs_value_t *path, int errn, njs_value_t *retval);
 static int njs_fs_flags(njs_str_t *value);
@@ -70,9 +72,10 @@ njs_fs_read_file(njs_vm_t *vm, njs_value
     njs_index_t unused)
 {
     int                 fd, errn, flags;
-    u_char              *p, *start, *end;
-    ssize_t             n, length;
-    njs_str_t           flag, encoding;
+    u_char              *start;
+    size_t              size;
+    ssize_t             length;
+    njs_str_t           flag, encoding, data;
     njs_int_t           ret;
     const char          *path, *syscall, *description;
     struct stat         sb;
@@ -209,32 +212,46 @@ njs_fs_read_file(njs_vm_t *vm, njs_value
         length = 0;
     }
 
-    start = njs_string_alloc(vm, &arguments[2], sb.st_size, length);
-    if (njs_slow_path(start == NULL)) {
-        goto fail;
-    }
+    size = sb.st_size;
 
-    p = start;
-    end = p + sb.st_size;
+    if (njs_fast_path(size != 0)) {
 
-    while (p < end) {
-        n = read(fd, p, end - p);
-        if (njs_slow_path(n == -1)) {
-            if (errno == EINTR) {
-                continue;
-            }
+        start = njs_string_alloc(vm, &arguments[2], size, length);
+        if (njs_slow_path(start == NULL)) {
+            goto fail;
+        }
 
-            errn = errno;
-            description = strerror(errno);
-            syscall = "read";
-            goto done;
+        data.start = start;
+        data.length = size;
+
+        ret = njs_fs_fd_read(vm, &args[1], fd, &data);
+        if (ret != NJS_OK) {
+            goto fail;
         }
 
-        p += n;
+        start = data.start;
+
+    } else {
+        /* size of the file is not known in advance. */
+
+        data.length = 0;
+
+        ret = njs_fs_fd_read(vm, &args[1], fd, &data);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        size = data.length;
+        start = data.start;
+
+        ret = njs_string_new(vm, &arguments[2], start, size, length);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto fail;
+        }
     }
 
     if (encoding.length != 0) {
-        length = njs_utf8_length(start, sb.st_size);
+        length = njs_utf8_length(start, size);
 
         if (length >= 0) {
             njs_string_length_set(&arguments[2], length);
@@ -295,9 +312,10 @@ njs_fs_read_file_sync(njs_vm_t *vm, njs_
     njs_index_t unused)
 {
     int                 fd, errn, flags;
-    u_char              *p, *start, *end;
-    ssize_t             n, length;
-    njs_str_t           flag, encoding;
+    u_char              *start;
+    size_t              size;
+    ssize_t             length;
+    njs_str_t           flag, encoding, data;
     njs_int_t           ret;
     const char          *path, *syscall, *description;
     struct stat         sb;
@@ -418,32 +436,46 @@ njs_fs_read_file_sync(njs_vm_t *vm, njs_
         length = 0;
     }
 
-    start = njs_string_alloc(vm, &vm->retval, sb.st_size, length);
-    if (njs_slow_path(start == NULL)) {
-        goto fail;
-    }
+    size = sb.st_size;
 
-    p = start;
-    end = p + sb.st_size;
+    if (njs_fast_path(size != 0)) {
 
-    while (p < end) {
-        n = read(fd, p, end - p);
-        if (njs_slow_path(n == -1)) {
-            if (errno == EINTR) {
-                continue;
-            }
+        start = njs_string_alloc(vm, &vm->retval, size, length);
+        if (njs_slow_path(start == NULL)) {
+            goto fail;
+        }
 
-            errn = errno;
-            description = strerror(errno);
-            syscall = "read";
-            goto done;
+        data.start = start;
+        data.length = size;
+
+        ret = njs_fs_fd_read(vm, &args[1], fd, &data);
+        if (ret != NJS_OK) {
+            goto fail;
         }
 
-        p += n;
+        start = data.start;
+
+    } else {
+        /* size of the file is not known in advance. */
+
+        data.length = 0;
+
+        ret = njs_fs_fd_read(vm, &args[1], fd, &data);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        size = data.length;
+        start = data.start;
+
+        ret = njs_string_new(vm, &vm->retval, start, size, length);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto fail;
+        }
     }
 
     if (encoding.length != 0) {
-        length = njs_utf8_length(start, sb.st_size);
+        length = njs_utf8_length(start, size);
 
         if (length >= 0) {
             njs_string_length_set(&vm->retval, length);
@@ -872,8 +904,71 @@ done:
 }
 
 
-static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall,
-    const char *description, njs_value_t *path, int errn, njs_value_t *retval)
+static njs_int_t
+njs_fs_fd_read(njs_vm_t *vm, njs_value_t *path, int fd, njs_str_t *data)
+{
+    u_char   *p, *end, *start;
+    size_t   size;
+    ssize_t  n;
+
+    size = data->length;
+
+    if (size == 0) {
+        size = 4096;
+
+        data->start = njs_mp_alloc(vm->mem_pool, size);
+        if (data->start == NULL) {
+            njs_memory_error(vm);
+            return NJS_ERROR;
+        }
+    }
+
+    p = data->start;
+    end = p + size;
+
+    for ( ;; ) {
+        n = read(fd, p, end - p);
+
+        if (njs_slow_path(n < 0)) {
+            (void) njs_fs_error(vm, "read", strerror(errno), path, errno,
+                                &vm->retval);
+            return NJS_ERROR;
+        }
+
+        p += n;
+
+        if (n == 0) {
+            break;
+        }
+
+        if (end - p < 2048) {
+            size *= 2;
+
+            start = njs_mp_alloc(vm->mem_pool, size);
+            if (start == NULL) {
+                njs_memory_error(vm);
+                return NJS_ERROR;
+            }
+
+            memcpy(start, data->start, p - data->start);
+
+            njs_mp_free(vm->mem_pool, data->start);
+
+            p = start + (p - data->start);
+            end = start + size;
+            data->start = start;
+        }
+    }
+
+    data->length = p - data->start;
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_fs_error(njs_vm_t *vm, const char *syscall, const char *description,
+    njs_value_t *path, int errn, njs_value_t *retval)
 {
     size_t              size;
     njs_int_t           ret;
diff -r 33c4966abdda -r 355028822e48 test/njs_expect_test.exp
--- a/test/njs_expect_test.exp	Thu Aug 08 03:52:18 2019 -0400
+++ b/test/njs_expect_test.exp	Mon Aug 12 21:03:24 2019 +0300
@@ -442,6 +442,15 @@ njs_test {
      "Error: No such file or directory\r\nundefined\r\n>> "}
 }
 
+njs_test {
+    {"var fs = require('fs')\r\n"
+     "undefined\r\n>> "}
+    {"fs.readFile('/proc/version', (e, data) => {console.log(e || data.slice(0,5) == 'Linux')})\r\n"
+     "true\r\nundefined\r\n>> "}
+    {"fs.readFile('/proc/cpuinfo', (e, data) => {console.log(e || data.slice(0,9) == 'processor')})\r\n"
+     "true\r\nundefined\r\n>> "}
+}
+
 # require('fs').readFileSync()
 
 njs_test {
@@ -500,6 +509,18 @@ njs_test {
      "Error: Non-UTF8 file, convertion is not implemented"}
 }
 
+njs_test {
+    {"var fs = require('fs'), file\r\n"
+     "undefined\r\n>> "}
+    {"try { file = fs.readFileSync('/proc/version')} catch (e) {}\r\n"
+     "undefined"}
+    {"(!file || file.slice(0,5) == 'Linux')\r\n"
+     "true"}
+    {"try { file = fs.readFileSync('/proc/cpuinfo')} catch (e) {}\r\n"
+     "undefined"}
+    {"(!file || file.slice(0,9) == 'processor')\r\n"
+     "true"}
+}
 
 # require('fs').writeFile()
 


More information about the nginx-devel mailing list