|
43 | 43 | #include "uv.h"
|
44 | 44 | #include "v8-fast-api-calls.h"
|
45 | 45 |
|
| 46 | +#include <cstdio> |
46 | 47 | #include <filesystem>
|
47 | 48 |
|
48 | 49 | #if defined(__MINGW32__) || defined(_MSC_VER)
|
@@ -3350,6 +3351,72 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
3350 | 3351 | }
|
3351 | 3352 | }
|
3352 | 3353 |
|
| 3354 | +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 | + |
3353 | 3420 | BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
|
3354 | 3421 | Environment* env, const std::string& file_path) {
|
3355 | 3422 | THROW_IF_INSUFFICIENT_PERMISSIONS(
|
@@ -3689,6 +3756,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
3689 | 3756 | SetMethod(isolate, target, "mkdtemp", Mkdtemp);
|
3690 | 3757 |
|
3691 | 3758 | SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths);
|
| 3759 | + SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile); |
3692 | 3760 |
|
3693 | 3761 | StatWatcher::CreatePerIsolateProperties(isolate_data, target);
|
3694 | 3762 | BindingData::CreatePerIsolateProperties(isolate_data, target);
|
@@ -3801,6 +3869,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
3801 | 3869 | registry->Register(CopyFile);
|
3802 | 3870 |
|
3803 | 3871 | registry->Register(CpSyncCheckPaths);
|
| 3872 | + registry->Register(CpSyncOverrideFile); |
3804 | 3873 |
|
3805 | 3874 | registry->Register(Chmod);
|
3806 | 3875 | registry->Register(FChmod);
|
|
0 commit comments