Repository navigation
Description
Version
v21.7.1
Platform
Darwin nathan-MacBook-Pro 23.3.0 Darwin Kernel Version 23.3.0: Wed Dec 20 21:31:00 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6020 arm64
Subsystem
fs
What steps will reproduce the bug?
The following snippet will reproduce the bug on macOS and Linux; I'm not able to test it on Windows:
const fs = require('fs');
const net = require('net');
fs.rmSync('dir', { recursive: true });
fs.mkdirSync('dir');
net.createServer().listen('dir/file.sock', () => {
const files = fs.readdirSync('dir');
console.log('files, non-recursive:', files);
const filesRecursive = fs.readdirSync('dir', { recursive: true });
console.log('files, recursive:', filesRecursive);
});How often does it reproduce? Is there a required condition?
It reproduces consistently for me.
What is the expected behavior? Why is that the expected behavior?
I would expect to see output like the following:
files, non-recursive: [ 'file.sock' ]
files, recursive: [ 'file.sock' ]
In both the recursive and non-recursive case, listing a directory with a single file in it should produce an array containing that file's name.
What do you see instead?
Instead, I see the following output:
files, non-recursive: [ 'file.sock' ]
node:fs:1400
const readdirResult = binding.readdir(
^
Error: ENOTDIR: not a directory, scandir 'dir/file.sock'
at read (node:fs:1400:35)
at readdirSyncRecursive (node:fs:1438:5)
at Object.readdirSync (node:fs:1505:12)
at Server.<anonymous> (/Users/nathan/git/PrairieLearn/repro.js:11:29)
at Object.onceWrapper (node:events:633:28)
at Server.emit (node:events:519:28)
at emitListeningNT (node:net:1931:10)
at process.processTicksAndRejections (node:internal/process/task_queues:81:21) {
errno: -20,
code: 'ENOTDIR',
syscall: 'scandir',
path: 'dir/file.sock'
}
Additional information
For some reason, it's treating a Unix domain socket as a directory and it tries to call scandir on it, which is clearly not valid.
To confirm that dir/file.sock created by the above script is indeed a socket, I ran the following (output shown below the command):
$ file dir/file.sock
dir/file.sock: socket
Activity
bakkot commentedon Mar 20, 2024
Amusingly this works if you pass
withFileTypes: true, which indicates that the problem is these lines.Edit: Ah, yeah, looks like this is wrong.
s->st_mode & S_IFDIRwill return1for sockets because the mask for sockets is a superset of the mask for directories. The correct test for directories is(s->st_mode & S_IFMT) == S_IFDIR.That code has been wrong for a long time. Didn't matter when it was just used for module loading, since it would end up being "module not found", but using it here exposes the problem.
theanarkh commentedon Mar 20, 2024
I think
!!(s->st_mode & S_IFDIR)should be changed toS_ISDIR(s->st_mode)innode_file.cc.src: use `S_ISDIR` to check if the file is a directory
src: use `S_ISDIR` to check if the file is a directory
src: use `S_ISDIR` to check if the file is a directory