22
33// This file is a modified version of the fs-extra's copySync method.
44
5- const { areIdentical, isSrcSubdir } = require ( 'internal/fs/cp/cp' ) ;
5+ const fsBinding = internalBinding ( 'fs' ) ;
6+ const { isSrcSubdir } = require ( 'internal/fs/cp/cp' ) ;
67const { codes : {
7- ERR_FS_CP_DIR_TO_NON_DIR ,
88 ERR_FS_CP_EEXIST ,
99 ERR_FS_CP_EINVAL ,
10- ERR_FS_CP_FIFO_PIPE ,
11- ERR_FS_CP_NON_DIR_TO_DIR ,
12- ERR_FS_CP_SOCKET ,
1310 ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY ,
14- ERR_FS_CP_UNKNOWN ,
15- ERR_FS_EISDIR ,
1611 ERR_INVALID_RETURN_VALUE ,
1712} } = require ( 'internal/errors' ) ;
1813const {
1914 os : {
2015 errno : {
2116 EEXIST ,
22- EISDIR ,
2317 EINVAL ,
24- ENOTDIR ,
2518 } ,
2619 } ,
2720} = internalBinding ( 'constants' ) ;
2821const {
2922 chmodSync,
3023 copyFileSync,
31- existsSync,
3224 lstatSync,
3325 mkdirSync,
3426 opendirSync,
@@ -42,7 +34,6 @@ const {
4234 dirname,
4335 isAbsolute,
4436 join,
45- parse,
4637 resolve,
4738} = require ( 'path' ) ;
4839const { isPromise } = require ( 'util/types' ) ;
@@ -54,152 +45,46 @@ function cpSyncFn(src, dest, opts) {
5445 'node is not recommended' ;
5546 process . emitWarning ( warning , 'TimestampPrecisionWarning' ) ;
5647 }
57- const { srcStat, destStat, skipped } = checkPathsSync ( src , dest , opts ) ;
58- if ( skipped ) return ;
59- checkParentPathsSync ( src , srcStat , dest ) ;
60- return checkParentDir ( destStat , src , dest , opts ) ;
61- }
62-
63- function checkPathsSync ( src , dest , opts ) {
6448 if ( opts . filter ) {
6549 const shouldCopy = opts . filter ( src , dest ) ;
6650 if ( isPromise ( shouldCopy ) ) {
6751 throw new ERR_INVALID_RETURN_VALUE ( 'boolean' , 'filter' , shouldCopy ) ;
6852 }
69- if ( ! shouldCopy ) return { __proto__ : null , skipped : true } ;
53+ if ( ! shouldCopy ) return ;
7054 }
71- const { srcStat, destStat } = getStatsSync ( src , dest , opts ) ;
7255
73- if ( destStat ) {
74- if ( areIdentical ( srcStat , destStat ) ) {
75- throw new ERR_FS_CP_EINVAL ( {
76- message : 'src and dest cannot be the same' ,
77- path : dest ,
78- syscall : 'cp' ,
79- errno : EINVAL ,
80- code : 'EINVAL' ,
81- } ) ;
82- }
83- if ( srcStat . isDirectory ( ) && ! destStat . isDirectory ( ) ) {
84- throw new ERR_FS_CP_DIR_TO_NON_DIR ( {
85- message : `cannot overwrite non-directory ${ dest } ` +
86- `with directory ${ src } ` ,
87- path : dest ,
88- syscall : 'cp' ,
89- errno : EISDIR ,
90- code : 'EISDIR' ,
91- } ) ;
92- }
93- if ( ! srcStat . isDirectory ( ) && destStat . isDirectory ( ) ) {
94- throw new ERR_FS_CP_NON_DIR_TO_DIR ( {
95- message : `cannot overwrite directory ${ dest } ` +
96- `with non-directory ${ src } ` ,
97- path : dest ,
98- syscall : 'cp' ,
99- errno : ENOTDIR ,
100- code : 'ENOTDIR' ,
101- } ) ;
102- }
103- }
104-
105- if ( srcStat . isDirectory ( ) && isSrcSubdir ( src , dest ) ) {
106- throw new ERR_FS_CP_EINVAL ( {
107- message : `cannot copy ${ src } to a subdirectory of self ${ dest } ` ,
108- path : dest ,
109- syscall : 'cp' ,
110- errno : EINVAL ,
111- code : 'EINVAL' ,
112- } ) ;
113- }
114- return { __proto__ : null , srcStat, destStat, skipped : false } ;
115- }
56+ fsBinding . cpSyncCheckPaths ( src , dest , opts . dereference , opts . recursive ) ;
11657
117- function getStatsSync ( src , dest , opts ) {
118- const statFunc = opts . dereference ? statSync : lstatSync ;
119- const srcStat = statFunc ( src , { bigint : true , throwIfNoEntry : true } ) ;
120- const destStat = statFunc ( dest , { bigint : true , throwIfNoEntry : false } ) ;
121- return { srcStat, destStat } ;
58+ return getStats ( src , dest , opts ) ;
12259}
12360
124- function checkParentPathsSync ( src , srcStat , dest ) {
125- const srcParent = resolve ( dirname ( src ) ) ;
126- const destParent = resolve ( dirname ( dest ) ) ;
127- if ( destParent === srcParent || destParent === parse ( destParent ) . root ) return ;
128- const destStat = statSync ( destParent , { bigint : true , throwIfNoEntry : false } ) ;
129-
130- if ( destStat === undefined ) {
131- return ;
132- }
133-
134- if ( areIdentical ( srcStat , destStat ) ) {
135- throw new ERR_FS_CP_EINVAL ( {
136- message : `cannot copy ${ src } to a subdirectory of self ${ dest } ` ,
137- path : dest ,
138- syscall : 'cp' ,
139- errno : EINVAL ,
140- code : 'EINVAL' ,
141- } ) ;
142- }
143- return checkParentPathsSync ( src , srcStat , destParent ) ;
144- }
145-
146- function checkParentDir ( destStat , src , dest , opts ) {
147- const destParent = dirname ( dest ) ;
148- if ( ! existsSync ( destParent ) ) mkdirSync ( destParent , { recursive : true } ) ;
149- return getStats ( destStat , src , dest , opts ) ;
150- }
151-
152- function getStats ( destStat , src , dest , opts ) {
61+ function getStats ( src , dest , opts ) {
62+ // TODO(@anonrig): Avoid making two stat calls.
15363 const statSyncFn = opts . dereference ? statSync : lstatSync ;
15464 const srcStat = statSyncFn ( src ) ;
65+ const destStat = statSyncFn ( dest , { bigint : true , throwIfNoEntry : false } ) ;
15566
15667 if ( srcStat . isDirectory ( ) && opts . recursive ) {
15768 return onDir ( srcStat , destStat , src , dest , opts ) ;
158- } else if ( srcStat . isDirectory ( ) ) {
159- throw new ERR_FS_EISDIR ( {
160- message : `${ src } is a directory (not copied)` ,
161- path : src ,
162- syscall : 'cp' ,
163- errno : EINVAL ,
164- code : 'EISDIR' ,
165- } ) ;
16669 } else if ( srcStat . isFile ( ) ||
16770 srcStat . isCharacterDevice ( ) ||
16871 srcStat . isBlockDevice ( ) ) {
16972 return onFile ( srcStat , destStat , src , dest , opts ) ;
17073 } else if ( srcStat . isSymbolicLink ( ) ) {
171- return onLink ( destStat , src , dest , opts ) ;
172- } else if ( srcStat . isSocket ( ) ) {
173- throw new ERR_FS_CP_SOCKET ( {
174- message : `cannot copy a socket file: ${ dest } ` ,
175- path : dest ,
176- syscall : 'cp' ,
177- errno : EINVAL ,
178- code : 'EINVAL' ,
179- } ) ;
180- } else if ( srcStat . isFIFO ( ) ) {
181- throw new ERR_FS_CP_FIFO_PIPE ( {
182- message : `cannot copy a FIFO pipe: ${ dest } ` ,
183- path : dest ,
184- syscall : 'cp' ,
185- errno : EINVAL ,
186- code : 'EINVAL' ,
187- } ) ;
74+ return onLink ( destStat , src , dest , opts . verbatimSymlinks ) ;
18875 }
189- throw new ERR_FS_CP_UNKNOWN ( {
190- message : `cannot copy an unknown file type: ${ dest } ` ,
191- path : dest ,
192- syscall : 'cp' ,
193- errno : EINVAL ,
194- code : 'EINVAL' ,
195- } ) ;
76+
77+ // It is not possible to get here because all possible cases are handled above.
78+ const assert = require ( 'internal/assert' ) ;
79+ assert . fail ( 'Unreachable code' ) ;
19680}
19781
19882function onFile ( srcStat , destStat , src , dest , opts ) {
19983 if ( ! destStat ) return copyFile ( srcStat , src , dest , opts ) ;
20084 return mayCopyFile ( srcStat , src , dest , opts ) ;
20185}
20286
87+ // TODO(@anonrig): Move this function to C++.
20388function mayCopyFile ( srcStat , src , dest , opts ) {
20489 if ( opts . force ) {
20590 unlinkSync ( dest ) ;
@@ -249,6 +134,7 @@ function setDestTimestamps(src, dest) {
249134 return utimesSync ( dest , updatedSrcStat . atime , updatedSrcStat . mtime ) ;
250135}
251136
137+ // TODO(@anonrig): Move this function to C++.
252138function onDir ( srcStat , destStat , src , dest , opts ) {
253139 if ( ! destStat ) return mkDirAndCopy ( srcStat . mode , src , dest , opts ) ;
254140 return copyDir ( src , dest , opts ) ;
@@ -260,6 +146,7 @@ function mkDirAndCopy(srcMode, src, dest, opts) {
260146 return setDestMode ( dest , srcMode ) ;
261147}
262148
149+ // TODO(@anonrig): Move this function to C++.
263150function copyDir ( src , dest , opts ) {
264151 const dir = opendirSync ( src ) ;
265152
@@ -270,17 +157,28 @@ function copyDir(src, dest, opts) {
270157 const { name } = dirent ;
271158 const srcItem = join ( src , name ) ;
272159 const destItem = join ( dest , name ) ;
273- const { destStat, skipped } = checkPathsSync ( srcItem , destItem , opts ) ;
274- if ( ! skipped ) getStats ( destStat , srcItem , destItem , opts ) ;
160+ let shouldCopy = true ;
161+
162+ if ( opts . filter ) {
163+ shouldCopy = opts . filter ( srcItem , destItem ) ;
164+ if ( isPromise ( shouldCopy ) ) {
165+ throw new ERR_INVALID_RETURN_VALUE ( 'boolean' , 'filter' , shouldCopy ) ;
166+ }
167+ }
168+
169+ if ( shouldCopy ) {
170+ getStats ( srcItem , destItem , opts ) ;
171+ }
275172 }
276173 } finally {
277174 dir . closeSync ( ) ;
278175 }
279176}
280177
281- function onLink ( destStat , src , dest , opts ) {
178+ // TODO(@anonrig): Move this function to C++.
179+ function onLink ( destStat , src , dest , verbatimSymlinks ) {
282180 let resolvedSrc = readlinkSync ( src ) ;
283- if ( ! opts . verbatimSymlinks && ! isAbsolute ( resolvedSrc ) ) {
181+ if ( ! verbatimSymlinks && ! isAbsolute ( resolvedSrc ) ) {
284182 resolvedSrc = resolve ( dirname ( src ) , resolvedSrc ) ;
285183 }
286184 if ( ! destStat ) {
0 commit comments