Expose posix realpath on windows as well

This commit is contained in:
isaacs 2012-06-08 15:26:04 -07:00
parent 60b45dcbb6
commit 6332a4cf00

346
lib/fs.js
View File

@ -893,222 +893,184 @@ fs.unwatchFile = function(filename) {
var normalize = pathModule.normalize; var normalize = pathModule.normalize;
if (isWindows) { // Regexp that finds the next partion of a (partial) path
// Node doesn't support symlinks / lstat on windows. Hence realpath is just // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
// the same as path.resolve that fails if the path doesn't exists. var nextPartRe = /(.*?)(?:[\/]+|$)/g;
// windows version fs.realpathSync = function realpathSync(p, cache) {
fs.realpathSync = function realpathSync(p, cache) { // make p is absolute
p = pathModule.resolve(p); p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
}
fs.statSync(p);
if (cache) cache[p] = p;
return p;
};
// windows version if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
fs.realpath = function(p, cache, cb) { return cache[p];
if (typeof cb !== 'function') { }
cb = cache;
cache = null;
}
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
}
fs.stat(p, function(err) {
if (err) return cb(err);
if (cache) cache[p] = p;
cb(null, p);
});
};
var original = p,
seenLinks = {},
knownHard = {};
} else /* posix */ { // current character position in p
var pos = 0;
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
// the partial path scanned in the previous round, with slash
var previous = '';
// Regexp that finds the next partion of a (partial) path // walk down the path, swapping out linked pathparts for their real
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] // values
var nextPartRe = /(.*?)(?:[\/]+|$)/g; // NB: p.length changes.
while (pos < p.length) {
// find the next part
nextPartRe.lastIndex = pos;
var result = nextPartRe.exec(p);
previous = current;
current += result[0];
base = previous + result[1];
pos = nextPartRe.lastIndex;
// posix version // continue if not a symlink, or if root
fs.realpathSync = function realpathSync(p, cache) { if (!base || knownHard[base] || (cache && cache[base] === base)) {
// make p is absolute continue;
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
} }
var original = p, var resolvedLink;
seenLinks = {}, if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
knownHard = {}; // some known symbolic link. no need to stat again.
resolvedLink = cache[base];
// current character position in p } else {
var pos = 0; var stat = fs.lstatSync(base);
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
// the partial path scanned in the previous round, with slash
var previous = '';
// walk down the path, swapping out linked pathparts for their real
// values
// NB: p.length changes.
while (pos < p.length) {
// find the next part
nextPartRe.lastIndex = pos;
var result = nextPartRe.exec(p);
previous = current;
current += result[0];
base = previous + result[1];
pos = nextPartRe.lastIndex;
// continue if not a symlink, or if root
if (!base || knownHard[base] || (cache && cache[base] === base)) {
continue;
}
var resolvedLink;
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// some known symbolic link. no need to stat again.
resolvedLink = cache[base];
} else {
var stat = fs.lstatSync(base);
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
if (cache) cache[base] = base;
continue;
}
// read the link if it wasn't read before
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
if (!seenLinks[id]) {
fs.statSync(base);
seenLinks[id] = fs.readlinkSync(base);
resolvedLink = pathModule.resolve(previous, seenLinks[id]);
// track this, if given a cache.
if (cache) cache[base] = resolvedLink;
}
}
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
}
if (cache) cache[original] = p;
return p;
};
// posix version
fs.realpath = function realpath(p, cache, cb) {
if (typeof cb !== 'function') {
cb = cache;
cache = null;
}
// make p is absolute
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
}
var original = p,
seenLinks = {},
knownHard = {};
// current character position in p
var pos = 0;
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
// the partial path scanned in the previous round, with slash
var previous = '';
// walk down the path, swapping out linked pathparts for their real
// values
LOOP();
function LOOP() {
// stop if scanned past end of path
if (pos >= p.length) {
if (cache) cache[original] = p;
return cb(null, p);
}
// find the next part
nextPartRe.lastIndex = pos;
var result = nextPartRe.exec(p);
previous = current;
current += result[0];
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)) {
return process.nextTick(LOOP);
}
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// known symbolic link. no need to stat again.
return gotResolvedLink(cache[base]);
}
return fs.lstat(base, gotStat);
}
function gotStat(err, stat) {
if (err) return cb(err);
// if not a symlink, skip to the next path part
if (!stat.isSymbolicLink()) { if (!stat.isSymbolicLink()) {
knownHard[base] = true; knownHard[base] = true;
if (cache) cache[base] = base; if (cache) cache[base] = base;
return process.nextTick(LOOP); continue;
} }
// stat & read the link if not read before // read the link if it wasn't read before
// call gotTarget as soon as the link target is known
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
if (seenLinks[id]) { if (!seenLinks[id]) {
return gotTarget(null, seenLinks[id], base); fs.statSync(base);
seenLinks[id] = fs.readlinkSync(base);
resolvedLink = pathModule.resolve(previous, seenLinks[id]);
// track this, if given a cache.
if (cache) cache[base] = resolvedLink;
} }
fs.stat(base, function(err) {
if (err) return cb(err);
fs.readlink(base, function(err, target) {
gotTarget(err, seenLinks[id] = target);
});
});
} }
function gotTarget(err, target, base) { // resolve the link, then start over
if (err) return cb(err); p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
}
var resolvedLink = pathModule.resolve(previous, target); if (cache) cache[original] = p;
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink); return p;
};
fs.realpath = function realpath(p, cache, cb) {
if (typeof cb !== 'function') {
cb = cache;
cache = null;
}
// make p is absolute
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
}
var original = p,
seenLinks = {},
knownHard = {};
// current character position in p
var pos = 0;
// the partial path so far, including a trailing slash if any
var current = '';
// the partial path without a trailing slash
var base = '';
// the partial path scanned in the previous round, with slash
var previous = '';
// walk down the path, swapping out linked pathparts for their real
// values
LOOP();
function LOOP() {
// stop if scanned past end of path
if (pos >= p.length) {
if (cache) cache[original] = p;
return cb(null, p);
} }
function gotResolvedLink(resolvedLink) { // find the next part
nextPartRe.lastIndex = pos;
// resolve the link, then start over var result = nextPartRe.exec(p);
p = pathModule.resolve(resolvedLink, p.slice(pos)); previous = current;
pos = 0; current += result[0];
previous = base = current = ''; 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)) {
return process.nextTick(LOOP); return process.nextTick(LOOP);
} }
};
} if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// known symbolic link. no need to stat again.
return gotResolvedLink(cache[base]);
}
return fs.lstat(base, gotStat);
}
function gotStat(err, stat) {
if (err) return cb(err);
// if not a symlink, skip to the next path part
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
if (cache) cache[base] = base;
return process.nextTick(LOOP);
}
// 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);
}
fs.stat(base, function(err) {
if (err) return cb(err);
fs.readlink(base, function(err, target) {
gotTarget(err, seenLinks[id] = target);
});
});
}
function gotTarget(err, target, base) {
if (err) return cb(err);
var resolvedLink = pathModule.resolve(previous, target);
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink);
}
function gotResolvedLink(resolvedLink) {
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
return process.nextTick(LOOP);
}
};
var pool; var pool;