diff --git a/lib/fs.js b/lib/fs.js index cde3a582727f80..0a2369d684d954 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -2681,7 +2681,6 @@ function realpathSync(p, options) { p += ''; } validatePath(p); - p = pathModule.resolve(p); const cache = options[realpathCacheKey]; const maybeCachedResult = cache?.get(p); @@ -2800,6 +2799,8 @@ function realpathSync(p, options) { } } + p = pathModule.resolve(p); + cache?.set(original, p); return encodeRealpathResult(p, options); } @@ -2842,7 +2843,6 @@ function realpath(p, options, callback) { p += ''; } validatePath(p); - p = pathModule.resolve(p); const seenLinks = new SafeMap(); const knownHard = new SafeSet(); @@ -2875,6 +2875,7 @@ function realpath(p, options, callback) { function LOOP() { // Stop if scanned past end of path if (pos >= p.length) { + p = pathModule.resolve(p); return callback(null, encodeRealpathResult(p, options)); } @@ -2896,6 +2897,7 @@ function realpath(p, options, callback) { if (knownHard.has(base)) { if (isFileType(statValues, S_IFIFO) || isFileType(statValues, S_IFSOCK)) { + p = pathModule.resolve(p); return callback(null, encodeRealpathResult(p, options)); } return process.nextTick(LOOP); diff --git a/test/parallel/test-fs-realpath.js b/test/parallel/test-fs-realpath.js index 6ad074397eb364..89278fceedfd39 100644 --- a/test/parallel/test-fs-realpath.js +++ b/test/parallel/test-fs-realpath.js @@ -85,6 +85,7 @@ function asynctest(testBlock, args, callback, assertBlock) { // sub-tests: function test_simple_error_callback(realpath, realpathSync, cb) { + console.log('test_simple_error_callback'); realpath('/this/path/does/not/exist', common.mustCall(function(err, s) { assert(err); assert(!s); @@ -93,6 +94,7 @@ function test_simple_error_callback(realpath, realpathSync, cb) { } function test_simple_error_cb_with_null_options(realpath, realpathSync, cb) { + console.log('test_simple_error_cb_with_null_options'); realpath('/this/path/does/not/exist', null, common.mustCall(function(err, s) { assert(err); assert(!s); @@ -382,6 +384,43 @@ function test_non_symlinks(realpath, realpathSync, callback) { }); } +function test_parent_after_symlink(realpath, realpathSync, callback) { + console.log('test_parent_after_symlink'); + if (skipSymlinks) { + common.printSkipMessage('symlink test (no privs)'); + return callback(); + } + + const folder = tmp('folder'); + const nested = path.join(folder, 'nested'); + const symlinkDir = tmp('symlink-dir'); + + try { + fs.mkdirSync(folder); + fs.mkdirSync(nested); + } catch { + // Continue regardless of error. + } + + try { fs.unlinkSync(symlinkDir); } catch { + // Continue regardless of error. + } + + fs.symlinkSync(nested, symlinkDir, 'dir'); + unlink.push(symlinkDir); + unlink.push(nested); + unlink.push(folder); + + const a = realpathSync(`${symlinkDir}/..`); + const b = realpathSync(folder); + + assertEqualPath(a, b); + + asynctest(realpath, [`${symlinkDir}/..`], callback, (err, res) => { + assertEqualPath(res, b); + }); +} + const upone = path.join(process.cwd(), '..'); function test_escape_cwd(realpath, realpathSync, cb) { console.log('test_escape_cwd'); @@ -579,6 +618,7 @@ const tests = [ test_up_multiple_with_null_options, test_root, test_root_with_null_options, + test_parent_after_symlink, ]; const numtests = tests.length; let testsRun = 0;