From 89048c2661a4ab100bb0abdfbbac41a9f5fcf2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 1 Nov 2017 23:45:34 +0800 Subject: [PATCH] fs: more realpath*() optimizations Including: * Avoid regexp on non-Windows platforms when parsing the root of a path Backport-PR-URL: https://github.com/nodejs/node/pull/11665 --- lib/fs.js | 64 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index a146bf505d0f10..fdcbf85e991861 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1622,10 +1622,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, err) { if (!options || !options.encoding || options.encoding === 'utf8' || err) @@ -1688,17 +1701,15 @@ fs.realpathSync = function realpathSync(p, options) { // the partial path scanned in the previous round, with slash var previous; - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; + // Skip over roots + current = base = splitRoot(p); + pos = current.length; - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { binding.lstat(pathModule._makeLong(base)); - knownHard[base] = true; - } + knownHard[base] = true; + } // walk down the path, swapping out linked path parts for their real // values @@ -1731,7 +1742,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; @@ -1752,8 +1764,8 @@ fs.realpathSync = function realpathSync(p, options) { } } 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); @@ -1765,10 +1777,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]) { @@ -1815,11 +1825,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]) { @@ -1906,11 +1913,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]) {