source: frontend/node_modules/fs-extra/lib/copy/copy.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.6 KB
Line 
1'use strict'
2
3const fs = require('graceful-fs')
4const path = require('path')
5const mkdirs = require('../mkdirs').mkdirs
6const pathExists = require('../path-exists').pathExists
7const utimesMillis = require('../util/utimes').utimesMillis
8const stat = require('../util/stat')
9
10function copy (src, dest, opts, cb) {
11 if (typeof opts === 'function' && !cb) {
12 cb = opts
13 opts = {}
14 } else if (typeof opts === 'function') {
15 opts = { filter: opts }
16 }
17
18 cb = cb || function () {}
19 opts = opts || {}
20
21 opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now
22 opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber
23
24 // Warn about using preserveTimestamps on 32-bit node
25 if (opts.preserveTimestamps && process.arch === 'ia32') {
26 process.emitWarning(
27 'Using the preserveTimestamps option in 32-bit node is not recommended;\n\n' +
28 '\tsee https://github.com/jprichardson/node-fs-extra/issues/269',
29 'Warning', 'fs-extra-WARN0001'
30 )
31 }
32
33 stat.checkPaths(src, dest, 'copy', opts, (err, stats) => {
34 if (err) return cb(err)
35 const { srcStat, destStat } = stats
36 stat.checkParentPaths(src, srcStat, dest, 'copy', err => {
37 if (err) return cb(err)
38 if (opts.filter) return handleFilter(checkParentDir, destStat, src, dest, opts, cb)
39 return checkParentDir(destStat, src, dest, opts, cb)
40 })
41 })
42}
43
44function checkParentDir (destStat, src, dest, opts, cb) {
45 const destParent = path.dirname(dest)
46 pathExists(destParent, (err, dirExists) => {
47 if (err) return cb(err)
48 if (dirExists) return getStats(destStat, src, dest, opts, cb)
49 mkdirs(destParent, err => {
50 if (err) return cb(err)
51 return getStats(destStat, src, dest, opts, cb)
52 })
53 })
54}
55
56function handleFilter (onInclude, destStat, src, dest, opts, cb) {
57 Promise.resolve(opts.filter(src, dest)).then(include => {
58 if (include) return onInclude(destStat, src, dest, opts, cb)
59 return cb()
60 }, error => cb(error))
61}
62
63function startCopy (destStat, src, dest, opts, cb) {
64 if (opts.filter) return handleFilter(getStats, destStat, src, dest, opts, cb)
65 return getStats(destStat, src, dest, opts, cb)
66}
67
68function getStats (destStat, src, dest, opts, cb) {
69 const stat = opts.dereference ? fs.stat : fs.lstat
70 stat(src, (err, srcStat) => {
71 if (err) return cb(err)
72
73 if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb)
74 else if (srcStat.isFile() ||
75 srcStat.isCharacterDevice() ||
76 srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb)
77 else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb)
78 else if (srcStat.isSocket()) return cb(new Error(`Cannot copy a socket file: ${src}`))
79 else if (srcStat.isFIFO()) return cb(new Error(`Cannot copy a FIFO pipe: ${src}`))
80 return cb(new Error(`Unknown file: ${src}`))
81 })
82}
83
84function onFile (srcStat, destStat, src, dest, opts, cb) {
85 if (!destStat) return copyFile(srcStat, src, dest, opts, cb)
86 return mayCopyFile(srcStat, src, dest, opts, cb)
87}
88
89function mayCopyFile (srcStat, src, dest, opts, cb) {
90 if (opts.overwrite) {
91 fs.unlink(dest, err => {
92 if (err) return cb(err)
93 return copyFile(srcStat, src, dest, opts, cb)
94 })
95 } else if (opts.errorOnExist) {
96 return cb(new Error(`'${dest}' already exists`))
97 } else return cb()
98}
99
100function copyFile (srcStat, src, dest, opts, cb) {
101 fs.copyFile(src, dest, err => {
102 if (err) return cb(err)
103 if (opts.preserveTimestamps) return handleTimestampsAndMode(srcStat.mode, src, dest, cb)
104 return setDestMode(dest, srcStat.mode, cb)
105 })
106}
107
108function handleTimestampsAndMode (srcMode, src, dest, cb) {
109 // Make sure the file is writable before setting the timestamp
110 // otherwise open fails with EPERM when invoked with 'r+'
111 // (through utimes call)
112 if (fileIsNotWritable(srcMode)) {
113 return makeFileWritable(dest, srcMode, err => {
114 if (err) return cb(err)
115 return setDestTimestampsAndMode(srcMode, src, dest, cb)
116 })
117 }
118 return setDestTimestampsAndMode(srcMode, src, dest, cb)
119}
120
121function fileIsNotWritable (srcMode) {
122 return (srcMode & 0o200) === 0
123}
124
125function makeFileWritable (dest, srcMode, cb) {
126 return setDestMode(dest, srcMode | 0o200, cb)
127}
128
129function setDestTimestampsAndMode (srcMode, src, dest, cb) {
130 setDestTimestamps(src, dest, err => {
131 if (err) return cb(err)
132 return setDestMode(dest, srcMode, cb)
133 })
134}
135
136function setDestMode (dest, srcMode, cb) {
137 return fs.chmod(dest, srcMode, cb)
138}
139
140function setDestTimestamps (src, dest, cb) {
141 // The initial srcStat.atime cannot be trusted
142 // because it is modified by the read(2) system call
143 // (See https://nodejs.org/api/fs.html#fs_stat_time_values)
144 fs.stat(src, (err, updatedSrcStat) => {
145 if (err) return cb(err)
146 return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb)
147 })
148}
149
150function onDir (srcStat, destStat, src, dest, opts, cb) {
151 if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts, cb)
152 return copyDir(src, dest, opts, cb)
153}
154
155function mkDirAndCopy (srcMode, src, dest, opts, cb) {
156 fs.mkdir(dest, err => {
157 if (err) return cb(err)
158 copyDir(src, dest, opts, err => {
159 if (err) return cb(err)
160 return setDestMode(dest, srcMode, cb)
161 })
162 })
163}
164
165function copyDir (src, dest, opts, cb) {
166 fs.readdir(src, (err, items) => {
167 if (err) return cb(err)
168 return copyDirItems(items, src, dest, opts, cb)
169 })
170}
171
172function copyDirItems (items, src, dest, opts, cb) {
173 const item = items.pop()
174 if (!item) return cb()
175 return copyDirItem(items, item, src, dest, opts, cb)
176}
177
178function copyDirItem (items, item, src, dest, opts, cb) {
179 const srcItem = path.join(src, item)
180 const destItem = path.join(dest, item)
181 stat.checkPaths(srcItem, destItem, 'copy', opts, (err, stats) => {
182 if (err) return cb(err)
183 const { destStat } = stats
184 startCopy(destStat, srcItem, destItem, opts, err => {
185 if (err) return cb(err)
186 return copyDirItems(items, src, dest, opts, cb)
187 })
188 })
189}
190
191function onLink (destStat, src, dest, opts, cb) {
192 fs.readlink(src, (err, resolvedSrc) => {
193 if (err) return cb(err)
194 if (opts.dereference) {
195 resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
196 }
197
198 if (!destStat) {
199 return fs.symlink(resolvedSrc, dest, cb)
200 } else {
201 fs.readlink(dest, (err, resolvedDest) => {
202 if (err) {
203 // dest exists and is a regular file or directory,
204 // Windows may throw UNKNOWN error. If dest already exists,
205 // fs throws error anyway, so no need to guard against it here.
206 if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb)
207 return cb(err)
208 }
209 if (opts.dereference) {
210 resolvedDest = path.resolve(process.cwd(), resolvedDest)
211 }
212 if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
213 return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`))
214 }
215
216 // do not copy if src is a subdir of dest since unlinking
217 // dest in this case would result in removing src contents
218 // and therefore a broken symlink would be created.
219 if (destStat.isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
220 return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`))
221 }
222 return copyLink(resolvedSrc, dest, cb)
223 })
224 }
225 })
226}
227
228function copyLink (resolvedSrc, dest, cb) {
229 fs.unlink(dest, err => {
230 if (err) return cb(err)
231 return fs.symlink(resolvedSrc, dest, cb)
232 })
233}
234
235module.exports = copy
Note: See TracBrowser for help on using the repository browser.