source: trip-planner-front/node_modules/fs-extra/lib/copy/copy.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.8 KB
Line 
1'use strict'
2
3const fs = require('graceful-fs')
4const path = require('path')
5const mkdirp = require('../mkdirs').mkdirs
6const pathExists = require('../path-exists').pathExists
7const utimes = 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 console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n
27 see https://github.com/jprichardson/node-fs-extra/issues/269`)
28 }
29
30 stat.checkPaths(src, dest, 'copy', (err, stats) => {
31 if (err) return cb(err)
32 const { srcStat, destStat } = stats
33 stat.checkParentPaths(src, srcStat, dest, 'copy', err => {
34 if (err) return cb(err)
35 if (opts.filter) return handleFilter(checkParentDir, destStat, src, dest, opts, cb)
36 return checkParentDir(destStat, src, dest, opts, cb)
37 })
38 })
39}
40
41function checkParentDir (destStat, src, dest, opts, cb) {
42 const destParent = path.dirname(dest)
43 pathExists(destParent, (err, dirExists) => {
44 if (err) return cb(err)
45 if (dirExists) return startCopy(destStat, src, dest, opts, cb)
46 mkdirp(destParent, err => {
47 if (err) return cb(err)
48 return startCopy(destStat, src, dest, opts, cb)
49 })
50 })
51}
52
53function handleFilter (onInclude, destStat, src, dest, opts, cb) {
54 Promise.resolve(opts.filter(src, dest)).then(include => {
55 if (include) return onInclude(destStat, src, dest, opts, cb)
56 return cb()
57 }, error => cb(error))
58}
59
60function startCopy (destStat, src, dest, opts, cb) {
61 if (opts.filter) return handleFilter(getStats, destStat, src, dest, opts, cb)
62 return getStats(destStat, src, dest, opts, cb)
63}
64
65function getStats (destStat, src, dest, opts, cb) {
66 const stat = opts.dereference ? fs.stat : fs.lstat
67 stat(src, (err, srcStat) => {
68 if (err) return cb(err)
69
70 if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb)
71 else if (srcStat.isFile() ||
72 srcStat.isCharacterDevice() ||
73 srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb)
74 else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb)
75 })
76}
77
78function onFile (srcStat, destStat, src, dest, opts, cb) {
79 if (!destStat) return copyFile(srcStat, src, dest, opts, cb)
80 return mayCopyFile(srcStat, src, dest, opts, cb)
81}
82
83function mayCopyFile (srcStat, src, dest, opts, cb) {
84 if (opts.overwrite) {
85 fs.unlink(dest, err => {
86 if (err) return cb(err)
87 return copyFile(srcStat, src, dest, opts, cb)
88 })
89 } else if (opts.errorOnExist) {
90 return cb(new Error(`'${dest}' already exists`))
91 } else return cb()
92}
93
94function copyFile (srcStat, src, dest, opts, cb) {
95 if (typeof fs.copyFile === 'function') {
96 return fs.copyFile(src, dest, err => {
97 if (err) return cb(err)
98 return setDestModeAndTimestamps(srcStat, dest, opts, cb)
99 })
100 }
101 return copyFileFallback(srcStat, src, dest, opts, cb)
102}
103
104function copyFileFallback (srcStat, src, dest, opts, cb) {
105 const rs = fs.createReadStream(src)
106 rs.on('error', err => cb(err)).once('open', () => {
107 const ws = fs.createWriteStream(dest, { mode: srcStat.mode })
108 ws.on('error', err => cb(err))
109 .on('open', () => rs.pipe(ws))
110 .once('close', () => setDestModeAndTimestamps(srcStat, dest, opts, cb))
111 })
112}
113
114function setDestModeAndTimestamps (srcStat, dest, opts, cb) {
115 fs.chmod(dest, srcStat.mode, err => {
116 if (err) return cb(err)
117 if (opts.preserveTimestamps) {
118 return utimes(dest, srcStat.atime, srcStat.mtime, cb)
119 }
120 return cb()
121 })
122}
123
124function onDir (srcStat, destStat, src, dest, opts, cb) {
125 if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts, cb)
126 if (destStat && !destStat.isDirectory()) {
127 return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`))
128 }
129 return copyDir(src, dest, opts, cb)
130}
131
132function mkDirAndCopy (srcStat, src, dest, opts, cb) {
133 fs.mkdir(dest, err => {
134 if (err) return cb(err)
135 copyDir(src, dest, opts, err => {
136 if (err) return cb(err)
137 return fs.chmod(dest, srcStat.mode, cb)
138 })
139 })
140}
141
142function copyDir (src, dest, opts, cb) {
143 fs.readdir(src, (err, items) => {
144 if (err) return cb(err)
145 return copyDirItems(items, src, dest, opts, cb)
146 })
147}
148
149function copyDirItems (items, src, dest, opts, cb) {
150 const item = items.pop()
151 if (!item) return cb()
152 return copyDirItem(items, item, src, dest, opts, cb)
153}
154
155function copyDirItem (items, item, src, dest, opts, cb) {
156 const srcItem = path.join(src, item)
157 const destItem = path.join(dest, item)
158 stat.checkPaths(srcItem, destItem, 'copy', (err, stats) => {
159 if (err) return cb(err)
160 const { destStat } = stats
161 startCopy(destStat, srcItem, destItem, opts, err => {
162 if (err) return cb(err)
163 return copyDirItems(items, src, dest, opts, cb)
164 })
165 })
166}
167
168function onLink (destStat, src, dest, opts, cb) {
169 fs.readlink(src, (err, resolvedSrc) => {
170 if (err) return cb(err)
171 if (opts.dereference) {
172 resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
173 }
174
175 if (!destStat) {
176 return fs.symlink(resolvedSrc, dest, cb)
177 } else {
178 fs.readlink(dest, (err, resolvedDest) => {
179 if (err) {
180 // dest exists and is a regular file or directory,
181 // Windows may throw UNKNOWN error. If dest already exists,
182 // fs throws error anyway, so no need to guard against it here.
183 if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb)
184 return cb(err)
185 }
186 if (opts.dereference) {
187 resolvedDest = path.resolve(process.cwd(), resolvedDest)
188 }
189 if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
190 return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`))
191 }
192
193 // do not copy if src is a subdir of dest since unlinking
194 // dest in this case would result in removing src contents
195 // and therefore a broken symlink would be created.
196 if (destStat.isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
197 return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`))
198 }
199 return copyLink(resolvedSrc, dest, cb)
200 })
201 }
202 })
203}
204
205function copyLink (resolvedSrc, dest, cb) {
206 fs.unlink(dest, err => {
207 if (err) return cb(err)
208 return fs.symlink(resolvedSrc, dest, cb)
209 })
210}
211
212module.exports = copy
Note: See TracBrowser for help on using the repository browser.