Skip to content

Commit df91026

Browse files
authored
[FS] Make fstat work on file descriptors with no name in nodefs (#23480)
This makes fstat work on anonymous nodefs file descriptors. It is the last part of #23058.
1 parent a8385bf commit df91026

File tree

2 files changed

+81
-60
lines changed

2 files changed

+81
-60
lines changed

src/lib/libnodefs.js

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -112,65 +112,84 @@ addToLibrary({
112112
}
113113
return newFlags;
114114
},
115-
115+
getattr(func, node) {
116+
var stat = NODEFS.tryFSOperation(func);
117+
if (NODEFS.isWindows) {
118+
// node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake
119+
// them with default blksize of 4096.
120+
// See http://support.microsoft.com/kb/140365
121+
if (!stat.blksize) {
122+
stat.blksize = 4096;
123+
}
124+
if (!stat.blocks) {
125+
stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
126+
}
127+
// Windows does not report the 'x' permission bit, so propagate read
128+
// bits to execute bits.
129+
stat.mode |= (stat.mode & {{{ cDefs.S_IRUGO }}}) >> 2;
130+
}
131+
return {
132+
dev: stat.dev,
133+
ino: node.id,
134+
mode: stat.mode,
135+
nlink: stat.nlink,
136+
uid: stat.uid,
137+
gid: stat.gid,
138+
rdev: stat.rdev,
139+
size: stat.size,
140+
atime: stat.atime,
141+
mtime: stat.mtime,
142+
ctime: stat.ctime,
143+
blksize: stat.blksize,
144+
blocks: stat.blocks
145+
};
146+
},
147+
// Common code for both node and stream setattr
148+
// For node getatrr:
149+
// - arg is a native path
150+
// - chmod, utimes, truncate are fs.chmodSync, fs.utimesSync, fs.truncateSync
151+
// For stream getatrr:
152+
// - arg is a native file descriptor
153+
// - chmod, utimes, truncate are fs.fchmodSync, fs.futimesSync, fs.ftruncateSync
154+
setattr(arg, node, attr, chmod, utimes, truncate, stat) {
155+
NODEFS.tryFSOperation(() => {
156+
if (attr.mode !== undefined) {
157+
var mode = attr.mode;
158+
if (NODEFS.isWindows) {
159+
// Windows only supports S_IREAD / S_IWRITE (S_IRUSR / S_IWUSR)
160+
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/chmod-wchmod
161+
mode &= {{{ cDefs.S_IRUSR | cDefs.S_IWUSR }}};
162+
}
163+
chmod(arg, mode);
164+
// update the common node structure mode as well
165+
node.mode = attr.mode;
166+
}
167+
if (typeof (attr.atime ?? attr.mtime) === "number") {
168+
// Unfortunately, we have to stat the current value if we don't want
169+
// to change it. On top of that, since the times don't round trip
170+
// this will only keep the value nearly unchanged not exactly
171+
// unchanged. See:
172+
// https://github.com/nodejs/node/issues/56492
173+
var atime = new Date(attr.atime ?? stat(arg).atime);
174+
var mtime = new Date(attr.mtime ?? stat(arg).mtime);
175+
utimes(arg, atime, mtime);
176+
}
177+
if (attr.size !== undefined) {
178+
truncate(arg, attr.size);
179+
}
180+
});
181+
},
116182
node_ops: {
117183
getattr(node) {
118184
var path = NODEFS.realPath(node);
119-
var stat;
120-
NODEFS.tryFSOperation(() => stat = fs.lstatSync(path));
121-
if (NODEFS.isWindows) {
122-
// Windows does not report the 'x' permission bit, so propagate read
123-
// bits to execute bits.
124-
stat.mode |= (stat.mode & {{{ cDefs.S_IRUGO }}}) >> 2;
125-
}
126-
return {
127-
dev: stat.dev,
128-
ino: node.id,
129-
mode: stat.mode,
130-
nlink: stat.nlink,
131-
uid: stat.uid,
132-
gid: stat.gid,
133-
rdev: stat.rdev,
134-
size: stat.size,
135-
atime: stat.atime,
136-
mtime: stat.mtime,
137-
ctime: stat.ctime,
138-
blksize: stat.blksize,
139-
blocks: stat.blocks
140-
};
185+
return NODEFS.getattr(() => fs.lstatSync(path), node);
141186
},
142187
setattr(node, attr) {
143188
var path = NODEFS.realPath(node);
144-
NODEFS.tryFSOperation(() => {
145-
if (attr.mode !== undefined) {
146-
if (attr.dontFollow) {
147-
throw new FS.ErrnoError({{{ cDefs.ENOSYS }}});
148-
}
149-
var mode = attr.mode;
150-
if (NODEFS.isWindows) {
151-
// Windows only supports S_IREAD / S_IWRITE (S_IRUSR / S_IWUSR)
152-
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/chmod-wchmod
153-
mode &= {{{ cDefs.S_IRUSR | cDefs.S_IWUSR }}};
154-
}
155-
fs.chmodSync(path, mode);
156-
// update the common node structure mode as well
157-
node.mode = attr.mode;
158-
}
159-
if (typeof (attr.atime ?? attr.mtime) === "number") {
160-
// Unfortunately, we have to stat the current value if we don't want
161-
// to change it. On top of that, since the times don't round trip
162-
// this will only keep the value nearly unchanged not exactly
163-
// unchanged. See:
164-
// https://github.com/nodejs/node/issues/56492
165-
var stat = () => fs.lstatSync(NODEFS.realPath(node));
166-
var atime = new Date(attr.atime ?? stat().atime);
167-
var mtime = new Date(attr.mtime ?? stat().mtime);
168-
fs.utimesSync(path, atime, mtime);
169-
}
170-
if (attr.size !== undefined) {
171-
fs.truncateSync(path, attr.size);
172-
}
173-
});
189+
if (attr.mode != null && attr.dontFollow) {
190+
throw new FS.ErrnoError({{{ cDefs.ENOSYS }}});
191+
}
192+
NODEFS.setattr(path, node, attr, fs.chmodSync, fs.utimesSync, fs.truncateSync, fs.lstatSync);
174193
},
175194
lookup(parent, name) {
176195
var path = PATH.join2(NODEFS.realPath(parent), name);
@@ -228,18 +247,22 @@ addToLibrary({
228247
}
229248
},
230249
stream_ops: {
250+
getattr(stream) {
251+
return NODEFS.getattr(() => fs.fstatSync(stream.nfd), stream.node);
252+
},
253+
setattr(stream, attr) {
254+
NODEFS.setattr(stream.nfd, stream.node, attr, fs.fchmodSync, fs.futimesSync, fs.ftruncateSync, fs.fstatSync);
255+
},
231256
open(stream) {
232257
var path = NODEFS.realPath(stream.node);
233258
NODEFS.tryFSOperation(() => {
234-
if (FS.isFile(stream.node.mode)) {
235-
stream.shared.refcount = 1;
236-
stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
237-
}
259+
stream.shared.refcount = 1;
260+
stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
238261
});
239262
},
240263
close(stream) {
241264
NODEFS.tryFSOperation(() => {
242-
if (FS.isFile(stream.node.mode) && stream.nfd && --stream.shared.refcount === 0) {
265+
if (stream.nfd && --stream.shared.refcount === 0) {
243266
fs.closeSync(stream.nfd);
244267
}
245268
});

test/test_core.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5844,8 +5844,6 @@ def test_fs_64bit(self):
58445844
@crossplatform
58455845
@with_all_fs
58465846
def test_fs_stat_unnamed_file_descriptor(self):
5847-
if '-DNODEFS' in self.emcc_args:
5848-
self.skipTest('TODO: doesnt work in nodefs')
58495847
self.do_runf('fs/test_stat_unnamed_file_descriptor.c', 'success')
58505848

58515849
@requires_node

0 commit comments

Comments
 (0)