Fix fs.realpath to work on Windows

1. Make the isRoot check valid
2. Don't cache results based on dev/ino, since those are alwasy 0 on
windows.
pull/24503/head
isaacs 2012-06-08 16:49:03 -07:00
parent 6332a4cf00
commit 424bca15c8
1 changed files with 44 additions and 11 deletions

View File

@ -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);
});
});
}