From 391fb7365e8fa53af5eadf8d673eda1fdda30db9 Mon Sep 17 00:00:00 2001 From: Maxime Bargiel Date: Sat, 1 Jun 2019 00:43:31 -0400 Subject: [PATCH] Add heuristics to stats.ino comparison when bigint is not available --- lib/util/stat.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/util/stat.js b/lib/util/stat.js index 350cb9f7..1361858e 100644 --- a/lib/util/stat.js +++ b/lib/util/stat.js @@ -76,7 +76,7 @@ function checkPaths (src, dest, funcName, cb) { 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.')) } if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { @@ -88,7 +88,7 @@ function checkPaths (src, dest, funcName, cb) { function checkPathsSync (src, dest, funcName) { 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.') } if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { @@ -111,7 +111,7 @@ function checkParentPaths (src, srcStat, dest, funcName, cb) { if (err.code === 'ENOENT') return cb() return cb(err) } - if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { + if (areIdentical(srcStat, destStat)) { return cb(new Error(errMsg(src, dest, funcName))) } return checkParentPaths(src, srcStat, destParent, funcName, cb) @@ -122,7 +122,7 @@ function checkParentPaths (src, srcStat, dest, funcName, cb) { if (err.code === 'ENOENT') return cb() return cb(err) } - if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { + if (areIdentical(srcStat, destStat)) { return cb(new Error(errMsg(src, dest, funcName))) } return checkParentPaths(src, srcStat, destParent, funcName, cb) @@ -145,12 +145,35 @@ function checkParentPathsSync (src, srcStat, dest, funcName) { if (err.code === 'ENOENT') return throw err } - if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) { + if (areIdentical(srcStat, destStat)) { throw new Error(errMsg(src, dest, funcName)) } return checkParentPathsSync(src, srcStat, destParent, funcName) } +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. // It only checks the path strings. function isSrcSubdir (src, dest) {