You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fs.copyFile on Mac OS does not respect permissions #26936
Platform: Darwin iMac.local 18.2.0 Darwin Kernel Version 18.2.0: Thu Dec 20 20:46:53 PST 2018; root:xnu-4903.241.1~1/RELEASE_X86_64 x86_64
Subsystem:
When setting a file mode to 444 using chmodSync, then trying to copy another file over it, on Windows and on Linux, copyFile will throw an error, but on a Mac it does not, and it will override the file
fs.chmodSync(dest,'444');// then try to fs.copyFile(source,dest,function(err){// i do expect an err here, // but there is no error on Mac});
i even check the stat.mode using parseInt(fs.statSync(dest).mode.toString(8), 10) and it does in fact say 100444
This platform is darwin
fs.stat.mode ./dest: 100444
/Users/akhoury/rcloned/code/NodeBB/rrr.js:26
throw new Error(`This should've thrown an error!`);
^
Error: This should've thrown an error!
I'm able to replicate this bug on Mojave. Seems like libuv is somehow running copyfile() with COPYFILE_UNLINK set or else there's a bug in macOS? @nodejs/fs @nodejs/libuv @nodejs/platform-macos
I'm able to replicate this bug on Mojave. Seems like libuv is somehow running copyfile() with COPYFILE_UNLINK set or else there's a bug in macOS? @nodejs/fs @nodejs/libuv @nodejs/platform-macos
I'm not a macOS person, but being able to bypass file permissions sounds like an OS bug.
This seems to be related to permissions and probably not a bug we can control. I'm also seeing no error by default, but if I run with sudo -u nobody then I get an EPERM error.
I'm not a macOS person, but being able to bypass file permissions sounds like an OS bug.
Yeah, definitely agree after playing around with different copyfile() flags inside libuv. Astonishingly, it seems that copyfile(3) on macOS does not respect file permissions. We can't be the first people to ever experience this, though... 🤔
libuv's fs.c has Apple-specific code for uv__fs_copyfile() added by @cjihrig in libuv/libuv#1465. Do you know if there was a reason other than "use analogous native functionality when you can" for using different code for macOS? Removing it all and using the code used by other UNIX-like operating systems fixes this problem. node continues to pass all tests too. So maybe that's the way to go?
Reacted by Sakthipriyan Vairamani and Ruben Bridgewater
I had recently noticed this behavior divergence also, as it can occur in the context of symlinks (hard or soft): libuv/libuv#2199 (comment). Turning that into an issue has been on my TODO list (and providing analysis on what it seems like it should do), but I think this should already address it.
I was actually a bit surprised by that the proposed behavior here is the desired choice, since it means that a copy may end up with different attributes from the original file, and it uses either the permissions of the hardlink or of the containing directory, if the destination didn't exist at the time. The result is not necessarily more nor less restrictive, just different.
But it seems that what libuv does on unix is the explicit choice for the C++17 standard for std::filesystem::copy_file and is also what unix cp appears to do. So that seems like a good track record to follow. By contrast, cp -f behaves either like "unix" (if the dest file could be opened for write) or like "macos" (if the dest file could not).
Activity
Trott commentedon Mar 27, 2019
I'm able to replicate this bug on Mojave. Seems like libuv is somehow running
copyfile()withCOPYFILE_UNLINKset or else there's a bug in macOS? @nodejs/fs @nodejs/libuv @nodejs/platform-macosTrott commentedon Mar 27, 2019
Confirmed with Node.js 8.x, 10.x, 11.x, and current master branch. (
fs.copyFile()does not exist in Node.js 6.x.)Trott commentedon Mar 27, 2019
I tried adding this to libuv's
fs.cfile and recompiling but it didn't change anything...(Of course, it's entirely likely I'm doing the bit math wrong or something simple like that.....)
richardlau commentedon Mar 27, 2019
I'm not a macOS person, but being able to bypass file permissions sounds like an OS bug.
cjihrig commentedon Mar 27, 2019
This seems to be related to permissions and probably not a bug we can control. I'm also seeing no error by default, but if I run with
sudo -u nobodythen I get anEPERMerror.Trott commentedon Mar 27, 2019
Yeah, definitely agree after playing around with different
copyfile()flags inside libuv. Astonishingly, it seems thatcopyfile(3)on macOS does not respect file permissions. We can't be the first people to ever experience this, though... 🤔Trott commentedon Mar 27, 2019
libuv'sfs.chas Apple-specific code foruv__fs_copyfile()added by @cjihrig in libuv/libuv#1465. Do you know if there was a reason other than "use analogous native functionality when you can" for using different code for macOS? Removing it all and using the code used by other UNIX-like operating systems fixes this problem.nodecontinues to pass all tests too. So maybe that's the way to go?fs: remove macOS-specific copyfile(3)
Trott commentedon Mar 27, 2019
libuv/libuv#2233
test: add known_issues test for fs.copyFile()
Trott commentedon Mar 27, 2019
#26939
vtjnash commentedon Mar 29, 2019
I had recently noticed this behavior divergence also, as it can occur in the context of symlinks (hard or soft): libuv/libuv#2199 (comment). Turning that into an issue has been on my TODO list (and providing analysis on what it seems like it should do), but I think this should already address it.
I was actually a bit surprised by that the proposed behavior here is the desired choice, since it means that a
copymay end up with different attributes from the original file, and it uses either the permissions of the hardlink or of the containing directory, if the destination didn't exist at the time. The result is not necessarily more nor less restrictive, just different.But it seems that what libuv does on unix is the explicit choice for the C++17 standard for
std::filesystem::copy_fileand is also what unixcpappears to do. So that seems like a good track record to follow. By contrast,cp -fbehaves either like "unix" (if the dest file could be opened for write) or like "macos" (if the dest file could not).Shell test script:
test: add known_issues test for fs.copyFile()
test: add known_issues test for fs.copyFile()
test: add known_issues test for fs.copyFile()
fs: remove macOS-specific copyfile(3)
cjihrig commentedon May 2, 2019
This was fixed by #27241.
test: add known_issues test for fs.copyFile()
test: add known_issues test for fs.copyFile()
fs: remove macOS-specific copyfile(3)
fs: remove macOS-specific copyfile(3)