2
2
3
3
// This file is a modified version of the fs-extra's copySync method.
4
4
5
- const { areIdentical, isSrcSubdir } = require ( 'internal/fs/cp/cp' ) ;
5
+ const fsBinding = internalBinding ( 'fs' ) ;
6
+ const { isSrcSubdir } = require ( 'internal/fs/cp/cp' ) ;
6
7
const { codes : {
7
- ERR_FS_CP_DIR_TO_NON_DIR ,
8
8
ERR_FS_CP_EEXIST ,
9
9
ERR_FS_CP_EINVAL ,
10
- ERR_FS_CP_FIFO_PIPE ,
11
- ERR_FS_CP_NON_DIR_TO_DIR ,
12
- ERR_FS_CP_SOCKET ,
13
10
ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY ,
14
- ERR_FS_CP_UNKNOWN ,
15
- ERR_FS_EISDIR ,
16
11
ERR_INVALID_RETURN_VALUE ,
17
12
} } = require ( 'internal/errors' ) ;
18
13
const {
19
14
os : {
20
15
errno : {
21
16
EEXIST ,
22
- EISDIR ,
23
17
EINVAL ,
24
- ENOTDIR ,
25
18
} ,
26
19
} ,
27
20
} = internalBinding ( 'constants' ) ;
28
21
const {
29
22
chmodSync,
30
23
copyFileSync,
31
- existsSync,
32
24
lstatSync,
33
25
mkdirSync,
34
26
opendirSync,
@@ -42,7 +34,6 @@ const {
42
34
dirname,
43
35
isAbsolute,
44
36
join,
45
- parse,
46
37
resolve,
47
38
} = require ( 'path' ) ;
48
39
const { isPromise } = require ( 'util/types' ) ;
@@ -54,152 +45,46 @@ function cpSyncFn(src, dest, opts) {
54
45
'node is not recommended' ;
55
46
process . emitWarning ( warning , 'TimestampPrecisionWarning' ) ;
56
47
}
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 ) {
64
48
if ( opts . filter ) {
65
49
const shouldCopy = opts . filter ( src , dest ) ;
66
50
if ( isPromise ( shouldCopy ) ) {
67
51
throw new ERR_INVALID_RETURN_VALUE ( 'boolean' , 'filter' , shouldCopy ) ;
68
52
}
69
- if ( ! shouldCopy ) return { __proto__ : null , skipped : true } ;
53
+ if ( ! shouldCopy ) return ;
70
54
}
71
- const { srcStat, destStat } = getStatsSync ( src , dest , opts ) ;
72
55
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 ) ;
116
57
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 ) ;
122
59
}
123
60
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.
153
63
const statSyncFn = opts . dereference ? statSync : lstatSync ;
154
64
const srcStat = statSyncFn ( src ) ;
65
+ const destStat = statSyncFn ( dest , { bigint : true , throwIfNoEntry : false } ) ;
155
66
156
67
if ( srcStat . isDirectory ( ) && opts . recursive ) {
157
68
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
- } ) ;
166
69
} else if ( srcStat . isFile ( ) ||
167
70
srcStat . isCharacterDevice ( ) ||
168
71
srcStat . isBlockDevice ( ) ) {
169
72
return onFile ( srcStat , destStat , src , dest , opts ) ;
170
73
} 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 ) ;
188
75
}
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' ) ;
196
80
}
197
81
198
82
function onFile ( srcStat , destStat , src , dest , opts ) {
199
83
if ( ! destStat ) return copyFile ( srcStat , src , dest , opts ) ;
200
84
return mayCopyFile ( srcStat , src , dest , opts ) ;
201
85
}
202
86
87
+ // TODO(@anonrig): Move this function to C++.
203
88
function mayCopyFile ( srcStat , src , dest , opts ) {
204
89
if ( opts . force ) {
205
90
unlinkSync ( dest ) ;
@@ -249,6 +134,7 @@ function setDestTimestamps(src, dest) {
249
134
return utimesSync ( dest , updatedSrcStat . atime , updatedSrcStat . mtime ) ;
250
135
}
251
136
137
+ // TODO(@anonrig): Move this function to C++.
252
138
function onDir ( srcStat , destStat , src , dest , opts ) {
253
139
if ( ! destStat ) return mkDirAndCopy ( srcStat . mode , src , dest , opts ) ;
254
140
return copyDir ( src , dest , opts ) ;
@@ -260,6 +146,7 @@ function mkDirAndCopy(srcMode, src, dest, opts) {
260
146
return setDestMode ( dest , srcMode ) ;
261
147
}
262
148
149
+ // TODO(@anonrig): Move this function to C++.
263
150
function copyDir ( src , dest , opts ) {
264
151
const dir = opendirSync ( src ) ;
265
152
@@ -270,17 +157,28 @@ function copyDir(src, dest, opts) {
270
157
const { name } = dirent ;
271
158
const srcItem = join ( src , name ) ;
272
159
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
+ }
275
172
}
276
173
} finally {
277
174
dir . closeSync ( ) ;
278
175
}
279
176
}
280
177
281
- function onLink ( destStat , src , dest , opts ) {
178
+ // TODO(@anonrig): Move this function to C++.
179
+ function onLink ( destStat , src , dest , verbatimSymlinks ) {
282
180
let resolvedSrc = readlinkSync ( src ) ;
283
- if ( ! opts . verbatimSymlinks && ! isAbsolute ( resolvedSrc ) ) {
181
+ if ( ! verbatimSymlinks && ! isAbsolute ( resolvedSrc ) ) {
284
182
resolvedSrc = resolve ( dirname ( src ) , resolvedSrc ) ;
285
183
}
286
184
if ( ! destStat ) {
0 commit comments