diff --git a/test/README.md b/test/README.md index a290835cb2d4ac..94f77eda5148f2 100644 --- a/test/README.md +++ b/test/README.md @@ -163,6 +163,13 @@ A stream to push an array into a REPL Blocks for `time` amount of time. +### canCreateSymLink +API to indicate whether the current running process can create +symlinks. On Windows, this returns false if the process running +doesn't have privileges to create symlinks (specifically +[SeCreateSymbolicLinkPrivilege](https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx)). +On non-Windows platforms, this currently returns true. + ### ddCommand(filename, kilobytes) * return [<Object>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) diff --git a/test/common.js b/test/common.js index 0306cc2ecacbe6..151573693167d9 100644 --- a/test/common.js +++ b/test/common.js @@ -8,6 +8,7 @@ const child_process = require('child_process'); const stream = require('stream'); const util = require('util'); const Timer = process.binding('timer_wrap').Timer; +const execSync = require('child_process').execSync; const testRoot = process.env.NODE_TEST_DIR ? fs.realpathSync(process.env.NODE_TEST_DIR) : __dirname; @@ -438,6 +439,34 @@ exports.fileExists = function(pathname) { } }; +exports.canCreateSymLink = function() { + // On Windows, creating symlinks requires admin privileges. + // We'll only try to run symlink test if we have enough privileges. + // On other platforms, creating symlinks shouldn't need admin privileges + if (exports.isWindows) { + // whoami.exe needs to be the one from System32 + // If unix tools are in the path, they can shadow the one we want, + // so use the full path while executing whoami + const whoamiPath = path.join(process.env['SystemRoot'], + 'System32', 'whoami.exe'); + + let err = false; + let output = ''; + + try { + output = execSync(whoamiPath + ' /priv', { timout: 1000 }); + } catch (e) { + err = true; + } finally { + if (err || !output.includes('SeCreateSymbolicLinkPrivilege')) { + return false; + } + } + } + + return true; +}; + function fail(msg) { assert.fail(null, null, msg); } diff --git a/test/parallel/test-fs-options-immutable.js b/test/parallel/test-fs-options-immutable.js index 47796a94a5e79e..185d14c4721d74 100644 --- a/test/parallel/test-fs-options-immutable.js +++ b/test/parallel/test-fs-options-immutable.js @@ -29,7 +29,7 @@ common.refreshTmpDir(); assert.doesNotThrow(() => fs.readdirSync(__dirname, options)); } -{ +if (common.canCreateSymLink()) { const sourceFile = path.resolve(common.tmpDir, 'test-readlink'); const linkFile = path.resolve(common.tmpDir, 'test-readlink-link'); diff --git a/test/parallel/test-fs-symlink.js b/test/parallel/test-fs-symlink.js index ab52ba22923f3d..69b78dad3d2797 100644 --- a/test/parallel/test-fs-symlink.js +++ b/test/parallel/test-fs-symlink.js @@ -3,20 +3,13 @@ const common = require('../common'); const assert = require('assert'); const path = require('path'); const fs = require('fs'); -const exec = require('child_process').exec; var linkTime; var fileTime; -if (common.isWindows) { - // On Windows, creating symlinks requires admin privileges. - // We'll only try to run symlink test if we have enough privileges. - exec('whoami /priv', function(err, o) { - if (err || !o.includes('SeCreateSymbolicLinkPrivilege')) { - common.skip('insufficient privileges'); - return; - } - }); +if (!common.canCreateSymLink()) { + common.skip('insufficient privileges'); + return; } common.refreshTmpDir();