-
-
Notifications
You must be signed in to change notification settings - Fork 34.1k
Description
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.