|
42 | 42 | #include "uv.h"
|
43 | 43 | #include "v8-fast-api-calls.h"
|
44 | 44 |
|
| 45 | +#include <cstdio> |
45 | 46 | #include <filesystem>
|
46 | 47 |
|
47 | 48 | #if defined(__MINGW32__) || defined(_MSC_VER)
|
@@ -3236,6 +3237,72 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
3236 | 3237 | }
|
3237 | 3238 | }
|
3238 | 3239 |
|
| 3240 | +static void CpSyncOverrideFile(const FunctionCallbackInfo<Value>& args) { |
| 3241 | + Environment* env = Environment::GetCurrent(args); |
| 3242 | + Isolate* isolate = env->isolate(); |
| 3243 | + |
| 3244 | + CHECK_EQ(args.Length(), 4); // src, dest, mode, preserveTimestamps |
| 3245 | + |
| 3246 | + BufferValue src(isolate, args[0]); |
| 3247 | + CHECK_NOT_NULL(*src); |
| 3248 | + ToNamespacedPath(env, &src); |
| 3249 | + |
| 3250 | + BufferValue dest(isolate, args[1]); |
| 3251 | + CHECK_NOT_NULL(*dest); |
| 3252 | + ToNamespacedPath(env, &dest); |
| 3253 | + |
| 3254 | + int mode; |
| 3255 | + if (!GetValidFileMode(env, args[2], UV_FS_COPYFILE).To(&mode)) { |
| 3256 | + return; |
| 3257 | + } |
| 3258 | + |
| 3259 | + bool preserve_timestamps = args[3]->IsTrue(); |
| 3260 | + |
| 3261 | + THROW_IF_INSUFFICIENT_PERMISSIONS( |
| 3262 | + env, permission::PermissionScope::kFileSystemRead, src.ToStringView()); |
| 3263 | + THROW_IF_INSUFFICIENT_PERMISSIONS( |
| 3264 | + env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView()); |
| 3265 | + |
| 3266 | + std::error_code error; |
| 3267 | + |
| 3268 | + if (!std::filesystem::remove(*dest, error)) { |
| 3269 | + return env->ThrowStdErrException(error, "unlink", *dest); |
| 3270 | + } |
| 3271 | + |
| 3272 | + if (mode == 0) { |
| 3273 | + // if no mode is specified use the faster std::filesystem API |
| 3274 | + if (!std::filesystem::copy_file(*src, *dest, error)) { |
| 3275 | + return env->ThrowStdErrException(error, "cp", *dest); |
| 3276 | + } |
| 3277 | + } else { |
| 3278 | + uv_fs_t req; |
| 3279 | + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); |
| 3280 | + auto result = uv_fs_copyfile(nullptr, &req, *src, *dest, mode, nullptr); |
| 3281 | + if (is_uv_error(result)) { |
| 3282 | + return env->ThrowUVException(result, "cp", nullptr, *src, *dest); |
| 3283 | + } |
| 3284 | + } |
| 3285 | + |
| 3286 | + if (preserve_timestamps) { |
| 3287 | + uv_fs_t req; |
| 3288 | + auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); |
| 3289 | + int result = uv_fs_stat(nullptr, &req, *src, nullptr); |
| 3290 | + if (is_uv_error(result)) { |
| 3291 | + return env->ThrowUVException(result, "stat", nullptr, *src); |
| 3292 | + } |
| 3293 | + |
| 3294 | + const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr); |
| 3295 | + const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; |
| 3296 | + const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; |
| 3297 | + |
| 3298 | + int utime_result = |
| 3299 | + uv_fs_utime(nullptr, &req, *dest, source_atime, source_mtime, nullptr); |
| 3300 | + if (is_uv_error(utime_result)) { |
| 3301 | + return env->ThrowUVException(utime_result, "utime", nullptr, *dest); |
| 3302 | + } |
| 3303 | + } |
| 3304 | +} |
| 3305 | + |
3239 | 3306 | BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
|
3240 | 3307 | Environment* env, const std::string& file_path) {
|
3241 | 3308 | THROW_IF_INSUFFICIENT_PERMISSIONS(
|
@@ -3574,6 +3641,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
|
3574 | 3641 | SetMethod(isolate, target, "mkdtemp", Mkdtemp);
|
3575 | 3642 |
|
3576 | 3643 | SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths);
|
| 3644 | + SetMethod(isolate, target, "cpSyncOverrideFile", CpSyncOverrideFile); |
3577 | 3645 |
|
3578 | 3646 | StatWatcher::CreatePerIsolateProperties(isolate_data, target);
|
3579 | 3647 | BindingData::CreatePerIsolateProperties(isolate_data, target);
|
@@ -3685,6 +3753,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
3685 | 3753 | registry->Register(CopyFile);
|
3686 | 3754 |
|
3687 | 3755 | registry->Register(CpSyncCheckPaths);
|
| 3756 | + registry->Register(CpSyncOverrideFile); |
3688 | 3757 |
|
3689 | 3758 | registry->Register(Chmod);
|
3690 | 3759 | registry->Register(FChmod);
|
|
0 commit comments