diff --git a/lib/util/__tests__/stat.test.js b/lib/util/__tests__/stat.test.js index 9b984997..613f1d50 100644 --- a/lib/util/__tests__/stat.test.js +++ b/lib/util/__tests__/stat.test.js @@ -4,6 +4,7 @@ const fs = require('../..') const os = require('os') const path = require('path') const assert = require('assert') +const proxyquire = require('proxyquire') const stat = require('../stat.js') /* global beforeEach, afterEach, describe, it */ @@ -66,13 +67,41 @@ describe('util/stat', () => { describe('should get correct identical result when stat.ino or stat.dev is 0n', () => { it('stat.areIdentical', () => { - assert.ok(stat.areIdentical({ ino: 0n, dev: 0n }, { ino: 0n, dev: 0n })) + assert.ok(!stat.areIdentical({ ino: 0n, dev: 0n }, { ino: 0n, dev: 0n })) assert.ok(stat.areIdentical({ ino: 1n, dev: 0n }, { ino: 1n, dev: 0n })) - assert.ok(stat.areIdentical({ ino: 0n, dev: 1n }, { ino: 0n, dev: 1n })) + assert.ok(!stat.areIdentical({ ino: 0n, dev: 1n }, { ino: 0n, dev: 1n })) assert.ok(stat.areIdentical({ ino: 1n, dev: 1n }, { ino: 1n, dev: 1n })) assert.ok(!stat.areIdentical({ ino: 2n, dev: 0n }, { ino: 1n, dev: 0n })) assert.ok(!stat.areIdentical({ ino: 0n, dev: 2n }, { ino: 0n, dev: 1n })) assert.ok(!stat.areIdentical({ ino: 2n, dev: 1n }, { ino: 1n, dev: 2n })) }) }) + + describe('when the filesystem reports 0n for every inode', () => { + const zeroInode = st => Object.assign(st, { ino: 0n }) + const statZero = proxyquire('../stat.js', { + '../fs': { + lstat: (file, opts) => fs.lstat(file, opts).then(zeroInode), + lstatSync: (file, opts) => zeroInode(fs.lstatSync(file, opts)) + } + }) + + it('stat.checkPaths() does not treat different files as the same', async () => { + const src = path.join(TEST_DIR, 'src') + const dest = path.join(TEST_DIR, 'dest') + fs.ensureFileSync(src) + fs.ensureFileSync(dest) + const { destStat } = await statZero.checkPaths(src, dest, 'move', {}) + assert.strictEqual(destStat.ino, 0n) + }) + + it('stat.checkPathsSync() does not treat different files as the same', () => { + const src = path.join(TEST_DIR, 'src') + const dest = path.join(TEST_DIR, 'dest') + fs.ensureFileSync(src) + fs.ensureFileSync(dest) + const { destStat } = statZero.checkPathsSync(src, dest, 'move', {}) + assert.strictEqual(destStat.ino, 0n) + }) + }) }) diff --git a/lib/util/stat.js b/lib/util/stat.js index 040d14c7..416d50e8 100644 --- a/lib/util/stat.js +++ b/lib/util/stat.js @@ -147,7 +147,8 @@ function checkParentPathsSync (src, srcStat, dest, funcName) { function areIdentical (srcStat, destStat) { // stat.dev can be 0n on windows when node version >= 22.x.x - return destStat.ino !== undefined && destStat.dev !== undefined && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev + // stat.ino is 0n on filesystems without inode numbers, so it cannot identify a file + return !!destStat.ino && destStat.dev !== undefined && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev } // return true if dest is a subdir of src, otherwise false.