Skip to content

fs.promises.cp() is broken for file names with certain characters #61121

@petcap

Description

@petcap

Version

v24.12.0

Platform

Linux 6.14.0-37. Tested with several different distros.

Subsystem

fs

What steps will reproduce the bug?

If fs.promises.cp() is called with the "recursive" flag set to true and it encounters a file name which contains characters that is not valid UTF8, the copy will fail.

To reproduce, first create a source folder with a file that contains an UTF8 invalid file name:

$ mkdir source
$ touch source/test_$'\240'.txt

Then, implement a simple JS script that copies the source folder:

const fs = require("fs").promises;
fs.cp("source", "destination", { recursive: true }).then(() => console.log("Done!"))

Execute the script:

$ node cp.js 
node:internal/fs/promises:1031
  const result = await PromisePrototypeThen(
                 ^

Error: ENOENT: no such file or directory, lstat 'source/test_�.txt'
    at async lstat (node:internal/fs/promises:1031:18)
    at async Promise.all (index 0)
    at async checkPaths (node:internal/fs/cp/cp:77:39)
    at async copyDir (node:internal/fs/cp/cp:320:35)
    at async mkDirAndCopy (node:internal/fs/cp/cp:310:3) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'lstat',
  path: 'source/test_�.txt'
}

Since the file name contains \240 (or 0xA0 in hex) which is not a valid UTF8 character, the UTF8 decoder replaces it with , causing the stat() call to a file name which does not exist.

How often does it reproduce? Is there a required condition?

Reproduces every time. Tested on Debian, Ubuntu, Red Hat and Fedora. All NodeJS versions I have tested have this bug, including the latest LTS.

What is the expected behavior? Why is that the expected behavior?

I expect fs.promises.cp() to just work regardless of the file names on whatever platform NodeJS is running on.

What do you see instead?

N/A

Additional information

I haven't checked the NodeJS code but I suspect the file names are stored in UTF8 internally. In Linux, file names are essentially byte arrays and can contain any data with a few exceptions.

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