diff --git a/lib/fs.js b/lib/fs.js index 56ca131d296..f0cd903cbc4 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -897,6 +897,11 @@ var normalize = pathModule.normalize; // result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] var nextPartRe = /(.*?)(?:[\/]+|$)/g; +// Regex to split a windows path into three parts: [*, device, slash, +// tail] windows-only +var splitDeviceRe = + /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/; + fs.realpathSync = function realpathSync(p, cache) { // make p is absolute p = pathModule.resolve(p); @@ -931,7 +936,15 @@ fs.realpathSync = function realpathSync(p, cache) { pos = nextPartRe.lastIndex; // continue if not a symlink, or if root - if (!base || knownHard[base] || (cache && cache[base] === base)) { + var isRoot = !base; + if (isWindows) { + // if it doens't have a tail, then it's the root. + var split = base.match(splitDeviceRe); + if (split) { + isRoot = !split[2]; + } + } + if (isRoot || knownHard[base] || (cache && cache[base] === base)) { continue; } @@ -948,13 +961,21 @@ fs.realpathSync = function realpathSync(p, cache) { } // read the link if it wasn't read before - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (!seenLinks[id]) { + // dev/ino always return 0 on windows, so skip the check. + var linkTarget; + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks[id]) { + linkTarget = seenLinks[id]; + } + } + if (!linkTarget) { fs.statSync(base); - seenLinks[id] = fs.readlinkSync(base); - resolvedLink = pathModule.resolve(previous, seenLinks[id]); + linkTarget = fs.readlinkSync(base); + resolvedLink = pathModule.resolve(previous, linkTarget); // track this, if given a cache. if (cache) cache[base] = resolvedLink; + if (!isWindows) seenLinks[id] = linkTarget; } } @@ -1014,8 +1035,16 @@ fs.realpath = function realpath(p, cache, cb) { base = previous + result[1]; pos = nextPartRe.lastIndex; - // continue if known to be hard or if root or in cache already. - if (!base || knownHard[base] || (cache && cache[base] === base)) { + // continue if not a symlink, or if root + var isRoot = !base; + if (isWindows) { + // if it doens't have a tail, then it's the root. + var split = base.match(splitDeviceRe); + if (split) { + isRoot = !split[2]; + } + } + if (isRoot || knownHard[base] || (cache && cache[base] === base)) { return process.nextTick(LOOP); } @@ -1039,15 +1068,19 @@ fs.realpath = function realpath(p, cache, cb) { // stat & read the link if not read before // call gotTarget as soon as the link target is known - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (seenLinks[id]) { - return gotTarget(null, seenLinks[id], base); + // dev/ino always return 0 on windows, so skip the check. + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks[id]) { + return gotTarget(null, seenLinks[id], base); + } } fs.stat(base, function(err) { if (err) return cb(err); fs.readlink(base, function(err, target) { - gotTarget(err, seenLinks[id] = target); + if (!isWindows) seenLinks[id] = target; + gotTarget(err, target); }); }); }