Skip to content

Commit d429547

Browse files
committed
Make fstat work on file descriptors with no name part 1
This fixes fstat on "anonymous" file descriptors in node rawfs and includes the changes to library_syscall and library_fs needed to allow pipes emscripten-core#23306 and nodefs descriptors emscripten-core#23058 to be stated.
1 parent dde19fa commit d429547

File tree

5 files changed

+83
-19
lines changed

5 files changed

+83
-19
lines changed

src/library_fs.js

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,24 @@ FS.staticInit();
479479
stream.stream_ops?.dup?.(stream);
480480
return stream;
481481
},
482+
streamGetAttr(stream) {
483+
var node = stream.node;
484+
var res = stream.stream_ops?.getattr?.(stream) ?? node.node_ops?.getattr?.(node);
485+
if (res) {
486+
return res;
487+
}
488+
throw new FS.ErrnoError({{{ cDefs.EPERM }}});
489+
},
490+
streamSetAttr(stream, attr) {
491+
var node = stream.node;
492+
var set;
493+
if (set = stream.stream_ops.setattr) {
494+
return set(stream, attr);
495+
} else if (set = node.node_ops.setattr) {
496+
return set(node, attr);
497+
}
498+
throw new FS.ErrnoError({{{ cDefs.EPERM }}});
499+
},
482500

483501
//
484502
// devices
@@ -956,6 +974,10 @@ FS.staticInit();
956974
}
957975
return node.node_ops.getattr(node);
958976
},
977+
fstat(fd) {
978+
var stream = FS.getStreamChecked(fd);
979+
return FS.streamGetAttr(stream);
980+
},
959981
lstat(path) {
960982
return FS.stat(path, true);
961983
},
@@ -981,7 +1003,10 @@ FS.staticInit();
9811003
},
9821004
fchmod(fd, mode) {
9831005
var stream = FS.getStreamChecked(fd);
984-
FS.chmod(stream.node, mode);
1006+
FS.streamSetAttr(stream, {
1007+
mode: (mode & {{{ cDefs.S_IALLUGO }}}) | (stream.node.mode & ~{{{ cDefs.S_IALLUGO }}}),
1008+
ctime: Date.now()
1009+
});
9851010
},
9861011
chown(path, uid, gid, dontFollow) {
9871012
var node;
@@ -1005,7 +1030,22 @@ FS.staticInit();
10051030
},
10061031
fchown(fd, uid, gid) {
10071032
var stream = FS.getStreamChecked(fd);
1008-
FS.chown(stream.node, uid, gid);
1033+
FS.streamSetAttr(stream, {
1034+
timestamp: Date.now()
1035+
// we ignore the uid / gid for now
1036+
});
1037+
},
1038+
truncateChecks(node) {
1039+
if (FS.isDir(node.mode)) {
1040+
throw new FS.ErrnoError({{{ cDefs.EISDIR }}});
1041+
}
1042+
if (!FS.isFile(node.mode)) {
1043+
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
1044+
}
1045+
var errCode = FS.nodePermissions(node, 'w');
1046+
if (errCode) {
1047+
throw new FS.ErrnoError(errCode);
1048+
}
10091049
},
10101050
truncate(path, len) {
10111051
if (len < 0) {
@@ -1018,30 +1058,21 @@ FS.staticInit();
10181058
} else {
10191059
node = path;
10201060
}
1021-
if (!node.node_ops.setattr) {
1022-
throw new FS.ErrnoError({{{ cDefs.EPERM }}});
1023-
}
1024-
if (FS.isDir(node.mode)) {
1025-
throw new FS.ErrnoError({{{ cDefs.EISDIR }}});
1026-
}
1027-
if (!FS.isFile(node.mode)) {
1028-
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
1029-
}
1030-
var errCode = FS.nodePermissions(node, 'w');
1031-
if (errCode) {
1032-
throw new FS.ErrnoError(errCode);
1033-
}
10341061
node.node_ops.setattr(node, {
10351062
size: len,
10361063
timestamp: Date.now()
10371064
});
10381065
},
10391066
ftruncate(fd, len) {
10401067
var stream = FS.getStreamChecked(fd);
1041-
if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) {
1068+
if (len < 0 || (stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) {
10421069
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
10431070
}
1044-
FS.truncate(stream.node, len);
1071+
FS.truncateChecks(stream.node);
1072+
FS.streamSetAttr(stream, {
1073+
size: len,
1074+
timestamp: Date.now()
1075+
});
10451076
},
10461077
utime(path, atime, mtime) {
10471078
var lookup = FS.lookupPath(path, { follow: true });

src/library_noderawfs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ addToLibrary({
7979
}
8080
return stat;
8181
},
82+
fstat(fd) {
83+
var stream = FS.getStreamChecked(fd);
84+
return fs.fstatSync(stream.nfd);
85+
},
8286
chmod(path, mode, dontFollow) {
8387
mode &= {{{ cDefs.S_IALLUGO }}};
8488
if (NODEFS.isWindows) {

src/library_syscall.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,8 +678,7 @@ var SyscallsLibrary = {
678678
return SYSCALLS.writeStat(buf, FS.lstat(path));
679679
},
680680
__syscall_fstat64: (fd, buf) => {
681-
var stream = SYSCALLS.getStreamFromFD(fd);
682-
return SYSCALLS.writeStat(buf, FS.stat(stream.path));
681+
return SYSCALLS.writeStat(buf, FS.fstat(fd));
683682
},
684683
__syscall_fchown32: (fd, owner, group) => {
685684
FS.fchown(fd, owner, group);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <fcntl.h>
2+
#include <unistd.h>
3+
#include <sys/stat.h>
4+
#include <assert.h>
5+
#include "stdio.h"
6+
7+
int main() {
8+
int fd = open("file.txt", O_RDWR | O_CREAT, 0666);
9+
unlink("file.txt");
10+
int res;
11+
struct stat buf;
12+
res = fstat(fd, &buf);
13+
assert(res == 0);
14+
assert(buf.st_atime > 1000000000);
15+
res = fchmod(fd, 0777);
16+
assert(res == 0);
17+
res = ftruncate(fd, 10);
18+
assert(res == 0);
19+
printf("success\n");
20+
}

test/test_core.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5847,6 +5847,16 @@ def test_fs_64bit(self):
58475847
self.set_setting('FORCE_FILESYSTEM')
58485848
self.do_runf('fs/test_64bit.c', 'success')
58495849

5850+
@crossplatform
5851+
@also_with_noderawfs
5852+
def test_fs_stat_unnamed_file_descriptor(self):
5853+
nodefs = '-DNODEFS' in self.emcc_args or '-DNODERAWFS' in self.emcc_args
5854+
if self.get_setting('WASMFS'):
5855+
if nodefs:
5856+
self.skipTest('NODEFS in WasmFS')
5857+
self.set_setting('FORCE_FILESYSTEM')
5858+
self.do_runf('fs/test_stat_unnamed_file_descriptor.c', 'success')
5859+
58505860
@requires_node
58515861
@crossplatform
58525862
@with_all_fs

0 commit comments

Comments
 (0)