fs-extra
Advanced tools
Comparing version 7.0.1 to 8.0.0
@@ -0,1 +1,11 @@ | ||
8.0.0 / 2019-05-11 | ||
------------------ | ||
**NOTE:** Node.js v6 support is depreciated, and will be dropped in the next major release. | ||
- Use `renameSync()` under the hood in `moveSync()` | ||
- Fix bug with bind-mounted directories in `copy*()` ([#613](https://github.com/jprichardson/node-fs-extra/issues/613), [#618](https://github.com/jprichardson/node-fs-extra/pull/618)) | ||
- Fix bug in `move()` with case-insensitive file systems | ||
- Use `fs.stat()`'s `bigint` option in `copy*()` & `move*()` where possible ([#657](https://github.com/jprichardson/node-fs-extra/issues/657)) | ||
7.0.1 / 2018-11-07 | ||
@@ -2,0 +12,0 @@ ------------------ |
'use strict' | ||
const fs = require('graceful-fs') | ||
// TODO: enable this once graceful-fs supports bigint option. | ||
// const fs = require('graceful-fs') | ||
const fs = require('fs') | ||
const path = require('path') | ||
const mkdirpSync = require('../mkdirs').mkdirsSync | ||
const utimesSync = require('../util/utimes.js').utimesMillisSync | ||
const stat = require('../util/stat') | ||
const notExist = Symbol('notExist') | ||
function copySync (src, dest, opts) { | ||
@@ -25,6 +26,9 @@ if (typeof opts === 'function') { | ||
const destStat = checkPaths(src, dest) | ||
const { srcStat, destStat } = stat.checkPathsSync(src, dest, 'copy') | ||
stat.checkParentPathsSync(src, srcStat, dest, 'copy') | ||
return handleFilterAndCopy(destStat, src, dest, opts) | ||
} | ||
function handleFilterAndCopy (destStat, src, dest, opts) { | ||
if (opts.filter && !opts.filter(src, dest)) return | ||
const destParent = path.dirname(dest) | ||
@@ -52,3 +56,3 @@ if (!fs.existsSync(destParent)) mkdirpSync(destParent) | ||
function onFile (srcStat, destStat, src, dest, opts) { | ||
if (destStat === notExist) return copyFile(srcStat, src, dest, opts) | ||
if (!destStat) return copyFile(srcStat, src, dest, opts) | ||
return mayCopyFile(srcStat, src, dest, opts) | ||
@@ -99,3 +103,3 @@ } | ||
function onDir (srcStat, destStat, src, dest, opts) { | ||
if (destStat === notExist) return mkDirAndCopy(srcStat, src, dest, opts) | ||
if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts) | ||
if (destStat && !destStat.isDirectory()) { | ||
@@ -120,3 +124,3 @@ throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) | ||
const destItem = path.join(dest, item) | ||
const destStat = checkPaths(srcItem, destItem) | ||
const { destStat } = stat.checkPathsSync(srcItem, destItem, 'copy') | ||
return startCopy(destStat, srcItem, destItem, opts) | ||
@@ -127,3 +131,2 @@ } | ||
let resolvedSrc = fs.readlinkSync(src) | ||
if (opts.dereference) { | ||
@@ -133,3 +136,3 @@ resolvedSrc = path.resolve(process.cwd(), resolvedSrc) | ||
if (destStat === notExist) { | ||
if (!destStat) { | ||
return fs.symlinkSync(resolvedSrc, dest) | ||
@@ -150,3 +153,3 @@ } else { | ||
} | ||
if (isSrcSubdir(resolvedSrc, resolvedDest)) { | ||
if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { | ||
throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`) | ||
@@ -158,3 +161,3 @@ } | ||
// and therefore a broken symlink would be created. | ||
if (fs.statSync(dest).isDirectory() && isSrcSubdir(resolvedDest, resolvedSrc)) { | ||
if (fs.statSync(dest).isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) { | ||
throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`) | ||
@@ -171,32 +174,2 @@ } | ||
// return true if dest is a subdir of src, otherwise false. | ||
function isSrcSubdir (src, dest) { | ||
const srcArray = path.resolve(src).split(path.sep) | ||
const destArray = path.resolve(dest).split(path.sep) | ||
return srcArray.reduce((acc, current, i) => acc && destArray[i] === current, true) | ||
} | ||
function checkStats (src, dest) { | ||
const srcStat = fs.statSync(src) | ||
let destStat | ||
try { | ||
destStat = fs.statSync(dest) | ||
} catch (err) { | ||
if (err.code === 'ENOENT') return {srcStat, destStat: notExist} | ||
throw err | ||
} | ||
return {srcStat, destStat} | ||
} | ||
function checkPaths (src, dest) { | ||
const {srcStat, destStat} = checkStats(src, dest) | ||
if (destStat.ino && destStat.ino === srcStat.ino) { | ||
throw new Error('Source and destination must not be the same.') | ||
} | ||
if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { | ||
throw new Error(`Cannot copy '${src}' to a subdirectory of itself, '${dest}'.`) | ||
} | ||
return destStat | ||
} | ||
module.exports = copySync |
'use strict' | ||
const fs = require('graceful-fs') | ||
// TODO: enable this once graceful-fs supports bigint option. | ||
// const fs = require('graceful-fs') | ||
const fs = require('fs') | ||
const path = require('path') | ||
@@ -8,5 +10,4 @@ const mkdirp = require('../mkdirs').mkdirs | ||
const utimes = require('../util/utimes').utimesMillis | ||
const stat = require('../util/stat') | ||
const notExist = Symbol('notExist') | ||
function copy (src, dest, opts, cb) { | ||
@@ -32,6 +33,10 @@ if (typeof opts === 'function' && !cb) { | ||
checkPaths(src, dest, (err, destStat) => { | ||
stat.checkPaths(src, dest, 'copy', (err, stats) => { | ||
if (err) return cb(err) | ||
if (opts.filter) return handleFilter(checkParentDir, destStat, src, dest, opts, cb) | ||
return checkParentDir(destStat, src, dest, opts, cb) | ||
const { srcStat, destStat } = stats | ||
stat.checkParentPaths(src, srcStat, dest, 'copy', err => { | ||
if (err) return cb(err) | ||
if (opts.filter) return handleFilter(checkParentDir, destStat, src, dest, opts, cb) | ||
return checkParentDir(destStat, src, dest, opts, cb) | ||
}) | ||
}) | ||
@@ -54,6 +59,3 @@ } | ||
Promise.resolve(opts.filter(src, dest)).then(include => { | ||
if (include) { | ||
if (destStat) return onInclude(destStat, src, dest, opts, cb) | ||
return onInclude(src, dest, opts, cb) | ||
} | ||
if (include) return onInclude(destStat, src, dest, opts, cb) | ||
return cb() | ||
@@ -82,3 +84,3 @@ }, error => cb(error)) | ||
function onFile (srcStat, destStat, src, dest, opts, cb) { | ||
if (destStat === notExist) return copyFile(srcStat, src, dest, opts, cb) | ||
if (!destStat) return copyFile(srcStat, src, dest, opts, cb) | ||
return mayCopyFile(srcStat, src, dest, opts, cb) | ||
@@ -129,3 +131,3 @@ } | ||
function onDir (srcStat, destStat, src, dest, opts, cb) { | ||
if (destStat === notExist) return mkDirAndCopy(srcStat, src, dest, opts, cb) | ||
if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts, cb) | ||
if (destStat && !destStat.isDirectory()) { | ||
@@ -163,4 +165,5 @@ return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)) | ||
const destItem = path.join(dest, item) | ||
checkPaths(srcItem, destItem, (err, destStat) => { | ||
stat.checkPaths(srcItem, destItem, 'copy', (err, stats) => { | ||
if (err) return cb(err) | ||
const { destStat } = stats | ||
startCopy(destStat, srcItem, destItem, opts, err => { | ||
@@ -176,3 +179,2 @@ if (err) return cb(err) | ||
if (err) return cb(err) | ||
if (opts.dereference) { | ||
@@ -182,3 +184,3 @@ resolvedSrc = path.resolve(process.cwd(), resolvedSrc) | ||
if (destStat === notExist) { | ||
if (!destStat) { | ||
return fs.symlink(resolvedSrc, dest, cb) | ||
@@ -197,3 +199,3 @@ } else { | ||
} | ||
if (isSrcSubdir(resolvedSrc, resolvedDest)) { | ||
if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) { | ||
return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`)) | ||
@@ -205,3 +207,3 @@ } | ||
// and therefore a broken symlink would be created. | ||
if (destStat.isDirectory() && isSrcSubdir(resolvedDest, resolvedSrc)) { | ||
if (destStat.isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) { | ||
return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)) | ||
@@ -222,36 +224,2 @@ } | ||
// return true if dest is a subdir of src, otherwise false. | ||
function isSrcSubdir (src, dest) { | ||
const srcArray = path.resolve(src).split(path.sep) | ||
const destArray = path.resolve(dest).split(path.sep) | ||
return srcArray.reduce((acc, current, i) => acc && destArray[i] === current, true) | ||
} | ||
function checkStats (src, dest, cb) { | ||
fs.stat(src, (err, srcStat) => { | ||
if (err) return cb(err) | ||
fs.stat(dest, (err, destStat) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') return cb(null, {srcStat, destStat: notExist}) | ||
return cb(err) | ||
} | ||
return cb(null, {srcStat, destStat}) | ||
}) | ||
}) | ||
} | ||
function checkPaths (src, dest, cb) { | ||
checkStats(src, dest, (err, stats) => { | ||
if (err) return cb(err) | ||
const {srcStat, destStat} = stats | ||
if (destStat.ino && destStat.ino === srcStat.ino) { | ||
return cb(new Error('Source and destination must not be the same.')) | ||
} | ||
if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { | ||
return cb(new Error(`Cannot copy '${src}' to a subdirectory of itself, '${dest}'.`)) | ||
} | ||
return cb(null, destStat) | ||
}) | ||
} | ||
module.exports = copy |
'use strict' | ||
const fs = require('graceful-fs') | ||
const path = require('path') | ||
const copySync = require('../copy-sync').copySync | ||
const removeSync = require('../remove').removeSync | ||
const mkdirpSync = require('../mkdirs').mkdirsSync | ||
const buffer = require('../util/buffer') | ||
function moveSync (src, dest, options) { | ||
options = options || {} | ||
const overwrite = options.overwrite || options.clobber || false | ||
src = path.resolve(src) | ||
dest = path.resolve(dest) | ||
if (src === dest) return fs.accessSync(src) | ||
if (isSrcSubdir(src, dest)) throw new Error(`Cannot move '${src}' into itself '${dest}'.`) | ||
mkdirpSync(path.dirname(dest)) | ||
tryRenameSync() | ||
function tryRenameSync () { | ||
if (overwrite) { | ||
try { | ||
return fs.renameSync(src, dest) | ||
} catch (err) { | ||
if (err.code === 'ENOTEMPTY' || err.code === 'EEXIST' || err.code === 'EPERM') { | ||
removeSync(dest) | ||
options.overwrite = false // just overwriteed it, no need to do it again | ||
return moveSync(src, dest, options) | ||
} | ||
if (err.code !== 'EXDEV') throw err | ||
return moveSyncAcrossDevice(src, dest, overwrite) | ||
} | ||
} else { | ||
try { | ||
fs.linkSync(src, dest) | ||
return fs.unlinkSync(src) | ||
} catch (err) { | ||
if (err.code === 'EXDEV' || err.code === 'EISDIR' || err.code === 'EPERM' || err.code === 'ENOTSUP') { | ||
return moveSyncAcrossDevice(src, dest, overwrite) | ||
} | ||
throw err | ||
} | ||
} | ||
} | ||
} | ||
function moveSyncAcrossDevice (src, dest, overwrite) { | ||
const stat = fs.statSync(src) | ||
if (stat.isDirectory()) { | ||
return moveDirSyncAcrossDevice(src, dest, overwrite) | ||
} else { | ||
return moveFileSyncAcrossDevice(src, dest, overwrite) | ||
} | ||
} | ||
function moveFileSyncAcrossDevice (src, dest, overwrite) { | ||
const BUF_LENGTH = 64 * 1024 | ||
const _buff = buffer(BUF_LENGTH) | ||
const flags = overwrite ? 'w' : 'wx' | ||
const fdr = fs.openSync(src, 'r') | ||
const stat = fs.fstatSync(fdr) | ||
const fdw = fs.openSync(dest, flags, stat.mode) | ||
let pos = 0 | ||
while (pos < stat.size) { | ||
const bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos) | ||
fs.writeSync(fdw, _buff, 0, bytesRead) | ||
pos += bytesRead | ||
} | ||
fs.closeSync(fdr) | ||
fs.closeSync(fdw) | ||
return fs.unlinkSync(src) | ||
} | ||
function moveDirSyncAcrossDevice (src, dest, overwrite) { | ||
const options = { | ||
overwrite: false | ||
} | ||
if (overwrite) { | ||
removeSync(dest) | ||
tryCopySync() | ||
} else { | ||
tryCopySync() | ||
} | ||
function tryCopySync () { | ||
copySync(src, dest, options) | ||
return removeSync(src) | ||
} | ||
} | ||
// return true if dest is a subdir of src, otherwise false. | ||
// extract dest base dir and check if that is the same as src basename | ||
function isSrcSubdir (src, dest) { | ||
try { | ||
return fs.statSync(src).isDirectory() && | ||
src !== dest && | ||
dest.indexOf(src) > -1 && | ||
dest.split(path.dirname(src) + path.sep)[1].split(path.sep)[0] === path.basename(src) | ||
} catch (e) { | ||
return false | ||
} | ||
} | ||
module.exports = { | ||
moveSync | ||
moveSync: require('./move-sync') | ||
} |
'use strict' | ||
const u = require('universalify').fromCallback | ||
const fs = require('graceful-fs') | ||
const path = require('path') | ||
const copy = require('../copy').copy | ||
const remove = require('../remove').remove | ||
const mkdirp = require('../mkdirs').mkdirp | ||
const pathExists = require('../path-exists').pathExists | ||
function move (src, dest, opts, cb) { | ||
if (typeof opts === 'function') { | ||
cb = opts | ||
opts = {} | ||
} | ||
const overwrite = opts.overwrite || opts.clobber || false | ||
src = path.resolve(src) | ||
dest = path.resolve(dest) | ||
if (src === dest) return fs.access(src, cb) | ||
fs.stat(src, (err, st) => { | ||
if (err) return cb(err) | ||
if (st.isDirectory() && isSrcSubdir(src, dest)) { | ||
return cb(new Error(`Cannot move '${src}' to a subdirectory of itself, '${dest}'.`)) | ||
} | ||
mkdirp(path.dirname(dest), err => { | ||
if (err) return cb(err) | ||
return doRename(src, dest, overwrite, cb) | ||
}) | ||
}) | ||
} | ||
function doRename (src, dest, overwrite, cb) { | ||
if (overwrite) { | ||
return remove(dest, err => { | ||
if (err) return cb(err) | ||
return rename(src, dest, overwrite, cb) | ||
}) | ||
} | ||
pathExists(dest, (err, destExists) => { | ||
if (err) return cb(err) | ||
if (destExists) return cb(new Error('dest already exists.')) | ||
return rename(src, dest, overwrite, cb) | ||
}) | ||
} | ||
function rename (src, dest, overwrite, cb) { | ||
fs.rename(src, dest, err => { | ||
if (!err) return cb() | ||
if (err.code !== 'EXDEV') return cb(err) | ||
return moveAcrossDevice(src, dest, overwrite, cb) | ||
}) | ||
} | ||
function moveAcrossDevice (src, dest, overwrite, cb) { | ||
const opts = { | ||
overwrite, | ||
errorOnExist: true | ||
} | ||
copy(src, dest, opts, err => { | ||
if (err) return cb(err) | ||
return remove(src, cb) | ||
}) | ||
} | ||
function isSrcSubdir (src, dest) { | ||
const srcArray = src.split(path.sep) | ||
const destArray = dest.split(path.sep) | ||
return srcArray.reduce((acc, current, i) => { | ||
return acc && destArray[i] === current | ||
}, true) | ||
} | ||
module.exports = { | ||
move: u(move) | ||
move: u(require('./move')) | ||
} |
{ | ||
"name": "fs-extra", | ||
"version": "7.0.1", | ||
"version": "8.0.0", | ||
"description": "fs-extra contains methods that aren't included in the vanilla Node.js fs package. Such as mkdir -p, cp -r, and rm -rf.", | ||
@@ -52,7 +52,4 @@ "engines": { | ||
"read-dir-files": "^0.1.1", | ||
"rimraf": "^2.2.8", | ||
"secure-random": "^1.1.1", | ||
"semver": "^5.3.0", | ||
"standard": "^11.0.1", | ||
"standard-markdown": "^4.0.1" | ||
"standard": "^11.0.1" | ||
}, | ||
@@ -59,0 +56,0 @@ "main": "./lib/index.js", |
@@ -25,3 +25,3 @@ Node.js: fs-extra | ||
npm install --save fs-extra | ||
npm install fs-extra | ||
@@ -28,0 +28,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
127060
10
36
1653
7