diff --git a/lib/fs.js b/lib/fs.js index 7b50412ea7..8a028bf799 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -43,6 +43,7 @@ const internalUtil = require('internal/util'); const assertEncoding = internalFS.assertEncoding; const stringToFlags = internalFS.stringToFlags; const getPathFromURL = internalURL.getPathFromURL; +const { StorageObject } = require('internal/querystring'); Object.defineProperty(exports, 'constants', { configurable: false, @@ -1514,10 +1515,23 @@ fs.unwatchFile = function(filename, listener) { }; -// Regex to find the device root, including trailing slash. E.g. 'c:\\'. -const splitRootRe = isWindows ? - /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/ : - /^[/]*/; +var splitRoot; +if (isWindows) { + // Regex to find the device root on Windows (e.g. 'c:\\'), including trailing + // slash. + const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/; + splitRoot = function splitRoot(str) { + return splitRootRe.exec(str)[0]; + }; +} else { + splitRoot = function splitRoot(str) { + for (var i = 0; i < str.length; ++i) { + if (str.charCodeAt(i) !== 47/*'/'*/) + return str.slice(0, i); + } + return str; + }; +} function encodeRealpathResult(result, options) { if (!options || !options.encoding || options.encoding === 'utf8') @@ -1545,11 +1559,17 @@ if (isWindows) { nextPart = function nextPart(p, i) { return p.indexOf('/', i); }; } +const emptyObj = new StorageObject(); fs.realpathSync = function realpathSync(p, options) { - options = getOptions(options, {}); - handleError((p = getPathFromURL(p))); - if (typeof p !== 'string') - p += ''; + if (!options) + options = emptyObj; + else + options = getOptions(options, emptyObj); + if (typeof p !== 'string') { + handleError((p = getPathFromURL(p))); + if (typeof p !== 'string') + p += ''; + } nullCheck(p); p = pathModule.resolve(p); @@ -1559,8 +1579,8 @@ fs.realpathSync = function realpathSync(p, options) { return maybeCachedResult; } - const seenLinks = {}; - const knownHard = {}; + const seenLinks = new StorageObject(); + const knownHard = new StorageObject(); const original = p; // current character position in p @@ -1573,10 +1593,8 @@ fs.realpathSync = function realpathSync(p, options) { var previous; // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; + current = base = splitRoot(p); + pos = current.length; // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) { @@ -1615,7 +1633,8 @@ fs.realpathSync = function realpathSync(p, options) { // Use stats array directly to avoid creating an fs.Stats instance just // for our internal use. - binding.lstat(pathModule._makeLong(base)); + var baseLong = pathModule._makeLong(base); + binding.lstat(baseLong); if ((statValues[1/*mode*/] & S_IFMT) !== S_IFLNK) { knownHard[base] = true; @@ -1631,13 +1650,13 @@ fs.realpathSync = function realpathSync(p, options) { var dev = statValues[0/*dev*/].toString(32); var ino = statValues[7/*ino*/].toString(32); id = `${dev}:${ino}`; - if (seenLinks.hasOwnProperty(id)) { + if (seenLinks[id]) { linkTarget = seenLinks[id]; } } if (linkTarget === null) { - binding.stat(pathModule._makeLong(base)); - linkTarget = binding.readlink(pathModule._makeLong(base)); + binding.stat(baseLong); + linkTarget = binding.readlink(baseLong); } resolvedLink = pathModule.resolve(previous, linkTarget); @@ -1649,10 +1668,8 @@ fs.realpathSync = function realpathSync(p, options) { p = pathModule.resolve(resolvedLink, p.slice(pos)); // Skip over roots - m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; + current = base = splitRoot(p); + pos = current.length; // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) { @@ -1668,17 +1685,22 @@ fs.realpathSync = function realpathSync(p, options) { fs.realpath = function realpath(p, options, callback) { callback = maybeCallback(typeof options === 'function' ? options : callback); - options = getOptions(options, {}); - if (handleError((p = getPathFromURL(p)), callback)) - return; - if (typeof p !== 'string') - p += ''; + if (!options) + options = emptyObj; + else + options = getOptions(options, emptyObj); + if (typeof p !== 'string') { + if (handleError((p = getPathFromURL(p)), callback)) + return; + if (typeof p !== 'string') + p += ''; + } if (!nullCheck(p, callback)) return; p = pathModule.resolve(p); - const seenLinks = {}; - const knownHard = {}; + const seenLinks = new StorageObject(); + const knownHard = new StorageObject(); // current character position in p var pos; @@ -1689,11 +1711,8 @@ fs.realpath = function realpath(p, options, callback) { // the partial path scanned in the previous round, with slash var previous; - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; + current = base = splitRoot(p); + pos = current.length; // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) { @@ -1756,7 +1775,7 @@ fs.realpath = function realpath(p, options, callback) { var dev = statValues[0/*ino*/].toString(32); var ino = statValues[7/*ino*/].toString(32); id = `${dev}:${ino}`; - if (seenLinks.hasOwnProperty(id)) { + if (seenLinks[id]) { return gotTarget(null, seenLinks[id], base); } } @@ -1780,11 +1799,8 @@ fs.realpath = function realpath(p, options, callback) { function gotResolvedLink(resolvedLink) { // resolve the link, then start over p = pathModule.resolve(resolvedLink, p.slice(pos)); - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; + current = base = splitRoot(p); + pos = current.length; // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard[base]) {