Skip to content

Commit

Permalink
Fix dup in nodefs
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodmane committed Feb 23, 2024
1 parent 03496d8 commit 7f107ab
Showing 1 changed file with 166 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
From 135baa3d4cc211c0145d2e1df116e39f60df4f91 Mon Sep 17 00:00:00 2001
From: Hood Chatham <roberthoodchatham@gmail.com>
Date: Thu, 22 Feb 2024 21:47:13 -0800
Subject: [PATCH] Fix dup in nodefs by refcounting nodefs file descriptors
(#21399)

---
src/library_fs.js | 5 +++++
src/library_nodefs.js | 6 +++++-
src/library_syscall.js | 6 +++---
test/fs/test_nodefs_dup.c | 45 +++++++++++++++++++++++++++++++++++++++
test/test_core.py | 8 +++++++
5 files changed, 66 insertions(+), 4 deletions(-)
create mode 100644 test/fs/test_nodefs_dup.c

diff --git a/src/library_fs.js b/src/library_fs.js
index f5d16b86c..379e65268 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -471,6 +471,11 @@ FS.staticInit();` +
closeStream(fd) {
FS.streams[fd] = null;
},
+ dupStream(origStream, fd = -1) {
+ var stream = FS.createStream(origStream, fd);
+ stream.stream_ops?.dup?.(stream);
+ return stream;
+ },

//
// devices
diff --git a/src/library_nodefs.js b/src/library_nodefs.js
index 81864ffcc..ace50458c 100644
--- a/src/library_nodefs.js
+++ b/src/library_nodefs.js
@@ -251,6 +251,7 @@ addToLibrary({
var path = NODEFS.realPath(stream.node);
try {
if (FS.isFile(stream.node.mode)) {
+ stream.shared.refcount = 1;
stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
}
} catch (e) {
@@ -260,7 +261,7 @@ addToLibrary({
},
close(stream) {
try {
- if (FS.isFile(stream.node.mode) && stream.nfd) {
+ if (FS.isFile(stream.node.mode) && stream.nfd && --stream.shared.refcount === 0) {
fs.closeSync(stream.nfd);
}
} catch (e) {
@@ -268,6 +269,9 @@ addToLibrary({
throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
}
},
+ dup(stream) {
+ stream.shared.refcount++;
+ },
read(stream, buffer, offset, length, position) {
// Node.js < 6 compatibility: node errors on 0 length reads
if (length === 0) return 0;
diff --git a/src/library_syscall.js b/src/library_syscall.js
index b078bd71c..69ea6f8b2 100644
--- a/src/library_syscall.js
+++ b/src/library_syscall.js
@@ -183,7 +183,7 @@ var SyscallsLibrary = {
},
__syscall_dup: (fd) => {
var old = SYSCALLS.getStreamFromFD(fd);
- return FS.createStream(old).fd;
+ return FS.dupStream(old).fd;
},
__syscall_pipe__deps: ['$PIPEFS'],
__syscall_pipe: (fdPtr) => {
@@ -760,7 +760,7 @@ var SyscallsLibrary = {
arg++;
}
var newStream;
- newStream = FS.createStream(stream, arg);
+ newStream = FS.dupStream(stream, arg);
return newStream.fd;
}
case {{{ cDefs.F_GETFD }}}:
@@ -1007,7 +1007,7 @@ var SyscallsLibrary = {
if (old.fd === newfd) return -{{{ cDefs.EINVAL }}};
var existing = FS.getStream(newfd);
if (existing) FS.close(existing);
- return FS.createStream(old, newfd).fd;
+ return FS.dupStream(old, newfd).fd;
},
};

diff --git a/test/fs/test_nodefs_dup.c b/test/fs/test_nodefs_dup.c
new file mode 100644
index 000000000..abf34935b
--- /dev/null
+++ b/test/fs/test_nodefs_dup.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Emscripten Authors. All rights reserved.
+ * Emscripten is available under two separate licenses, the MIT license and the
+ * University of Illinois/NCSA Open Source License. Both these licenses can be
+ * found in the LICENSE file.
+ */
+
+#include <assert.h>
+#include <emscripten.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef NODERAWFS
+#define CWD ""
+#else
+#define CWD "/working/"
+#endif
+
+int main(void)
+{
+ EM_ASM(
+#ifdef NODERAWFS
+ FS.close(FS.open('test.txt', 'w'));
+#else
+ FS.mkdir('/working');
+ FS.mount(NODEFS, {root: '.'}, '/working');
+ FS.close(FS.open('/working/test.txt', 'w'));
+#endif
+ );
+ int fd1 = open(CWD "test.txt", O_WRONLY);
+ int fd2 = dup(fd1);
+ int fd3 = fcntl(fd1, F_DUPFD_CLOEXEC, 0);
+
+ assert(fd1 == 3);
+ assert(fd2 == 4);
+ assert(fd3 == 5);
+ assert(close(fd1) == 0);
+ assert(write(fd2, "abcdef", 6) == 6);
+ assert(close(fd2) == 0);
+ assert(write(fd3, "ghijkl", 6) == 6);
+ assert(close(fd3) == 0);
+ printf("success\n");
+ return 0;
+}
diff --git a/test/test_core.py b/test/test_core.py
index 3f21eb5ef..f304f1366 100644
--- a/test/test_core.py
+++ b/test/test_core.py
@@ -5745,6 +5745,14 @@ Module = {
self.emcc_args += ['-lnodefs.js']
self.do_runf('fs/test_nodefs_cloexec.c', 'success')

+ @also_with_noderawfs
+ @requires_node
+ def test_fs_nodefs_dup(self):
+ if self.get_setting('WASMFS'):
+ self.set_setting('FORCE_FILESYSTEM')
+ self.emcc_args += ['-lnodefs.js']
+ self.do_runf('fs/test_nodefs_dup.c', 'success')
+
@requires_node
def test_fs_nodefs_home(self):
self.set_setting('FORCE_FILESYSTEM')
--
2.34.1

0 comments on commit 7f107ab

Please sign in to comment.