Skip to content

Commit 7081997

Browse files
src: move cpSync dir copy logic completely to C++
prior to these changes cpSync would copy directories using C++ logic only if the user didn't provide a filtering function to the cpSync call, the changes here make it so that instead C++ is used to copy directories even when a filtering function is provided
1 parent 3c351c2 commit 7081997

File tree

2 files changed

+43
-59
lines changed

2 files changed

+43
-59
lines changed

lib/internal/fs/cp/cp-sync.js

Lines changed: 7 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@ function getStats(src, dest, opts) {
6565
const destStat = statSyncFn(dest, { bigint: true, throwIfNoEntry: false });
6666

6767
if (srcStat.isDirectory() && opts.recursive) {
68-
return onDir(srcStat, destStat, src, dest, opts);
68+
return fsBinding.cpSyncCopyDir(src, dest,
69+
opts.force,
70+
opts.dereference,
71+
opts.errorOnExist,
72+
opts.verbatimSymlinks,
73+
opts.preserveTimestamps,
74+
opts.filter);
6975
} else if (srcStat.isFile() ||
7076
srcStat.isCharacterDevice() ||
7177
srcStat.isBlockDevice()) {
@@ -131,60 +137,6 @@ function setDestTimestamps(src, dest) {
131137
return utimesSync(dest, updatedSrcStat.atime, updatedSrcStat.mtime);
132138
}
133139

134-
// TODO(@anonrig): Move this function to C++.
135-
function onDir(srcStat, destStat, src, dest, opts) {
136-
if (!destStat) return copyDir(src, dest, opts, true, srcStat.mode);
137-
return copyDir(src, dest, opts);
138-
}
139-
140-
function copyDir(src, dest, opts, mkDir, srcMode) {
141-
if (!opts.filter) {
142-
// The caller didn't provide a js filter function, in this case
143-
// we can run the whole function faster in C++
144-
// TODO(dario-piotrowicz): look into making cpSyncCopyDir also accept the potential filter function
145-
return fsBinding.cpSyncCopyDir(src, dest,
146-
opts.force,
147-
opts.dereference,
148-
opts.errorOnExist,
149-
opts.verbatimSymlinks,
150-
opts.preserveTimestamps);
151-
}
152-
153-
if (mkDir) {
154-
mkdirSync(dest);
155-
}
156-
157-
const dir = opendirSync(src);
158-
159-
try {
160-
let dirent;
161-
162-
while ((dirent = dir.readSync()) !== null) {
163-
const { name } = dirent;
164-
const srcItem = join(src, name);
165-
const destItem = join(dest, name);
166-
let shouldCopy = true;
167-
168-
if (opts.filter) {
169-
shouldCopy = opts.filter(srcItem, destItem);
170-
if (isPromise(shouldCopy)) {
171-
throw new ERR_INVALID_RETURN_VALUE('boolean', 'filter', shouldCopy);
172-
}
173-
}
174-
175-
if (shouldCopy) {
176-
getStats(srcItem, destItem, opts);
177-
}
178-
}
179-
} finally {
180-
dir.closeSync();
181-
182-
if (srcMode !== undefined) {
183-
setDestMode(dest, srcMode);
184-
}
185-
}
186-
}
187-
188140
// TODO(@anonrig): Move this function to C++.
189141
function onLink(destStat, src, dest, verbatimSymlinks) {
190142
let resolvedSrc = readlinkSync(src);

src/node_file.cc

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,8 +3411,9 @@ bool isInsideDir(const std::filesystem::path& src,
34113411
}
34123412

34133413
static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
3414-
CHECK_EQ(args.Length(), 7); // src, dest, force, dereference, errorOnExist,
3415-
// verbatimSymlinks, preserveTimestamps
3414+
CHECK_EQ(args.Length(),
3415+
8); // src, dest, force, dereference, errorOnExist,
3416+
// verbatimSymlinks, preserveTimestamps, filterFunction
34163417

34173418
Environment* env = Environment::GetCurrent(args);
34183419
Isolate* isolate = env->isolate();
@@ -3431,6 +3432,27 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
34313432
bool verbatim_symlinks = args[5]->IsTrue();
34323433
bool preserve_timestamps = args[6]->IsTrue();
34333434

3435+
std::function<bool(std::string, std::string)> filter_fn = nullptr;
3436+
3437+
if (args[7]->IsFunction()) {
3438+
Local<v8::Function> args_filter_fn = args[7].As<v8::Function>();
3439+
3440+
filter_fn = [env, args_filter_fn](std::string src,
3441+
std::string dest) -> bool {
3442+
Local<Value> argv[] = {
3443+
String::NewFromUtf8(
3444+
env->isolate(), src.c_str(), v8::NewStringType::kNormal)
3445+
.ToLocalChecked(),
3446+
String::NewFromUtf8(
3447+
env->isolate(), dest.c_str(), v8::NewStringType::kNormal)
3448+
.ToLocalChecked()};
3449+
auto result =
3450+
args_filter_fn->Call(env->context(), Null(env->isolate()), 2, argv)
3451+
.ToLocalChecked();
3452+
return result->BooleanValue(env->isolate());
3453+
};
3454+
}
3455+
34343456
std::error_code error;
34353457
std::filesystem::create_directories(*dest, error);
34363458
if (error) {
@@ -3456,11 +3478,21 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
34563478
force,
34573479
error_on_exist,
34583480
dereference,
3459-
&isolate](std::filesystem::path src,
3460-
std::filesystem::path dest) {
3481+
&isolate,
3482+
&filter_fn](std::filesystem::path src,
3483+
std::filesystem::path dest) {
34613484
std::error_code error;
34623485
for (auto dir_entry : std::filesystem::directory_iterator(src)) {
34633486
auto dest_file_path = dest / dir_entry.path().filename();
3487+
3488+
if (filter_fn) {
3489+
auto shouldSkip =
3490+
!filter_fn(dir_entry.path().c_str(), dest_file_path.c_str());
3491+
if (shouldSkip) {
3492+
continue;
3493+
}
3494+
}
3495+
34643496
auto dest_str = PathToString(dest);
34653497

34663498
if (dir_entry.is_symlink()) {

0 commit comments

Comments
 (0)