Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs.copyFile fails with permission denied even when dest folder is writable #37285

Closed
kakaroto opened this issue Feb 9, 2021 · 2 comments
Closed
Labels
fs Issues and PRs related to the fs subsystem / file system.

Comments

@kakaroto
Copy link

kakaroto commented Feb 9, 2021

What steps will reproduce the bug?

Following up from issue #37284, the second issue I discovered is that if you copy a file to replace an existing read-only file, it will fail with permission denied, even if the copy should be possible because the parent folder is writable.

Simple code to reproduce the issue :

const fs = require("fs");

fs.copyFileSync("/tmp/foo", "/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 succeed the first time it runs, but will fail the second time, as the file already exists and is read-only, but using a cp /tmp/foo /tmp/bar command in the shell will succeed because the parent directory is writable, therefore, we can delete/create files in it, regardless of their individual file permissions.

You can test it by pasting this script into the shell from docker run --rm -it node:14-alpine /bin/sh :

su - node
touch /tmp/foo
chmod -w /tmp/foo
cat <<EOF > test.js
const fs = require("fs");
fs.copyFileSync("/tmp/foo", "/tmp/bar");
EOF
# Succeed
rm -f /tmp/bar
node test.js
ls -l /tmp/bar
# Fail
node test.js
# Succeeds from the shell
touch -t 202101010000 /tmp/bar
ls -l /tmp/bar
cp /tmp/foo /tmp/bar
ls -l /tmp/bar
exit
exit

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

always reproducible

What is the expected behavior?

Copying a file into a writable directory should succeed. The behavior with copyFile should be the same as with a shell cp in this case.

What do you see instead?

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

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

Additional information

Contrarily to issue #37284, this issue happens with node 12.18.4 as well, so the cause may not be related.
Note that this is also a lower priority for me, because logically, we might expect a read-only file to not be overwritable, even if that's not how the Unix permissions function.

@PoojaDurgad PoojaDurgad added the fs Issues and PRs related to the fs subsystem / file system. label Feb 9, 2021
@RaisinTen
Copy link
Contributor

cp doesn't seem to be able to copy over the file:

❯ mkdir a b
❯ touch a/file
❯ ls -l a/file
-rw-r--r-- 1 raisinten raisinten 0 Feb  9 19:25 a/file
❯ chmod -w a/file
❯ cp a/file b/file
❯ ls -l a/file b/file
-r--r--r-- 1 raisinten raisinten 0 Feb  9 19:25 a/file
-r--r--r-- 1 raisinten raisinten 0 Feb  9 19:26 b/file
❯ touch -t 202101010000 b/file
❯ cp a/file b/file
cp: cannot create regular file 'b/file': Permission denied
❯ echo $?
1
❯ ls -l a/file b/file
-r--r--r-- 1 raisinten raisinten 0 Feb  9 19:25 a/file
-r--r--r-- 1 raisinten raisinten 0 Jan  1 00:00 b/file

Am I doing something wrong?

@kakaroto
Copy link
Author

kakaroto commented Feb 9, 2021

Am I doing something wrong?

I guess not.
I tried the above on my machine and got the same "permission denied" error as you. I tried it in that alpine docker image, and got it to work, so I believe it's actually an issue with busybox's version of cp used in alpine Linux, which succeeds in the copy as long as it's able to (i.e: forcibly deleting the file first before copying the new one).
On my Debian system, the cp only worked with using -f argument.

Sorry about that, but it does seem like this report is invalid in that case. Thankfully, it's not a problem for my use case, it was just something I noticed while trying to debug issue #37284.
Thanks.

@kakaroto kakaroto closed this as completed Feb 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fs Issues and PRs related to the fs subsystem / file system.
Projects
None yet
Development

No branches or pull requests

3 participants