Skip to content

fs.copyFile fails with permission denied when source is read-only #37284

@kakaroto

Description

@kakaroto

What steps will reproduce the bug?

if I have an external mount (in my case a cephfs cluster mounted using ceph-fuse), then copying a file into it will fail with permission denied if the source file is read-only.

Simple code to reproduce the issue :

const fs = require("fs");

fs.copyFileSync("/tmp/foo", "/ceph-mount/tmp/bar");

Doing a touch /tmp/foo && chmod -w /tmp/foo before running the script will allow you to reproduce the error. The above code will fail as long as the source file is read-only, even if the file can be copied in the shell.

(note, it might work with an NFS mount or some other type of mount, but have only tested with my cephfs mount. A local ext4fs mount does not seem to be affected by the problem).

Also note that this works with Node 12.18.4. I actually noticed this issue a little while ago when I reinstalled one of my systems, and ended up with node 12.19.0 and my app started failing to copy files from a read-only file system and I was forced to downgrade to 12.18.3 where it was known to be working as expected. Today, I confirmed the bug is still there in node 14.15.4.

Using this command docker run --rm -it -v /ceph-mount/:/ceph-mount node:12.19.0-alpine /bin/sh to run node then pasting these commands in it will show the problem :

su - node
touch /tmp/foo
chmod -w /tmp/foo
cat <<EOF > test.js
const fs = require("fs");
fs.copyFileSync("/tmp/foo", "/ceph-mount/tmp/bar");
EOF
rm -f /ceph-mount/tmp/bar
node test.js
exit
exit

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

100% reproducible on node 12.19.0 up to 14.15.4, 0% reproducible on node 12.18.4

What is the expected behavior?

the fs.copyFile should be able to succeed in copying the file as long as the destination folder is writable.

What do you see instead?

The output is :

internal/fs/utils.js:269
    throw err;
    ^

Error: EACCES: permission denied, copyfile '/tmp/foo' -> '/ceph-mount/tmp/bar'
    at Object.copyFileSync (fs.js:1904:3)
    at Object.<anonymous> (/home/node/test.js:2:4)
    at Module._compile (internal/modules/cjs/loader.js:1015:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
    at Module.load (internal/modules/cjs/loader.js:879:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47 {
  errno: -13,
  syscall: 'copyfile',
  code: 'EACCES',
  path: '/tmp/foo',
  dest: '/ceph-mount/tmp/bar'
}

Here are screenshots showing the above running on node 12.19.0 as well as 12.18.4 to prove that the bug was introduced in the 12.19.x branch :
image

And a screenshot showing it with node 14.15.4 proving that a cp in the shell works as well (this is on another system, the /forge-vtt-dev/ folder is the cephfs mount):
image

This also shows a second bug where it's unable to overwrite the file if it already exists, and I'm about to file another issue for it.

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