-
Notifications
You must be signed in to change notification settings - Fork 20
/
index.js
105 lines (98 loc) · 2.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
var fs = require('fs');
var ncp = require('ncp').ncp;
var path = require('path');
var rimraf = require('rimraf');
var mkdirp = require('mkdirp');
module.exports = mv;
function mv(source, dest, options, cb){
if (typeof options === 'function') {
cb = options;
options = {};
}
var shouldMkdirp = !!options.mkdirp;
var clobber = options.clobber !== false;
var limit = options.limit || 16;
if (shouldMkdirp) {
mkdirs();
} else {
doRename();
}
function mkdirs() {
mkdirp(path.dirname(dest), function(err) {
if (err) return cb(err);
doRename();
});
}
function doRename() {
if (clobber) {
fs.rename(source, dest, function(err) {
if (!err) return cb();
if (err.code !== 'EXDEV') return cb(err);
moveFileAcrossDevice(source, dest, clobber, limit, cb);
});
} else {
fs.link(source, dest, function(err) {
if (err) {
if (err.code === 'EXDEV') {
moveFileAcrossDevice(source, dest, clobber, limit, cb);
return;
}
if (err.code === 'EISDIR' || err.code === 'EPERM') {
moveDirAcrossDevice(source, dest, clobber, limit, cb);
return;
}
cb(err);
return;
}
fs.unlink(source, cb);
});
}
}
}
function moveFileAcrossDevice(source, dest, clobber, limit, cb) {
var outFlags = clobber ? 'w' : 'wx';
var ins = fs.createReadStream(source);
var outs = fs.createWriteStream(dest, {flags: outFlags});
ins.on('error', function(err){
ins.destroy();
outs.destroy();
outs.removeListener('close', onClose);
if (err.code === 'EISDIR' || err.code === 'EPERM') {
moveDirAcrossDevice(source, dest, clobber, limit, cb);
} else {
cb(err);
}
});
outs.on('error', function(err){
ins.destroy();
outs.destroy();
outs.removeListener('close', onClose);
cb(err);
});
outs.once('close', onClose);
ins.pipe(outs);
function onClose(){
fs.unlink(source, cb);
}
}
function moveDirAcrossDevice(source, dest, clobber, limit, cb) {
var options = {
stopOnErr: true,
clobber: false,
limit: limit,
};
if (clobber) {
rimraf(dest, { disableGlob: true }, function(err) {
if (err) return cb(err);
startNcp();
});
} else {
startNcp();
}
function startNcp() {
ncp(source, dest, options, function(errList) {
if (errList) return cb(errList[0]);
rimraf(source, { disableGlob: true }, cb);
});
}
}