fs: improve `cpSync` dest overriding performance · nodejs/node@8870bb8
@@ -43,6 +43,7 @@
4343#include "uv.h"
4444#include "v8-fast-api-calls.h"
454546+#include <cstdio>
4647#include <filesystem>
47484849#if defined(__MINGW32__) || defined(_MSC_VER)
@@ -3350,6 +3351,72 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
33503351 }
33513352}
335233533354+static void CpSyncOverrideFile(const FunctionCallbackInfo<Value>& args) {
3355+ Environment* env = Environment::GetCurrent(args);
3356+ Isolate* isolate = env->isolate();
3357+3358+CHECK_EQ(args.Length(), 4); // src, dest, mode, preserveTimestamps
3359+3360+ BufferValue src(isolate, args[0]);
3361+CHECK_NOT_NULL(*src);
3362+ToNamespacedPath(env, &src);
3363+3364+ BufferValue dest(isolate, args[1]);
3365+CHECK_NOT_NULL(*dest);
3366+ToNamespacedPath(env, &dest);
3367+3368+int mode;
3369+if (!GetValidFileMode(env, args[2], UV_FS_COPYFILE).To(&mode)) {
3370+return;
3371+ }
3372+3373+bool preserve_timestamps = args[3]->IsTrue();
3374+3375+THROW_IF_INSUFFICIENT_PERMISSIONS(
3376+ env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
3377+THROW_IF_INSUFFICIENT_PERMISSIONS(
3378+ env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
3379+3380+ std::error_code error;
3381+3382+if (!std::filesystem::remove(*dest, error)) {
3383+return env->ThrowStdErrException(error, "unlink", *dest);
3384+ }
3385+3386+if (mode == 0) {
3387+// if no mode is specified use the faster std::filesystem API
3388+if (!std::filesystem::copy_file(*src, *dest, error)) {
3389+return env->ThrowStdErrException(error, "cp", *dest);
3390+ }
3391+ } else {
3392+uv_fs_t req;
3393+auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
3394+auto result = uv_fs_copyfile(nullptr, &req, *src, *dest, mode, nullptr);
3395+if (is_uv_error(result)) {
3396+return env->ThrowUVException(result, "cp", nullptr, *src, *dest);
3397+ }
3398+ }
3399+3400+if (preserve_timestamps) {
3401+uv_fs_t req;
3402+auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
3403+int result = uv_fs_stat(nullptr, &req, *src, nullptr);
3404+if (is_uv_error(result)) {
3405+return env->ThrowUVException(result, "stat", nullptr, *src);
3406+ }
3407+3408+const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
3409+const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
3410+const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;
3411+3412+int utime_result =
3413+uv_fs_utime(nullptr, &req, *dest, source_atime, source_mtime, nullptr);
3414+if (is_uv_error(utime_result)) {
3415+return env->ThrowUVException(utime_result, "utime", nullptr, *dest);
3416+ }
3417+ }
3418+}
3419+33533420BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
33543421 Environment* env, const std::string& file_path) {
33553422THROW_IF_INSUFFICIENT_PERMISSIONS(
@@ -3689,6 +3756,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
36893756SetMethod(isolate, target, "mkdtemp", Mkdtemp);
3690375736913758SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths);
3759+SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile);
3692376036933761StatWatcher::CreatePerIsolateProperties(isolate_data, target);
36943762BindingData::CreatePerIsolateProperties(isolate_data, target);
@@ -3801,6 +3869,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
38013869 registry->Register(CopyFile);
3802387038033871 registry->Register(CpSyncCheckPaths);
3872+ registry->Register(CpSyncOverrideFile);
3804387338053874 registry->Register(Chmod);
38063875 registry->Register(FChmod);