Skip to content

fix(fs): use libuv for recursive cpSync to avoid VirtioFS EACCES - #65547

Open
shoemoney wants to merge 1 commit into
nodejs:mainfrom
shoemoney:fix/cpsync-virtiofs-permission
Open

fix(fs): use libuv for recursive cpSync to avoid VirtioFS EACCES#65547
shoemoney wants to merge 1 commit into
nodejs:mainfrom
shoemoney:fix/cpsync-virtiofs-permission

Conversation

@shoemoney

@shoemoney shoemoney commented Aug 25, 2026

Copy link
Copy Markdown

Fixes recursive cpSync EACCES on Docker VirtioFS bind mounts.

Bug: CpSyncCopyDir at src/node_file.cc:4205 uses std::filesystem::copy_file which libstdc++ implements by creating dest with 0200 then fchmod. VirtioFS blocks the 0200 creation with EACCES. Single-file path at 4015 already avoids this by using uv_fs_copyfile when mode != 0.

Fix: Use uv_fs_copyfile with mode 0 for recursive regular-file copies, preserving force, errorOnExist and skipExisting semantics via UV_FS_COPYFILE_EXCL and an exists check. Mirrors the single-file path fix.

Evidence: Verified RED before and GREEN after. All 42 test/parallel/test-fs-cp-sync* tests pass sequentially.

Fixes: #65497
Signed-off-by: Jeremy Schoemaker (jeremy@shoemoney.com)

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run. labels Aug 25, 2026
@shoemoney
shoemoney force-pushed the fix/cpsync-virtiofs-permission branch from 0f9ffa7 to 221cfd9 Compare August 25, 2026 22:13
@shoemoney
shoemoney force-pushed the fix/cpsync-virtiofs-permission branch from 7f3d0f5 to be00f60 Compare September 8, 2026 20:32
@shoemoney

Copy link
Copy Markdown
Author

Rebased onto main. CopyDirRecursive() was refactored upstream since this PR was opened: it is now the single implementation shared by fs.cpSync() and the thread-pool fs.cp() job, with a new fresh_destination path used only by fs.cp(). The EACCES bug is still present on the merge-into-existing-directory path, which is the one fs.cpSync() takes, so the fix now lives in CopyDirRecursive()'s regular-file branch instead of directly in CpSyncCopyDir(). Same approach as before: uv_fs_copyfile() instead of std::filesystem::copy_file(), preserving force, errorOnExist and skip-existing semantics via UV_FS_COPYFILE_EXCL and an existence check.

fs.cpSync() recursive copy fails EACCES on Docker VirtioFS bind
mounts. CopyDirRecursive()'s regular-file branch calls
std::filesystem::copy_file(), which libstdc++ implements by creating
dest with mode 0200 and then fchmod(). VirtioFS rejects that initial
0200 open with EACCES. The single-file cpSync path and the
fresh-destination branch of CopyDirRecursive() already avoid this by
using uv_fs_copyfile(), which opens dest with its final mode
directly.

Use uv_fs_copyfile() for the merge-into-existing-directory case too,
preserving force, errorOnExist and skip-existing semantics via
UV_FS_COPYFILE_EXCL and an existence check. Also drops the
file_copy_opts capture, now unused once the regular-file branch no
longer calls std::filesystem::copy_file().

Fixes: nodejs#65497
Signed-off-by: Jeremy Schoemaker <jeremy@shoemoney.com>
@shoemoney
shoemoney force-pushed the fix/cpsync-virtiofs-permission branch from be00f60 to e2396c6 Compare September 8, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to file-system APIs and the fs module. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fs.cpSync fails with EACCES when the destination is on a Docker bind mount (regression in 22.17)

2 participants