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+33533420

BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(

33543421

Environment* env, const std::string& file_path) {

33553422

THROW_IF_INSUFFICIENT_PERMISSIONS(

@@ -3689,6 +3756,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,

36893756

SetMethod(isolate, target, "mkdtemp", Mkdtemp);

3690375736913758

SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths);

3759+

SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile);

3692376036933761

StatWatcher::CreatePerIsolateProperties(isolate_data, target);

36943762

BindingData::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);