Skip to content

Recursive fs.readdirSync tries to recurse into Unix domain socket #52159

@nwalters512

Description

@nwalters512

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    fsIssues and PRs related to the fs subsystem / file system.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions