From 221cfd951a0282588b0065cd3275bf611e76d1dd Mon Sep 17 00:00:00 2001 From: Jeremy Schoemaker Date: Tue, 25 Aug 2026 12:41:18 -0500 Subject: [PATCH] fs: use libuv for recursive cpSync to avoid VirtioFS EACCES Fix verified RED->GREEN. fs.cpSync recursive copy fails EACCES on Docker VirtioFS bind mounts via std::filesystem 0200 intermediate at node_file.cc:4205. libstdc++ creates dest with 0200 then fchmod, VirtioFS blocks. Single-file path at 4015 correctly uses uv_fs_copyfile when mode != 0. Fixes: https://github.com/nodejs/node/issues/65497 Signed-off-by: Jeremy Schoemaker Assisted-by: Claude --- src/node_file.cc | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/node_file.cc b/src/node_file.cc index b2e765346cf1..dd1e6ee7054d 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -4202,17 +4202,36 @@ static void CpSyncCopyDir(const FunctionCallbackInfo& args) { return false; } } else if (dir_entry.is_regular_file()) { - std::filesystem::copy_file( - dir_entry.path(), dest_file_path, file_copy_opts, error); - if (error) { - if (error == std::errc::file_exists) { + // Use libuv for regular file copies to avoid VirtioFS EACCES + // (libstdc++ creates dest with 0200 then fchmod, VirtioFS blocks). + // Mirrors single-file path which uses uv_fs_copyfile when mode != 0. + // Handle force / errorOnExist / skipExisting semantics via libuv flags. + if (!force && !error_on_exist) { + std::error_code ec; + if (std::filesystem::exists(dest_file_path, ec) && !ec) { + continue; + } + } + auto src_str = ConvertPathToUTF8(dir_entry.path()); + auto dest_file_str = ConvertPathToUTF8(dest_file_path); + uv_fs_t req; + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + int flags = error_on_exist ? UV_FS_COPYFILE_EXCL : 0; + int result = uv_fs_copyfile(nullptr, + &req, + src_str.c_str(), + dest_file_str.c_str(), + flags, + nullptr); + if (is_uv_error(result)) { + if (result == UV_EEXIST) { THROW_ERR_FS_CP_EEXIST(isolate, "[ERR_FS_CP_EEXIST]: Target already exists: " "cp returned EEXIST (%s already exists)", dest_file_path); return false; } - env->ThrowStdErrException(error, "cp", dest_str.c_str()); + env->ThrowUVException(result, "cp", nullptr, dest_file_str.c_str()); return false; }