11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci'use strict';
231cb0ef41Sopenharmony_ciconst common = require('../common');
241cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
251cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciif (!common.isMainThread)
281cb0ef41Sopenharmony_ci  common.skip('process.chdir is not available in Workers');
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciconst assert = require('assert');
311cb0ef41Sopenharmony_ciconst fs = require('fs');
321cb0ef41Sopenharmony_ciconst path = require('path');
331cb0ef41Sopenharmony_cilet async_completed = 0;
341cb0ef41Sopenharmony_cilet async_expected = 0;
351cb0ef41Sopenharmony_ciconst unlink = [];
361cb0ef41Sopenharmony_ciconst skipSymlinks = !common.canCreateSymLink();
371cb0ef41Sopenharmony_ciconst tmpDir = tmpdir.path;
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_citmpdir.refresh();
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cilet root = '/';
421cb0ef41Sopenharmony_cilet assertEqualPath = assert.strictEqual;
431cb0ef41Sopenharmony_ciif (common.isWindows) {
441cb0ef41Sopenharmony_ci  // Something like "C:\\"
451cb0ef41Sopenharmony_ci  root = process.cwd().substr(0, 3);
461cb0ef41Sopenharmony_ci  assertEqualPath = function(path_left, path_right, message) {
471cb0ef41Sopenharmony_ci    assert
481cb0ef41Sopenharmony_ci      .strictEqual(path_left.toLowerCase(), path_right.toLowerCase(), message);
491cb0ef41Sopenharmony_ci  };
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciprocess.nextTick(runTest);
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cifunction tmp(p) {
551cb0ef41Sopenharmony_ci  return path.join(tmpDir, p);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ciconst targetsAbsDir = path.join(tmpDir, 'targets');
591cb0ef41Sopenharmony_ciconst tmpAbsDir = tmpDir;
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci// Set up targetsAbsDir and expected subdirectories
621cb0ef41Sopenharmony_cifs.mkdirSync(targetsAbsDir);
631cb0ef41Sopenharmony_cifs.mkdirSync(path.join(targetsAbsDir, 'nested-index'));
641cb0ef41Sopenharmony_cifs.mkdirSync(path.join(targetsAbsDir, 'nested-index', 'one'));
651cb0ef41Sopenharmony_cifs.mkdirSync(path.join(targetsAbsDir, 'nested-index', 'two'));
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_cifunction asynctest(testBlock, args, callback, assertBlock) {
681cb0ef41Sopenharmony_ci  async_expected++;
691cb0ef41Sopenharmony_ci  testBlock.apply(testBlock, args.concat(function(err) {
701cb0ef41Sopenharmony_ci    let ignoreError = false;
711cb0ef41Sopenharmony_ci    if (assertBlock) {
721cb0ef41Sopenharmony_ci      try {
731cb0ef41Sopenharmony_ci        ignoreError = assertBlock.apply(assertBlock, arguments);
741cb0ef41Sopenharmony_ci      } catch (e) {
751cb0ef41Sopenharmony_ci        err = e;
761cb0ef41Sopenharmony_ci      }
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci    async_completed++;
791cb0ef41Sopenharmony_ci    callback(ignoreError ? null : err);
801cb0ef41Sopenharmony_ci  }));
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci// sub-tests:
841cb0ef41Sopenharmony_cifunction test_simple_error_callback(realpath, realpathSync, cb) {
851cb0ef41Sopenharmony_ci  realpath('/this/path/does/not/exist', common.mustCall(function(err, s) {
861cb0ef41Sopenharmony_ci    assert(err);
871cb0ef41Sopenharmony_ci    assert(!s);
881cb0ef41Sopenharmony_ci    cb();
891cb0ef41Sopenharmony_ci  }));
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_cifunction test_simple_error_cb_with_null_options(realpath, realpathSync, cb) {
931cb0ef41Sopenharmony_ci  realpath('/this/path/does/not/exist', null, common.mustCall(function(err, s) {
941cb0ef41Sopenharmony_ci    assert(err);
951cb0ef41Sopenharmony_ci    assert(!s);
961cb0ef41Sopenharmony_ci    cb();
971cb0ef41Sopenharmony_ci  }));
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_cifunction test_simple_relative_symlink(realpath, realpathSync, callback) {
1011cb0ef41Sopenharmony_ci  console.log('test_simple_relative_symlink');
1021cb0ef41Sopenharmony_ci  if (skipSymlinks) {
1031cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
1041cb0ef41Sopenharmony_ci    return callback();
1051cb0ef41Sopenharmony_ci  }
1061cb0ef41Sopenharmony_ci  const entry = `${tmpDir}/symlink`;
1071cb0ef41Sopenharmony_ci  const expected = `${tmpDir}/cycles/root.js`;
1081cb0ef41Sopenharmony_ci  [
1091cb0ef41Sopenharmony_ci    [entry, `../${path.basename(tmpDir)}/cycles/root.js`],
1101cb0ef41Sopenharmony_ci  ].forEach(function(t) {
1111cb0ef41Sopenharmony_ci    try { fs.unlinkSync(t[0]); } catch {
1121cb0ef41Sopenharmony_ci      // Continue regardless of error.
1131cb0ef41Sopenharmony_ci    }
1141cb0ef41Sopenharmony_ci    console.log('fs.symlinkSync(%j, %j, %j)', t[1], t[0], 'file');
1151cb0ef41Sopenharmony_ci    fs.symlinkSync(t[1], t[0], 'file');
1161cb0ef41Sopenharmony_ci    unlink.push(t[0]);
1171cb0ef41Sopenharmony_ci  });
1181cb0ef41Sopenharmony_ci  const result = realpathSync(entry);
1191cb0ef41Sopenharmony_ci  assertEqualPath(result, path.resolve(expected));
1201cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
1211cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
1221cb0ef41Sopenharmony_ci  });
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_cifunction test_simple_absolute_symlink(realpath, realpathSync, callback) {
1261cb0ef41Sopenharmony_ci  console.log('test_simple_absolute_symlink');
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  // This one should still run, even if skipSymlinks is set,
1291cb0ef41Sopenharmony_ci  // because it uses a junction.
1301cb0ef41Sopenharmony_ci  const type = skipSymlinks ? 'junction' : 'dir';
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  console.log('using type=%s', type);
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  const entry = `${tmpAbsDir}/symlink`;
1351cb0ef41Sopenharmony_ci  const expected = fixtures.path('nested-index', 'one');
1361cb0ef41Sopenharmony_ci  [
1371cb0ef41Sopenharmony_ci    [entry, expected],
1381cb0ef41Sopenharmony_ci  ].forEach(function(t) {
1391cb0ef41Sopenharmony_ci    try { fs.unlinkSync(t[0]); } catch {
1401cb0ef41Sopenharmony_ci      // Continue regardless of error.
1411cb0ef41Sopenharmony_ci    }
1421cb0ef41Sopenharmony_ci    console.error('fs.symlinkSync(%j, %j, %j)', t[1], t[0], type);
1431cb0ef41Sopenharmony_ci    fs.symlinkSync(t[1], t[0], type);
1441cb0ef41Sopenharmony_ci    unlink.push(t[0]);
1451cb0ef41Sopenharmony_ci  });
1461cb0ef41Sopenharmony_ci  const result = realpathSync(entry);
1471cb0ef41Sopenharmony_ci  assertEqualPath(result, path.resolve(expected));
1481cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
1491cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
1501cb0ef41Sopenharmony_ci  });
1511cb0ef41Sopenharmony_ci}
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_cifunction test_deep_relative_file_symlink(realpath, realpathSync, callback) {
1541cb0ef41Sopenharmony_ci  console.log('test_deep_relative_file_symlink');
1551cb0ef41Sopenharmony_ci  if (skipSymlinks) {
1561cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
1571cb0ef41Sopenharmony_ci    return callback();
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  const expected = fixtures.path('cycles', 'root.js');
1611cb0ef41Sopenharmony_ci  const linkData1 = path
1621cb0ef41Sopenharmony_ci                      .relative(path.join(targetsAbsDir, 'nested-index', 'one'),
1631cb0ef41Sopenharmony_ci                                expected);
1641cb0ef41Sopenharmony_ci  const linkPath1 = path.join(targetsAbsDir,
1651cb0ef41Sopenharmony_ci                              'nested-index', 'one', 'symlink1.js');
1661cb0ef41Sopenharmony_ci  try { fs.unlinkSync(linkPath1); } catch {
1671cb0ef41Sopenharmony_ci    // Continue regardless of error.
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci  fs.symlinkSync(linkData1, linkPath1, 'file');
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  const linkData2 = '../one/symlink1.js';
1721cb0ef41Sopenharmony_ci  const entry = path.join(targetsAbsDir,
1731cb0ef41Sopenharmony_ci                          'nested-index', 'two', 'symlink1-b.js');
1741cb0ef41Sopenharmony_ci  try { fs.unlinkSync(entry); } catch {
1751cb0ef41Sopenharmony_ci    // Continue regardless of error.
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci  fs.symlinkSync(linkData2, entry, 'file');
1781cb0ef41Sopenharmony_ci  unlink.push(linkPath1);
1791cb0ef41Sopenharmony_ci  unlink.push(entry);
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(entry), path.resolve(expected));
1821cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
1831cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
1841cb0ef41Sopenharmony_ci  });
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_cifunction test_deep_relative_dir_symlink(realpath, realpathSync, callback) {
1881cb0ef41Sopenharmony_ci  console.log('test_deep_relative_dir_symlink');
1891cb0ef41Sopenharmony_ci  if (skipSymlinks) {
1901cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
1911cb0ef41Sopenharmony_ci    return callback();
1921cb0ef41Sopenharmony_ci  }
1931cb0ef41Sopenharmony_ci  const expected = fixtures.path('cycles', 'folder');
1941cb0ef41Sopenharmony_ci  const path1b = path.join(targetsAbsDir, 'nested-index', 'one');
1951cb0ef41Sopenharmony_ci  const linkPath1b = path.join(path1b, 'symlink1-dir');
1961cb0ef41Sopenharmony_ci  const linkData1b = path.relative(path1b, expected);
1971cb0ef41Sopenharmony_ci  try { fs.unlinkSync(linkPath1b); } catch {
1981cb0ef41Sopenharmony_ci    // Continue regardless of error.
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci  fs.symlinkSync(linkData1b, linkPath1b, 'dir');
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  const linkData2b = '../one/symlink1-dir';
2031cb0ef41Sopenharmony_ci  const entry = path.join(targetsAbsDir,
2041cb0ef41Sopenharmony_ci                          'nested-index', 'two', 'symlink12-dir');
2051cb0ef41Sopenharmony_ci  try { fs.unlinkSync(entry); } catch {
2061cb0ef41Sopenharmony_ci    // Continue regardless of error.
2071cb0ef41Sopenharmony_ci  }
2081cb0ef41Sopenharmony_ci  fs.symlinkSync(linkData2b, entry, 'dir');
2091cb0ef41Sopenharmony_ci  unlink.push(linkPath1b);
2101cb0ef41Sopenharmony_ci  unlink.push(entry);
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(entry), path.resolve(expected));
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
2151cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
2161cb0ef41Sopenharmony_ci  });
2171cb0ef41Sopenharmony_ci}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_cifunction test_cyclic_link_protection(realpath, realpathSync, callback) {
2201cb0ef41Sopenharmony_ci  console.log('test_cyclic_link_protection');
2211cb0ef41Sopenharmony_ci  if (skipSymlinks) {
2221cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
2231cb0ef41Sopenharmony_ci    return callback();
2241cb0ef41Sopenharmony_ci  }
2251cb0ef41Sopenharmony_ci  const entry = path.join(tmpDir, '/cycles/realpath-3a');
2261cb0ef41Sopenharmony_ci  [
2271cb0ef41Sopenharmony_ci    [entry, '../cycles/realpath-3b'],
2281cb0ef41Sopenharmony_ci    [path.join(tmpDir, '/cycles/realpath-3b'), '../cycles/realpath-3c'],
2291cb0ef41Sopenharmony_ci    [path.join(tmpDir, '/cycles/realpath-3c'), '../cycles/realpath-3a'],
2301cb0ef41Sopenharmony_ci  ].forEach(function(t) {
2311cb0ef41Sopenharmony_ci    try { fs.unlinkSync(t[0]); } catch {
2321cb0ef41Sopenharmony_ci      // Continue regardless of error.
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci    fs.symlinkSync(t[1], t[0], 'dir');
2351cb0ef41Sopenharmony_ci    unlink.push(t[0]);
2361cb0ef41Sopenharmony_ci  });
2371cb0ef41Sopenharmony_ci  assert.throws(() => {
2381cb0ef41Sopenharmony_ci    realpathSync(entry);
2391cb0ef41Sopenharmony_ci  }, { code: 'ELOOP', name: 'Error' });
2401cb0ef41Sopenharmony_ci  asynctest(
2411cb0ef41Sopenharmony_ci    realpath, [entry], callback, common.mustCall(function(err, result) {
2421cb0ef41Sopenharmony_ci      assert.strictEqual(err.path, entry);
2431cb0ef41Sopenharmony_ci      assert.strictEqual(result, undefined);
2441cb0ef41Sopenharmony_ci      return true;
2451cb0ef41Sopenharmony_ci    }));
2461cb0ef41Sopenharmony_ci}
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_cifunction test_cyclic_link_overprotection(realpath, realpathSync, callback) {
2491cb0ef41Sopenharmony_ci  console.log('test_cyclic_link_overprotection');
2501cb0ef41Sopenharmony_ci  if (skipSymlinks) {
2511cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
2521cb0ef41Sopenharmony_ci    return callback();
2531cb0ef41Sopenharmony_ci  }
2541cb0ef41Sopenharmony_ci  const cycles = `${tmpDir}/cycles`;
2551cb0ef41Sopenharmony_ci  const expected = realpathSync(cycles);
2561cb0ef41Sopenharmony_ci  const folder = `${cycles}/folder`;
2571cb0ef41Sopenharmony_ci  const link = `${folder}/cycles`;
2581cb0ef41Sopenharmony_ci  let testPath = cycles;
2591cb0ef41Sopenharmony_ci  testPath += '/folder/cycles'.repeat(10);
2601cb0ef41Sopenharmony_ci  try { fs.unlinkSync(link); } catch {
2611cb0ef41Sopenharmony_ci    // Continue regardless of error.
2621cb0ef41Sopenharmony_ci  }
2631cb0ef41Sopenharmony_ci  fs.symlinkSync(cycles, link, 'dir');
2641cb0ef41Sopenharmony_ci  unlink.push(link);
2651cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(testPath), path.resolve(expected));
2661cb0ef41Sopenharmony_ci  asynctest(realpath, [testPath], callback, function(er, res) {
2671cb0ef41Sopenharmony_ci    assertEqualPath(res, path.resolve(expected));
2681cb0ef41Sopenharmony_ci  });
2691cb0ef41Sopenharmony_ci}
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_cifunction test_relative_input_cwd(realpath, realpathSync, callback) {
2721cb0ef41Sopenharmony_ci  console.log('test_relative_input_cwd');
2731cb0ef41Sopenharmony_ci  if (skipSymlinks) {
2741cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
2751cb0ef41Sopenharmony_ci    return callback();
2761cb0ef41Sopenharmony_ci  }
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci  // We need to calculate the relative path to the tmp dir from cwd
2791cb0ef41Sopenharmony_ci  const entrydir = process.cwd();
2801cb0ef41Sopenharmony_ci  const entry = path.relative(entrydir,
2811cb0ef41Sopenharmony_ci                              path.join(`${tmpDir}/cycles/realpath-3a`));
2821cb0ef41Sopenharmony_ci  const expected = `${tmpDir}/cycles/root.js`;
2831cb0ef41Sopenharmony_ci  [
2841cb0ef41Sopenharmony_ci    [entry, '../cycles/realpath-3b'],
2851cb0ef41Sopenharmony_ci    [`${tmpDir}/cycles/realpath-3b`, '../cycles/realpath-3c'],
2861cb0ef41Sopenharmony_ci    [`${tmpDir}/cycles/realpath-3c`, 'root.js'],
2871cb0ef41Sopenharmony_ci  ].forEach(function(t) {
2881cb0ef41Sopenharmony_ci    const fn = t[0];
2891cb0ef41Sopenharmony_ci    console.error('fn=%j', fn);
2901cb0ef41Sopenharmony_ci    try { fs.unlinkSync(fn); } catch {
2911cb0ef41Sopenharmony_ci      // Continue regardless of error.
2921cb0ef41Sopenharmony_ci    }
2931cb0ef41Sopenharmony_ci    const b = path.basename(t[1]);
2941cb0ef41Sopenharmony_ci    const type = (b === 'root.js' ? 'file' : 'dir');
2951cb0ef41Sopenharmony_ci    console.log('fs.symlinkSync(%j, %j, %j)', t[1], fn, type);
2961cb0ef41Sopenharmony_ci    fs.symlinkSync(t[1], fn, 'file');
2971cb0ef41Sopenharmony_ci    unlink.push(fn);
2981cb0ef41Sopenharmony_ci  });
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  const origcwd = process.cwd();
3011cb0ef41Sopenharmony_ci  process.chdir(entrydir);
3021cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(entry), path.resolve(expected));
3031cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
3041cb0ef41Sopenharmony_ci    process.chdir(origcwd);
3051cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
3061cb0ef41Sopenharmony_ci    return true;
3071cb0ef41Sopenharmony_ci  });
3081cb0ef41Sopenharmony_ci}
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_cifunction test_deep_symlink_mix(realpath, realpathSync, callback) {
3111cb0ef41Sopenharmony_ci  console.log('test_deep_symlink_mix');
3121cb0ef41Sopenharmony_ci  if (common.isWindows) {
3131cb0ef41Sopenharmony_ci    // This one is a mix of files and directories, and it's quite tricky
3141cb0ef41Sopenharmony_ci    // to get the file/dir links sorted out correctly.
3151cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
3161cb0ef41Sopenharmony_ci    return callback();
3171cb0ef41Sopenharmony_ci  }
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci  // /tmp/node-test-realpath-f1 -> $tmpDir/node-test-realpath-d1/foo
3201cb0ef41Sopenharmony_ci  // /tmp/node-test-realpath-d1 -> $tmpDir/node-test-realpath-d2
3211cb0ef41Sopenharmony_ci  // /tmp/node-test-realpath-d2/foo -> $tmpDir/node-test-realpath-f2
3221cb0ef41Sopenharmony_ci  // /tmp/node-test-realpath-f2
3231cb0ef41Sopenharmony_ci  //   -> $tmpDir/targets/nested-index/one/realpath-c
3241cb0ef41Sopenharmony_ci  // $tmpDir/targets/nested-index/one/realpath-c
3251cb0ef41Sopenharmony_ci  //   -> $tmpDir/targets/nested-index/two/realpath-c
3261cb0ef41Sopenharmony_ci  // $tmpDir/targets/nested-index/two/realpath-c -> $tmpDir/cycles/root.js
3271cb0ef41Sopenharmony_ci  // $tmpDir/targets/cycles/root.js (hard)
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  const entry = tmp('node-test-realpath-f1');
3301cb0ef41Sopenharmony_ci  try { fs.unlinkSync(tmp('node-test-realpath-d2/foo')); } catch {
3311cb0ef41Sopenharmony_ci    // Continue regardless of error.
3321cb0ef41Sopenharmony_ci  }
3331cb0ef41Sopenharmony_ci  try { fs.rmdirSync(tmp('node-test-realpath-d2')); } catch {
3341cb0ef41Sopenharmony_ci    // Continue regardless of error.
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci  fs.mkdirSync(tmp('node-test-realpath-d2'), 0o700);
3371cb0ef41Sopenharmony_ci  try {
3381cb0ef41Sopenharmony_ci    [
3391cb0ef41Sopenharmony_ci      [entry, `${tmpDir}/node-test-realpath-d1/foo`],
3401cb0ef41Sopenharmony_ci      [tmp('node-test-realpath-d1'),
3411cb0ef41Sopenharmony_ci       `${tmpDir}/node-test-realpath-d2`],
3421cb0ef41Sopenharmony_ci      [tmp('node-test-realpath-d2/foo'), '../node-test-realpath-f2'],
3431cb0ef41Sopenharmony_ci      [tmp('node-test-realpath-f2'),
3441cb0ef41Sopenharmony_ci       `${targetsAbsDir}/nested-index/one/realpath-c`],
3451cb0ef41Sopenharmony_ci      [`${targetsAbsDir}/nested-index/one/realpath-c`,
3461cb0ef41Sopenharmony_ci       `${targetsAbsDir}/nested-index/two/realpath-c`],
3471cb0ef41Sopenharmony_ci      [`${targetsAbsDir}/nested-index/two/realpath-c`,
3481cb0ef41Sopenharmony_ci       `${tmpDir}/cycles/root.js`],
3491cb0ef41Sopenharmony_ci    ].forEach(function(t) {
3501cb0ef41Sopenharmony_ci      try { fs.unlinkSync(t[0]); } catch {
3511cb0ef41Sopenharmony_ci        // Continue regardless of error.
3521cb0ef41Sopenharmony_ci      }
3531cb0ef41Sopenharmony_ci      fs.symlinkSync(t[1], t[0]);
3541cb0ef41Sopenharmony_ci      unlink.push(t[0]);
3551cb0ef41Sopenharmony_ci    });
3561cb0ef41Sopenharmony_ci  } finally {
3571cb0ef41Sopenharmony_ci    unlink.push(tmp('node-test-realpath-d2'));
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci  const expected = `${tmpAbsDir}/cycles/root.js`;
3601cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(entry), path.resolve(expected));
3611cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
3621cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
3631cb0ef41Sopenharmony_ci    return true;
3641cb0ef41Sopenharmony_ci  });
3651cb0ef41Sopenharmony_ci}
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_cifunction test_non_symlinks(realpath, realpathSync, callback) {
3681cb0ef41Sopenharmony_ci  console.log('test_non_symlinks');
3691cb0ef41Sopenharmony_ci  const entrydir = path.dirname(tmpAbsDir);
3701cb0ef41Sopenharmony_ci  const entry = `${tmpAbsDir.substr(entrydir.length + 1)}/cycles/root.js`;
3711cb0ef41Sopenharmony_ci  const expected = `${tmpAbsDir}/cycles/root.js`;
3721cb0ef41Sopenharmony_ci  const origcwd = process.cwd();
3731cb0ef41Sopenharmony_ci  process.chdir(entrydir);
3741cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(entry), path.resolve(expected));
3751cb0ef41Sopenharmony_ci  asynctest(realpath, [entry], callback, function(err, result) {
3761cb0ef41Sopenharmony_ci    process.chdir(origcwd);
3771cb0ef41Sopenharmony_ci    assertEqualPath(result, path.resolve(expected));
3781cb0ef41Sopenharmony_ci    return true;
3791cb0ef41Sopenharmony_ci  });
3801cb0ef41Sopenharmony_ci}
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ciconst upone = path.join(process.cwd(), '..');
3831cb0ef41Sopenharmony_cifunction test_escape_cwd(realpath, realpathSync, cb) {
3841cb0ef41Sopenharmony_ci  console.log('test_escape_cwd');
3851cb0ef41Sopenharmony_ci  asynctest(realpath, ['..'], cb, function(er, uponeActual) {
3861cb0ef41Sopenharmony_ci    assertEqualPath(
3871cb0ef41Sopenharmony_ci      upone, uponeActual,
3881cb0ef41Sopenharmony_ci      `realpath("..") expected: ${path.resolve(upone)} actual:${uponeActual}`);
3891cb0ef41Sopenharmony_ci  });
3901cb0ef41Sopenharmony_ci}
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_cifunction test_upone_actual(realpath, realpathSync, cb) {
3931cb0ef41Sopenharmony_ci  console.log('test_upone_actual');
3941cb0ef41Sopenharmony_ci  const uponeActual = realpathSync('..');
3951cb0ef41Sopenharmony_ci  assertEqualPath(upone, uponeActual);
3961cb0ef41Sopenharmony_ci  cb();
3971cb0ef41Sopenharmony_ci}
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci// Going up with .. multiple times
4001cb0ef41Sopenharmony_ci// .
4011cb0ef41Sopenharmony_ci// `-- a/
4021cb0ef41Sopenharmony_ci//     |-- b/
4031cb0ef41Sopenharmony_ci//     |   `-- e -> ..
4041cb0ef41Sopenharmony_ci//     `-- d -> ..
4051cb0ef41Sopenharmony_ci// realpath(a/b/e/d/a/b/e/d/a) ==> a
4061cb0ef41Sopenharmony_cifunction test_up_multiple(realpath, realpathSync, cb) {
4071cb0ef41Sopenharmony_ci  console.error('test_up_multiple');
4081cb0ef41Sopenharmony_ci  if (skipSymlinks) {
4091cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
4101cb0ef41Sopenharmony_ci    return cb();
4111cb0ef41Sopenharmony_ci  }
4121cb0ef41Sopenharmony_ci  const tmpdir = require('../common/tmpdir');
4131cb0ef41Sopenharmony_ci  tmpdir.refresh();
4141cb0ef41Sopenharmony_ci  fs.mkdirSync(tmp('a'), 0o755);
4151cb0ef41Sopenharmony_ci  fs.mkdirSync(tmp('a/b'), 0o755);
4161cb0ef41Sopenharmony_ci  fs.symlinkSync('..', tmp('a/d'), 'dir');
4171cb0ef41Sopenharmony_ci  unlink.push(tmp('a/d'));
4181cb0ef41Sopenharmony_ci  fs.symlinkSync('..', tmp('a/b/e'), 'dir');
4191cb0ef41Sopenharmony_ci  unlink.push(tmp('a/b/e'));
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci  const abedabed = tmp('abedabed'.split('').join('/'));
4221cb0ef41Sopenharmony_ci  const abedabed_real = tmp('');
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_ci  const abedabeda = tmp('abedabeda'.split('').join('/'));
4251cb0ef41Sopenharmony_ci  const abedabeda_real = tmp('a');
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(abedabeda), abedabeda_real);
4281cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(abedabed), abedabed_real);
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci  realpath(abedabeda, function(er, real) {
4311cb0ef41Sopenharmony_ci    assert.ifError(er);
4321cb0ef41Sopenharmony_ci    assertEqualPath(abedabeda_real, real);
4331cb0ef41Sopenharmony_ci    realpath(abedabed, function(er, real) {
4341cb0ef41Sopenharmony_ci      assert.ifError(er);
4351cb0ef41Sopenharmony_ci      assertEqualPath(abedabed_real, real);
4361cb0ef41Sopenharmony_ci      cb();
4371cb0ef41Sopenharmony_ci    });
4381cb0ef41Sopenharmony_ci  });
4391cb0ef41Sopenharmony_ci}
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci// Going up with .. multiple times with options = null
4431cb0ef41Sopenharmony_ci// .
4441cb0ef41Sopenharmony_ci// `-- a/
4451cb0ef41Sopenharmony_ci//     |-- b/
4461cb0ef41Sopenharmony_ci//     |   `-- e -> ..
4471cb0ef41Sopenharmony_ci//     `-- d -> ..
4481cb0ef41Sopenharmony_ci// realpath(a/b/e/d/a/b/e/d/a) ==> a
4491cb0ef41Sopenharmony_cifunction test_up_multiple_with_null_options(realpath, realpathSync, cb) {
4501cb0ef41Sopenharmony_ci  console.error('test_up_multiple');
4511cb0ef41Sopenharmony_ci  if (skipSymlinks) {
4521cb0ef41Sopenharmony_ci    common.printSkipMessage('symlink test (no privs)');
4531cb0ef41Sopenharmony_ci    return cb();
4541cb0ef41Sopenharmony_ci  }
4551cb0ef41Sopenharmony_ci  const tmpdir = require('../common/tmpdir');
4561cb0ef41Sopenharmony_ci  tmpdir.refresh();
4571cb0ef41Sopenharmony_ci  fs.mkdirSync(tmp('a'), 0o755);
4581cb0ef41Sopenharmony_ci  fs.mkdirSync(tmp('a/b'), 0o755);
4591cb0ef41Sopenharmony_ci  fs.symlinkSync('..', tmp('a/d'), 'dir');
4601cb0ef41Sopenharmony_ci  unlink.push(tmp('a/d'));
4611cb0ef41Sopenharmony_ci  fs.symlinkSync('..', tmp('a/b/e'), 'dir');
4621cb0ef41Sopenharmony_ci  unlink.push(tmp('a/b/e'));
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  const abedabed = tmp('abedabed'.split('').join('/'));
4651cb0ef41Sopenharmony_ci  const abedabed_real = tmp('');
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_ci  const abedabeda = tmp('abedabeda'.split('').join('/'));
4681cb0ef41Sopenharmony_ci  const abedabeda_real = tmp('a');
4691cb0ef41Sopenharmony_ci
4701cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(abedabeda), abedabeda_real);
4711cb0ef41Sopenharmony_ci  assertEqualPath(realpathSync(abedabed), abedabed_real);
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  realpath(abedabeda, null, function(er, real) {
4741cb0ef41Sopenharmony_ci    assert.ifError(er);
4751cb0ef41Sopenharmony_ci    assertEqualPath(abedabeda_real, real);
4761cb0ef41Sopenharmony_ci    realpath(abedabed, null, function(er, real) {
4771cb0ef41Sopenharmony_ci      assert.ifError(er);
4781cb0ef41Sopenharmony_ci      assertEqualPath(abedabed_real, real);
4791cb0ef41Sopenharmony_ci      cb();
4801cb0ef41Sopenharmony_ci    });
4811cb0ef41Sopenharmony_ci  });
4821cb0ef41Sopenharmony_ci}
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci// Absolute symlinks with children.
4851cb0ef41Sopenharmony_ci// .
4861cb0ef41Sopenharmony_ci// `-- a/
4871cb0ef41Sopenharmony_ci//     |-- b/
4881cb0ef41Sopenharmony_ci//     |   `-- c/
4891cb0ef41Sopenharmony_ci//     |       `-- x.txt
4901cb0ef41Sopenharmony_ci//     `-- link -> /tmp/node-test-realpath-abs-kids/a/b/
4911cb0ef41Sopenharmony_ci// realpath(root+'/a/link/c/x.txt') ==> root+'/a/b/c/x.txt'
4921cb0ef41Sopenharmony_cifunction test_abs_with_kids(realpath, realpathSync, cb) {
4931cb0ef41Sopenharmony_ci  console.log('test_abs_with_kids');
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  // This one should still run, even if skipSymlinks is set,
4961cb0ef41Sopenharmony_ci  // because it uses a junction.
4971cb0ef41Sopenharmony_ci  const type = skipSymlinks ? 'junction' : 'dir';
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci  console.log('using type=%s', type);
5001cb0ef41Sopenharmony_ci
5011cb0ef41Sopenharmony_ci  const root = `${tmpAbsDir}/node-test-realpath-abs-kids`;
5021cb0ef41Sopenharmony_ci  function cleanup() {
5031cb0ef41Sopenharmony_ci    ['/a/b/c/x.txt',
5041cb0ef41Sopenharmony_ci     '/a/link',
5051cb0ef41Sopenharmony_ci    ].forEach(function(file) {
5061cb0ef41Sopenharmony_ci      try { fs.unlinkSync(root + file); } catch {
5071cb0ef41Sopenharmony_ci        // Continue regardless of error.
5081cb0ef41Sopenharmony_ci      }
5091cb0ef41Sopenharmony_ci    });
5101cb0ef41Sopenharmony_ci    ['/a/b/c',
5111cb0ef41Sopenharmony_ci     '/a/b',
5121cb0ef41Sopenharmony_ci     '/a',
5131cb0ef41Sopenharmony_ci     '',
5141cb0ef41Sopenharmony_ci    ].forEach(function(folder) {
5151cb0ef41Sopenharmony_ci      try { fs.rmdirSync(root + folder); } catch {
5161cb0ef41Sopenharmony_ci        // Continue regardless of error.
5171cb0ef41Sopenharmony_ci      }
5181cb0ef41Sopenharmony_ci    });
5191cb0ef41Sopenharmony_ci  }
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  function setup() {
5221cb0ef41Sopenharmony_ci    cleanup();
5231cb0ef41Sopenharmony_ci    ['',
5241cb0ef41Sopenharmony_ci     '/a',
5251cb0ef41Sopenharmony_ci     '/a/b',
5261cb0ef41Sopenharmony_ci     '/a/b/c',
5271cb0ef41Sopenharmony_ci    ].forEach(function(folder) {
5281cb0ef41Sopenharmony_ci      console.log(`mkdir ${root}${folder}`);
5291cb0ef41Sopenharmony_ci      fs.mkdirSync(root + folder, 0o700);
5301cb0ef41Sopenharmony_ci    });
5311cb0ef41Sopenharmony_ci    fs.writeFileSync(`${root}/a/b/c/x.txt`, 'foo');
5321cb0ef41Sopenharmony_ci    fs.symlinkSync(`${root}/a/b`, `${root}/a/link`, type);
5331cb0ef41Sopenharmony_ci  }
5341cb0ef41Sopenharmony_ci  setup();
5351cb0ef41Sopenharmony_ci  const linkPath = `${root}/a/link/c/x.txt`;
5361cb0ef41Sopenharmony_ci  const expectPath = `${root}/a/b/c/x.txt`;
5371cb0ef41Sopenharmony_ci  const actual = realpathSync(linkPath);
5381cb0ef41Sopenharmony_ci  // console.log({link:linkPath,expect:expectPath,actual:actual},'sync');
5391cb0ef41Sopenharmony_ci  assertEqualPath(actual, path.resolve(expectPath));
5401cb0ef41Sopenharmony_ci  asynctest(realpath, [linkPath], cb, function(er, actual) {
5411cb0ef41Sopenharmony_ci    // console.log({link:linkPath,expect:expectPath,actual:actual},'async');
5421cb0ef41Sopenharmony_ci    assertEqualPath(actual, path.resolve(expectPath));
5431cb0ef41Sopenharmony_ci    cleanup();
5441cb0ef41Sopenharmony_ci  });
5451cb0ef41Sopenharmony_ci}
5461cb0ef41Sopenharmony_ci
5471cb0ef41Sopenharmony_cifunction test_root(realpath, realpathSync, cb) {
5481cb0ef41Sopenharmony_ci  assertEqualPath(root, realpathSync('/'));
5491cb0ef41Sopenharmony_ci  realpath('/', function(err, result) {
5501cb0ef41Sopenharmony_ci    assert.ifError(err);
5511cb0ef41Sopenharmony_ci    assertEqualPath(root, result);
5521cb0ef41Sopenharmony_ci    cb();
5531cb0ef41Sopenharmony_ci  });
5541cb0ef41Sopenharmony_ci}
5551cb0ef41Sopenharmony_ci
5561cb0ef41Sopenharmony_cifunction test_root_with_null_options(realpath, realpathSync, cb) {
5571cb0ef41Sopenharmony_ci  realpath('/', null, function(err, result) {
5581cb0ef41Sopenharmony_ci    assert.ifError(err);
5591cb0ef41Sopenharmony_ci    assertEqualPath(root, result);
5601cb0ef41Sopenharmony_ci    cb();
5611cb0ef41Sopenharmony_ci  });
5621cb0ef41Sopenharmony_ci}
5631cb0ef41Sopenharmony_ci
5641cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------
5651cb0ef41Sopenharmony_ci
5661cb0ef41Sopenharmony_ciconst tests = [
5671cb0ef41Sopenharmony_ci  test_simple_error_callback,
5681cb0ef41Sopenharmony_ci  test_simple_error_cb_with_null_options,
5691cb0ef41Sopenharmony_ci  test_simple_relative_symlink,
5701cb0ef41Sopenharmony_ci  test_simple_absolute_symlink,
5711cb0ef41Sopenharmony_ci  test_deep_relative_file_symlink,
5721cb0ef41Sopenharmony_ci  test_deep_relative_dir_symlink,
5731cb0ef41Sopenharmony_ci  test_cyclic_link_protection,
5741cb0ef41Sopenharmony_ci  test_cyclic_link_overprotection,
5751cb0ef41Sopenharmony_ci  test_relative_input_cwd,
5761cb0ef41Sopenharmony_ci  test_deep_symlink_mix,
5771cb0ef41Sopenharmony_ci  test_non_symlinks,
5781cb0ef41Sopenharmony_ci  test_escape_cwd,
5791cb0ef41Sopenharmony_ci  test_upone_actual,
5801cb0ef41Sopenharmony_ci  test_abs_with_kids,
5811cb0ef41Sopenharmony_ci  test_up_multiple,
5821cb0ef41Sopenharmony_ci  test_up_multiple_with_null_options,
5831cb0ef41Sopenharmony_ci  test_root,
5841cb0ef41Sopenharmony_ci  test_root_with_null_options,
5851cb0ef41Sopenharmony_ci];
5861cb0ef41Sopenharmony_ciconst numtests = tests.length;
5871cb0ef41Sopenharmony_cilet testsRun = 0;
5881cb0ef41Sopenharmony_cifunction runNextTest(err) {
5891cb0ef41Sopenharmony_ci  assert.ifError(err);
5901cb0ef41Sopenharmony_ci  const test = tests.shift();
5911cb0ef41Sopenharmony_ci  if (!test) {
5921cb0ef41Sopenharmony_ci    return console.log(`${numtests} subtests completed OK for fs.realpath`);
5931cb0ef41Sopenharmony_ci  }
5941cb0ef41Sopenharmony_ci  testsRun++;
5951cb0ef41Sopenharmony_ci  test(fs.realpath, fs.realpathSync, common.mustSucceed(() => {
5961cb0ef41Sopenharmony_ci    testsRun++;
5971cb0ef41Sopenharmony_ci    test(fs.realpath.native,
5981cb0ef41Sopenharmony_ci         fs.realpathSync.native,
5991cb0ef41Sopenharmony_ci         common.mustCall(runNextTest));
6001cb0ef41Sopenharmony_ci  }));
6011cb0ef41Sopenharmony_ci}
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_cifunction runTest() {
6041cb0ef41Sopenharmony_ci  const tmpDirs = ['cycles', 'cycles/folder'];
6051cb0ef41Sopenharmony_ci  tmpDirs.forEach(function(t) {
6061cb0ef41Sopenharmony_ci    t = tmp(t);
6071cb0ef41Sopenharmony_ci    fs.mkdirSync(t, 0o700);
6081cb0ef41Sopenharmony_ci  });
6091cb0ef41Sopenharmony_ci  fs.writeFileSync(tmp('cycles/root.js'), "console.error('roooot!');");
6101cb0ef41Sopenharmony_ci  console.error('start tests');
6111cb0ef41Sopenharmony_ci  runNextTest();
6121cb0ef41Sopenharmony_ci}
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci
6151cb0ef41Sopenharmony_ciprocess.on('exit', function() {
6161cb0ef41Sopenharmony_ci  assert.strictEqual(2 * numtests, testsRun);
6171cb0ef41Sopenharmony_ci  assert.strictEqual(async_completed, async_expected);
6181cb0ef41Sopenharmony_ci});
619