fs-extra
Advanced tools
Comparing version 8.1.0 to 9.0.0
@@ -5,4 +5,4 @@ 'use strict' | ||
const path = require('path') | ||
const mkdirpSync = require('../mkdirs').mkdirsSync | ||
const utimesSync = require('../util/utimes.js').utimesMillisSync | ||
const mkdirsSync = require('../mkdirs').mkdirsSync | ||
const utimesMillisSync = require('../util/utimes').utimesMillisSync | ||
const stat = require('../util/stat') | ||
@@ -33,3 +33,3 @@ | ||
const destParent = path.dirname(dest) | ||
if (!fs.existsSync(destParent)) mkdirpSync(destParent) | ||
if (!fs.existsSync(destParent)) mkdirsSync(destParent) | ||
return startCopy(destStat, src, dest, opts) | ||
@@ -69,35 +69,37 @@ } | ||
function copyFile (srcStat, src, dest, opts) { | ||
if (typeof fs.copyFileSync === 'function') { | ||
fs.copyFileSync(src, dest) | ||
fs.chmodSync(dest, srcStat.mode) | ||
if (opts.preserveTimestamps) { | ||
return utimesSync(dest, srcStat.atime, srcStat.mtime) | ||
} | ||
return | ||
} | ||
return copyFileFallback(srcStat, src, dest, opts) | ||
fs.copyFileSync(src, dest) | ||
if (opts.preserveTimestamps) handleTimestamps(srcStat.mode, src, dest) | ||
return setDestMode(dest, srcStat.mode) | ||
} | ||
function copyFileFallback (srcStat, src, dest, opts) { | ||
const BUF_LENGTH = 64 * 1024 | ||
const _buff = require('../util/buffer')(BUF_LENGTH) | ||
function handleTimestamps (srcMode, src, dest) { | ||
// Make sure the file is writable before setting the timestamp | ||
// otherwise open fails with EPERM when invoked with 'r+' | ||
// (through utimes call) | ||
if (fileIsNotWritable(srcMode)) makeFileWritable(dest, srcMode) | ||
return setDestTimestamps(src, dest) | ||
} | ||
const fdr = fs.openSync(src, 'r') | ||
const fdw = fs.openSync(dest, 'w', srcStat.mode) | ||
let pos = 0 | ||
function fileIsNotWritable (srcMode) { | ||
return (srcMode & 0o200) === 0 | ||
} | ||
while (pos < srcStat.size) { | ||
const bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos) | ||
fs.writeSync(fdw, _buff, 0, bytesRead) | ||
pos += bytesRead | ||
} | ||
function makeFileWritable (dest, srcMode) { | ||
return setDestMode(dest, srcMode | 0o200) | ||
} | ||
if (opts.preserveTimestamps) fs.futimesSync(fdw, srcStat.atime, srcStat.mtime) | ||
function setDestMode (dest, srcMode) { | ||
return fs.chmodSync(dest, srcMode) | ||
} | ||
fs.closeSync(fdr) | ||
fs.closeSync(fdw) | ||
function setDestTimestamps (src, dest) { | ||
// The initial srcStat.atime cannot be trusted | ||
// because it is modified by the read(2) system call | ||
// (See https://nodejs.org/api/fs.html#fs_stat_time_values) | ||
const updatedSrcStat = fs.statSync(src) | ||
return utimesMillisSync(dest, updatedSrcStat.atime, updatedSrcStat.mtime) | ||
} | ||
function onDir (srcStat, destStat, src, dest, opts) { | ||
if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts) | ||
if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts) | ||
if (destStat && !destStat.isDirectory()) { | ||
@@ -109,6 +111,6 @@ throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`) | ||
function mkDirAndCopy (srcStat, src, dest, opts) { | ||
function mkDirAndCopy (srcMode, src, dest, opts) { | ||
fs.mkdirSync(dest) | ||
copyDir(src, dest, opts) | ||
return fs.chmodSync(dest, srcStat.mode) | ||
return setDestMode(dest, srcMode) | ||
} | ||
@@ -115,0 +117,0 @@ |
@@ -5,5 +5,5 @@ 'use strict' | ||
const path = require('path') | ||
const mkdirp = require('../mkdirs').mkdirs | ||
const mkdirs = require('../mkdirs').mkdirs | ||
const pathExists = require('../path-exists').pathExists | ||
const utimes = require('../util/utimes').utimesMillis | ||
const utimesMillis = require('../util/utimes').utimesMillis | ||
const stat = require('../util/stat') | ||
@@ -47,3 +47,3 @@ | ||
if (dirExists) return startCopy(destStat, src, dest, opts, cb) | ||
mkdirp(destParent, err => { | ||
mkdirs(destParent, err => { | ||
if (err) return cb(err) | ||
@@ -97,28 +97,48 @@ return startCopy(destStat, src, dest, opts, cb) | ||
function copyFile (srcStat, src, dest, opts, cb) { | ||
if (typeof fs.copyFile === 'function') { | ||
return fs.copyFile(src, dest, err => { | ||
fs.copyFile(src, dest, err => { | ||
if (err) return cb(err) | ||
if (opts.preserveTimestamps) return handleTimestampsAndMode(srcStat.mode, src, dest, cb) | ||
return setDestMode(dest, srcStat.mode, cb) | ||
}) | ||
} | ||
function handleTimestampsAndMode (srcMode, src, dest, cb) { | ||
// Make sure the file is writable before setting the timestamp | ||
// otherwise open fails with EPERM when invoked with 'r+' | ||
// (through utimes call) | ||
if (fileIsNotWritable(srcMode)) { | ||
return makeFileWritable(dest, srcMode, err => { | ||
if (err) return cb(err) | ||
return setDestModeAndTimestamps(srcStat, dest, opts, cb) | ||
return setDestTimestampsAndMode(srcMode, src, dest, cb) | ||
}) | ||
} | ||
return copyFileFallback(srcStat, src, dest, opts, cb) | ||
return setDestTimestampsAndMode(srcMode, src, dest, cb) | ||
} | ||
function copyFileFallback (srcStat, src, dest, opts, cb) { | ||
const rs = fs.createReadStream(src) | ||
rs.on('error', err => cb(err)).once('open', () => { | ||
const ws = fs.createWriteStream(dest, { mode: srcStat.mode }) | ||
ws.on('error', err => cb(err)) | ||
.on('open', () => rs.pipe(ws)) | ||
.once('close', () => setDestModeAndTimestamps(srcStat, dest, opts, cb)) | ||
function fileIsNotWritable (srcMode) { | ||
return (srcMode & 0o200) === 0 | ||
} | ||
function makeFileWritable (dest, srcMode, cb) { | ||
return setDestMode(dest, srcMode | 0o200, cb) | ||
} | ||
function setDestTimestampsAndMode (srcMode, src, dest, cb) { | ||
setDestTimestamps(src, dest, err => { | ||
if (err) return cb(err) | ||
return setDestMode(dest, srcMode, cb) | ||
}) | ||
} | ||
function setDestModeAndTimestamps (srcStat, dest, opts, cb) { | ||
fs.chmod(dest, srcStat.mode, err => { | ||
function setDestMode (dest, srcMode, cb) { | ||
return fs.chmod(dest, srcMode, cb) | ||
} | ||
function setDestTimestamps (src, dest, cb) { | ||
// The initial srcStat.atime cannot be trusted | ||
// because it is modified by the read(2) system call | ||
// (See https://nodejs.org/api/fs.html#fs_stat_time_values) | ||
fs.stat(src, (err, updatedSrcStat) => { | ||
if (err) return cb(err) | ||
if (opts.preserveTimestamps) { | ||
return utimes(dest, srcStat.atime, srcStat.mtime, cb) | ||
} | ||
return cb() | ||
return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb) | ||
}) | ||
@@ -128,3 +148,3 @@ } | ||
function onDir (srcStat, destStat, src, dest, opts, cb) { | ||
if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts, cb) | ||
if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts, cb) | ||
if (destStat && !destStat.isDirectory()) { | ||
@@ -136,3 +156,3 @@ return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)) | ||
function mkDirAndCopy (srcStat, src, dest, opts, cb) { | ||
function mkDirAndCopy (srcMode, src, dest, opts, cb) { | ||
fs.mkdir(dest, err => { | ||
@@ -142,3 +162,3 @@ if (err) return cb(err) | ||
if (err) return cb(err) | ||
return fs.chmod(dest, srcStat.mode, cb) | ||
return setDestMode(dest, srcMode, cb) | ||
}) | ||
@@ -145,0 +165,0 @@ }) |
@@ -33,3 +33,3 @@ 'use strict' | ||
items = fs.readdirSync(dir) | ||
} catch (err) { | ||
} catch { | ||
return mkdir.mkdirsSync(dir) | ||
@@ -36,0 +36,0 @@ } |
@@ -7,3 +7,2 @@ 'use strict' | ||
const mkdir = require('../mkdirs') | ||
const pathExists = require('../path-exists').pathExists | ||
@@ -21,9 +20,22 @@ function createFile (file, callback) { | ||
const dir = path.dirname(file) | ||
pathExists(dir, (err, dirExists) => { | ||
if (err) return callback(err) | ||
if (dirExists) return makeFile() | ||
mkdir.mkdirs(dir, err => { | ||
if (err) return callback(err) | ||
makeFile() | ||
}) | ||
fs.stat(dir, (err, stats) => { | ||
if (err) { | ||
// if the directory doesn't exist, make it | ||
if (err.code === 'ENOENT') { | ||
return mkdir.mkdirs(dir, err => { | ||
if (err) return callback(err) | ||
makeFile() | ||
}) | ||
} | ||
return callback(err) | ||
} | ||
if (stats.isDirectory()) makeFile() | ||
else { | ||
// parent is not a directory | ||
// This is just to cause an internal ENOTDIR error to be thrown | ||
fs.readdir(dir, err => { | ||
if (err) return callback(err) | ||
}) | ||
} | ||
}) | ||
@@ -37,8 +49,16 @@ }) | ||
stats = fs.statSync(file) | ||
} catch (e) {} | ||
} catch {} | ||
if (stats && stats.isFile()) return | ||
const dir = path.dirname(file) | ||
if (!fs.existsSync(dir)) { | ||
mkdir.mkdirsSync(dir) | ||
try { | ||
if (!fs.statSync(dir).isDirectory()) { | ||
// parent is not a directory | ||
// This is just to cause an internal ENOTDIR error to be thrown | ||
fs.readdirSync(dir) | ||
} | ||
} catch (err) { | ||
// If the stat call above failed because the directory doesn't exist, create it | ||
if (err && err.code === 'ENOENT') mkdir.mkdirsSync(dir) | ||
else throw err | ||
} | ||
@@ -45,0 +65,0 @@ |
@@ -37,4 +37,4 @@ 'use strict' | ||
return callback(null, { | ||
'toCwd': srcpath, | ||
'toDst': srcpath | ||
toCwd: srcpath, | ||
toDst: srcpath | ||
}) | ||
@@ -49,4 +49,4 @@ }) | ||
return callback(null, { | ||
'toCwd': relativeToDst, | ||
'toDst': srcpath | ||
toCwd: relativeToDst, | ||
toDst: srcpath | ||
}) | ||
@@ -60,4 +60,4 @@ } else { | ||
return callback(null, { | ||
'toCwd': srcpath, | ||
'toDst': path.relative(dstdir, srcpath) | ||
toCwd: srcpath, | ||
toDst: path.relative(dstdir, srcpath) | ||
}) | ||
@@ -76,4 +76,4 @@ }) | ||
return { | ||
'toCwd': srcpath, | ||
'toDst': srcpath | ||
toCwd: srcpath, | ||
toDst: srcpath | ||
} | ||
@@ -86,4 +86,4 @@ } else { | ||
return { | ||
'toCwd': relativeToDst, | ||
'toDst': srcpath | ||
toCwd: relativeToDst, | ||
toDst: srcpath | ||
} | ||
@@ -94,4 +94,4 @@ } else { | ||
return { | ||
'toCwd': srcpath, | ||
'toDst': path.relative(dstdir, srcpath) | ||
toCwd: srcpath, | ||
toDst: path.relative(dstdir, srcpath) | ||
} | ||
@@ -98,0 +98,0 @@ } |
@@ -22,3 +22,3 @@ 'use strict' | ||
stats = fs.lstatSync(srcpath) | ||
} catch (e) { | ||
} catch { | ||
return 'file' | ||
@@ -25,0 +25,0 @@ } |
@@ -21,4 +21,4 @@ 'use strict' | ||
'futimes', | ||
'lchmod', | ||
'lchown', | ||
'lchmod', | ||
'link', | ||
@@ -29,4 +29,5 @@ 'lstat', | ||
'open', | ||
'opendir', | ||
'readdir', | ||
'readFile', | ||
'readdir', | ||
'readlink', | ||
@@ -44,4 +45,3 @@ 'realpath', | ||
// Some commands are not available on some systems. Ex: | ||
// fs.copyFile was added in Node.js v8.5.0 | ||
// fs.mkdtemp was added in Node.js v5.10.0 | ||
// fs.opendir was added in Node.js v12.12.0 | ||
// fs.lchown is not available on at least some Linux | ||
@@ -77,3 +77,3 @@ return typeof fs[key] === 'function' | ||
// fs.read() & fs.write need special treatment due to multiple callback args | ||
// fs.read(), fs.write(), & fs.writev() need special treatment due to multiple callback args | ||
@@ -110,2 +110,21 @@ exports.read = function (fd, buffer, offset, length, position, callback) { | ||
// fs.writev only available in Node v12.9.0+ | ||
if (typeof fs.writev === 'function') { | ||
// Function signature is | ||
// s.writev(fd, buffers[, position], callback) | ||
// We need to handle the optional arg, so we use ...args | ||
exports.writev = function (fd, buffers, ...args) { | ||
if (typeof args[args.length - 1] === 'function') { | ||
return fs.writev(fd, buffers, ...args) | ||
} | ||
return new Promise((resolve, reject) => { | ||
fs.writev(fd, buffers, ...args, (err, bytesWritten, buffers) => { | ||
if (err) return reject(err) | ||
resolve({ bytesWritten, buffers }) | ||
}) | ||
}) | ||
} | ||
} | ||
// fs.realpath.native only available in Node v9.2+ | ||
@@ -112,0 +131,0 @@ if (typeof fs.realpath.native === 'function') { |
'use strict' | ||
module.exports = Object.assign( | ||
{}, | ||
module.exports = { | ||
// Export promiseified graceful-fs: | ||
require('./fs'), | ||
...require('./fs'), | ||
// Export extra methods: | ||
require('./copy-sync'), | ||
require('./copy'), | ||
require('./empty'), | ||
require('./ensure'), | ||
require('./json'), | ||
require('./mkdirs'), | ||
require('./move-sync'), | ||
require('./move'), | ||
require('./output'), | ||
require('./path-exists'), | ||
require('./remove') | ||
) | ||
...require('./copy-sync'), | ||
...require('./copy'), | ||
...require('./empty'), | ||
...require('./ensure'), | ||
...require('./json'), | ||
...require('./mkdirs'), | ||
...require('./move-sync'), | ||
...require('./move'), | ||
...require('./output'), | ||
...require('./path-exists'), | ||
...require('./remove') | ||
} | ||
@@ -21,0 +20,0 @@ // Export fs.promises as a getter property so that we don't trigger |
'use strict' | ||
const u = require('universalify').fromCallback | ||
const u = require('universalify').fromPromise | ||
const jsonFile = require('./jsonfile') | ||
@@ -5,0 +5,0 @@ |
'use strict' | ||
const u = require('universalify').fromCallback | ||
const jsonFile = require('jsonfile') | ||
@@ -8,6 +7,6 @@ | ||
// jsonfile exports | ||
readJson: u(jsonFile.readFile), | ||
readJson: jsonFile.readFile, | ||
readJsonSync: jsonFile.readFileSync, | ||
writeJson: u(jsonFile.writeFile), | ||
writeJson: jsonFile.writeFile, | ||
writeJsonSync: jsonFile.writeFileSync | ||
} |
'use strict' | ||
const fs = require('graceful-fs') | ||
const path = require('path') | ||
const mkdir = require('../mkdirs') | ||
const jsonFile = require('./jsonfile') | ||
const { stringify } = require('jsonfile/utils') | ||
const { outputFileSync } = require('../output') | ||
function outputJsonSync (file, data, options) { | ||
const dir = path.dirname(file) | ||
const str = stringify(data, options) | ||
if (!fs.existsSync(dir)) { | ||
mkdir.mkdirsSync(dir) | ||
} | ||
jsonFile.writeJsonSync(file, data, options) | ||
outputFileSync(file, str, options) | ||
} | ||
module.exports = outputJsonSync |
'use strict' | ||
const path = require('path') | ||
const mkdir = require('../mkdirs') | ||
const pathExists = require('../path-exists').pathExists | ||
const jsonFile = require('./jsonfile') | ||
const { stringify } = require('jsonfile/utils') | ||
const { outputFile } = require('../output') | ||
function outputJson (file, data, options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options | ||
options = {} | ||
} | ||
async function outputJson (file, data, options = {}) { | ||
const str = stringify(data, options) | ||
const dir = path.dirname(file) | ||
pathExists(dir, (err, itDoes) => { | ||
if (err) return callback(err) | ||
if (itDoes) return jsonFile.writeJson(file, data, options, callback) | ||
mkdir.mkdirs(dir, err => { | ||
if (err) return callback(err) | ||
jsonFile.writeJson(file, data, options, callback) | ||
}) | ||
}) | ||
await outputFile(file, str, options) | ||
} | ||
module.exports = outputJson |
'use strict' | ||
const u = require('universalify').fromCallback | ||
const mkdirs = u(require('./mkdirs')) | ||
const mkdirsSync = require('./mkdirs-sync') | ||
const u = require('universalify').fromPromise | ||
const { makeDir: _makeDir, makeDirSync } = require('./make-dir') | ||
const makeDir = u(_makeDir) | ||
module.exports = { | ||
mkdirs, | ||
mkdirsSync, | ||
mkdirs: makeDir, | ||
mkdirsSync: makeDirSync, | ||
// alias | ||
mkdirp: mkdirs, | ||
mkdirpSync: mkdirsSync, | ||
ensureDir: mkdirs, | ||
ensureDirSync: mkdirsSync | ||
mkdirp: makeDir, | ||
mkdirpSync: makeDirSync, | ||
ensureDir: makeDir, | ||
ensureDirSync: makeDirSync | ||
} |
@@ -305,3 +305,3 @@ 'use strict' | ||
return ret | ||
} catch (er) { } | ||
} catch {} | ||
} while (Date.now() - startTime < 500) // give up after 500ms | ||
@@ -308,0 +308,0 @@ } else { |
'use strict' | ||
const fs = require('graceful-fs') | ||
const fs = require('../fs') | ||
const path = require('path') | ||
const util = require('util') | ||
const atLeastNode = require('at-least-node') | ||
const NODE_VERSION_MAJOR_WITH_BIGINT = 10 | ||
const NODE_VERSION_MINOR_WITH_BIGINT = 5 | ||
const NODE_VERSION_PATCH_WITH_BIGINT = 0 | ||
const nodeVersion = process.versions.node.split('.') | ||
const nodeVersionMajor = Number.parseInt(nodeVersion[0], 10) | ||
const nodeVersionMinor = Number.parseInt(nodeVersion[1], 10) | ||
const nodeVersionPatch = Number.parseInt(nodeVersion[2], 10) | ||
const nodeSupportsBigInt = atLeastNode('10.5.0') | ||
const stat = (file) => nodeSupportsBigInt ? fs.stat(file, { bigint: true }) : fs.stat(file) | ||
const statSync = (file) => nodeSupportsBigInt ? fs.statSync(file, { bigint: true }) : fs.statSync(file) | ||
function nodeSupportsBigInt () { | ||
if (nodeVersionMajor > NODE_VERSION_MAJOR_WITH_BIGINT) { | ||
return true | ||
} else if (nodeVersionMajor === NODE_VERSION_MAJOR_WITH_BIGINT) { | ||
if (nodeVersionMinor > NODE_VERSION_MINOR_WITH_BIGINT) { | ||
return true | ||
} else if (nodeVersionMinor === NODE_VERSION_MINOR_WITH_BIGINT) { | ||
if (nodeVersionPatch >= NODE_VERSION_PATCH_WITH_BIGINT) { | ||
return true | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
function getStats (src, dest, cb) { | ||
if (nodeSupportsBigInt()) { | ||
fs.stat(src, { bigint: true }, (err, srcStat) => { | ||
if (err) return cb(err) | ||
fs.stat(dest, { bigint: true }, (err, destStat) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') return cb(null, { srcStat, destStat: null }) | ||
return cb(err) | ||
} | ||
return cb(null, { srcStat, destStat }) | ||
}) | ||
function getStats (src, dest) { | ||
return Promise.all([ | ||
stat(src), | ||
stat(dest).catch(err => { | ||
if (err.code === 'ENOENT') return null | ||
throw err | ||
}) | ||
} else { | ||
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: null }) | ||
return cb(err) | ||
} | ||
return cb(null, { srcStat, destStat }) | ||
}) | ||
}) | ||
} | ||
]).then(([srcStat, destStat]) => ({ srcStat, destStat })) | ||
} | ||
function getStatsSync (src, dest) { | ||
let srcStat, destStat | ||
if (nodeSupportsBigInt()) { | ||
srcStat = fs.statSync(src, { bigint: true }) | ||
} else { | ||
srcStat = fs.statSync(src) | ||
} | ||
let destStat | ||
const srcStat = statSync(src) | ||
try { | ||
if (nodeSupportsBigInt()) { | ||
destStat = fs.statSync(dest, { bigint: true }) | ||
} else { | ||
destStat = fs.statSync(dest) | ||
} | ||
destStat = statSync(dest) | ||
} catch (err) { | ||
@@ -76,6 +35,6 @@ if (err.code === 'ENOENT') return { srcStat, destStat: null } | ||
function checkPaths (src, dest, funcName, cb) { | ||
getStats(src, dest, (err, stats) => { | ||
util.callbackify(getStats)(src, dest, (err, stats) => { | ||
if (err) return cb(err) | ||
const { srcStat, destStat } = stats | ||
if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
if (destStat && areIdentical(srcStat, destStat)) { | ||
return cb(new Error('Source and destination must not be the same.')) | ||
@@ -92,3 +51,3 @@ } | ||
const { srcStat, destStat } = getStatsSync(src, dest) | ||
if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
if (destStat && areIdentical(srcStat, destStat)) { | ||
throw new Error('Source and destination must not be the same.') | ||
@@ -110,25 +69,14 @@ } | ||
if (destParent === srcParent || destParent === path.parse(destParent).root) return cb() | ||
if (nodeSupportsBigInt()) { | ||
fs.stat(destParent, { bigint: true }, (err, destStat) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') return cb() | ||
return cb(err) | ||
} | ||
if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
return cb(new Error(errMsg(src, dest, funcName))) | ||
} | ||
return checkParentPaths(src, srcStat, destParent, funcName, cb) | ||
}) | ||
} else { | ||
fs.stat(destParent, (err, destStat) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') return cb() | ||
return cb(err) | ||
} | ||
if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
return cb(new Error(errMsg(src, dest, funcName))) | ||
} | ||
return checkParentPaths(src, srcStat, destParent, funcName, cb) | ||
}) | ||
const callback = (err, destStat) => { | ||
if (err) { | ||
if (err.code === 'ENOENT') return cb() | ||
return cb(err) | ||
} | ||
if (areIdentical(srcStat, destStat)) { | ||
return cb(new Error(errMsg(src, dest, funcName))) | ||
} | ||
return checkParentPaths(src, srcStat, destParent, funcName, cb) | ||
} | ||
if (nodeSupportsBigInt) fs.stat(destParent, { bigint: true }, callback) | ||
else fs.stat(destParent, callback) | ||
} | ||
@@ -142,7 +90,3 @@ | ||
try { | ||
if (nodeSupportsBigInt()) { | ||
destStat = fs.statSync(destParent, { bigint: true }) | ||
} else { | ||
destStat = fs.statSync(destParent) | ||
} | ||
destStat = statSync(destParent) | ||
} catch (err) { | ||
@@ -152,3 +96,3 @@ if (err.code === 'ENOENT') return | ||
} | ||
if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
if (areIdentical(srcStat, destStat)) { | ||
throw new Error(errMsg(src, dest, funcName)) | ||
@@ -159,2 +103,25 @@ } | ||
function areIdentical (srcStat, destStat) { | ||
if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { | ||
if (nodeSupportsBigInt || destStat.ino < Number.MAX_SAFE_INTEGER) { | ||
// definitive answer | ||
return true | ||
} | ||
// Use additional heuristics if we can't use 'bigint'. | ||
// Different 'ino' could be represented the same if they are >= Number.MAX_SAFE_INTEGER | ||
// See issue 657 | ||
if (destStat.size === srcStat.size && | ||
destStat.mode === srcStat.mode && | ||
destStat.nlink === srcStat.nlink && | ||
destStat.atimeMs === srcStat.atimeMs && | ||
destStat.mtimeMs === srcStat.mtimeMs && | ||
destStat.ctimeMs === srcStat.ctimeMs && | ||
destStat.birthtimeMs === srcStat.birthtimeMs) { | ||
// heuristic answer | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
// return true if dest is a subdir of src, otherwise false. | ||
@@ -161,0 +128,0 @@ // It only checks the path strings. |
'use strict' | ||
const fs = require('graceful-fs') | ||
const os = require('os') | ||
const path = require('path') | ||
// HFS, ext{2,3}, FAT do not, Node.js v0.10 does not | ||
function hasMillisResSync () { | ||
let tmpfile = path.join('millis-test-sync' + Date.now().toString() + Math.random().toString().slice(2)) | ||
tmpfile = path.join(os.tmpdir(), tmpfile) | ||
// 550 millis past UNIX epoch | ||
const d = new Date(1435410243862) | ||
fs.writeFileSync(tmpfile, 'https://github.com/jprichardson/node-fs-extra/pull/141') | ||
const fd = fs.openSync(tmpfile, 'r+') | ||
fs.futimesSync(fd, d, d) | ||
fs.closeSync(fd) | ||
return fs.statSync(tmpfile).mtime > 1435410243000 | ||
} | ||
function hasMillisRes (callback) { | ||
let tmpfile = path.join('millis-test' + Date.now().toString() + Math.random().toString().slice(2)) | ||
tmpfile = path.join(os.tmpdir(), tmpfile) | ||
// 550 millis past UNIX epoch | ||
const d = new Date(1435410243862) | ||
fs.writeFile(tmpfile, 'https://github.com/jprichardson/node-fs-extra/pull/141', err => { | ||
if (err) return callback(err) | ||
fs.open(tmpfile, 'r+', (err, fd) => { | ||
if (err) return callback(err) | ||
fs.futimes(fd, d, d, err => { | ||
if (err) return callback(err) | ||
fs.close(fd, err => { | ||
if (err) return callback(err) | ||
fs.stat(tmpfile, (err, stats) => { | ||
if (err) return callback(err) | ||
callback(null, stats.mtime > 1435410243000) | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) | ||
} | ||
function timeRemoveMillis (timestamp) { | ||
if (typeof timestamp === 'number') { | ||
return Math.floor(timestamp / 1000) * 1000 | ||
} else if (timestamp instanceof Date) { | ||
return new Date(Math.floor(timestamp.getTime() / 1000) * 1000) | ||
} else { | ||
throw new Error('fs-extra: timeRemoveMillis() unknown parameter type') | ||
} | ||
} | ||
function utimesMillis (path, atime, mtime, callback) { | ||
@@ -74,7 +24,4 @@ // if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback) | ||
module.exports = { | ||
hasMillisRes, | ||
hasMillisResSync, | ||
timeRemoveMillis, | ||
utimesMillis, | ||
utimesMillisSync | ||
} |
{ | ||
"name": "fs-extra", | ||
"version": "8.1.0", | ||
"version": "9.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.", | ||
"engines": { | ||
"node": ">=6 <7 || >=8" | ||
"node": ">=10" | ||
}, | ||
@@ -34,3 +34,4 @@ "homepage": "https://github.com/jprichardson/node-fs-extra", | ||
"output", | ||
"move" | ||
"move", | ||
"promise" | ||
], | ||
@@ -40,9 +41,9 @@ "author": "JP Richardson <jprichardson@gmail.com>", | ||
"dependencies": { | ||
"at-least-node": "^1.0.0", | ||
"graceful-fs": "^4.2.0", | ||
"jsonfile": "^4.0.0", | ||
"universalify": "^0.1.0" | ||
"jsonfile": "^6.0.1", | ||
"universalify": "^1.0.0" | ||
}, | ||
"devDependencies": { | ||
"coveralls": "^3.0.0", | ||
"istanbul": "^0.4.5", | ||
"klaw": "^2.1.1", | ||
@@ -52,6 +53,6 @@ "klaw-sync": "^3.0.2", | ||
"mocha": "^5.0.5", | ||
"nyc": "^15.0.0", | ||
"proxyquire": "^2.0.1", | ||
"read-dir-files": "^0.1.1", | ||
"semver": "^5.3.0", | ||
"standard": "^12.0.1" | ||
"standard": "^14.1.0" | ||
}, | ||
@@ -65,3 +66,3 @@ "main": "./lib/index.js", | ||
"full-ci": "npm run lint && npm run coverage", | ||
"coverage": "istanbul cover -i 'lib/**' -x '**/__tests__/**' test.js", | ||
"coverage": "nyc -r lcovonly npm run unit", | ||
"coveralls": "coveralls < coverage/lcov.info", | ||
@@ -68,0 +69,0 @@ "lint": "standard", |
@@ -146,3 +146,3 @@ Node.js: fs-extra | ||
**NOTE:** You can still use the native Node.js methods. They are promisified and copied over to `fs-extra`. See [notes on `fs.read()` & `fs.write()`](docs/fs-read-write.md) | ||
**NOTE:** You can still use the native Node.js methods. They are promisified and copied over to `fs-extra`. See [notes on `fs.read()`, `fs.write()`, & `fs.writev()`](docs/fs-read-write-writev.md) | ||
@@ -149,0 +149,0 @@ ### What happened to `walk()` and `walkSync()`? |
Sorry, the diff of this file is too big to display
129011
9
4
33
1591
+ Addedat-least-node@^1.0.0
+ Addedat-least-node@1.0.0(transitive)
+ Addedjsonfile@6.1.0(transitive)
+ Addeduniversalify@1.0.02.0.1(transitive)
- Removedjsonfile@4.0.0(transitive)
- Removeduniversalify@0.1.2(transitive)
Updatedjsonfile@^6.0.1
Updateduniversalify@^1.0.0