Browse Source

Expose posix realpath on windows as well

v0.9.1-release
isaacs 13 years ago
parent
commit
6332a4cf00
  1. 326
      lib/fs.js

326
lib/fs.js

@ -893,222 +893,184 @@ fs.unwatchFile = function(filename) {
var normalize = pathModule.normalize;
if (isWindows) {
// Node doesn't support symlinks / lstat on windows. Hence realpath is just
// the same as path.resolve that fails if the path doesn't exists.
// windows version
fs.realpathSync = function realpathSync(p, cache) {
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
fs.realpath = function(p, cache, cb) {
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);
});
};
// Regexp that finds the next partion of a (partial) path
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
var nextPartRe = /(.*?)(?:[\/]+|$)/g;
fs.realpathSync = function realpathSync(p, cache) {
// make p is absolute
p = pathModule.resolve(p);
} else /* posix */ {
// Regexp that finds the next partion of a (partial) path
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
var nextPartRe = /(.*?)(?:[\/]+|$)/g;
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
}
// posix version
fs.realpathSync = function realpathSync(p, cache) {
// make p is absolute
p = pathModule.resolve(p);
var original = p,
seenLinks = {},
knownHard = {};
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
// 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
// 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 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
// 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)) {
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;
}
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;
}
// 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;
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
}
return p;
};
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);
fs.realpath = function realpath(p, cache, cb) {
if (typeof cb !== 'function') {
cb = cache;
cache = null;
}
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[p]);
}
// make p is absolute
p = pathModule.resolve(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);
}
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cb(null, cache[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);
}
var original = p,
seenLinks = {},
knownHard = {};
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// known symbolic link. no need to stat again.
return gotResolvedLink(cache[base]);
}
// 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;
return fs.lstat(base, gotStat);
// 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);
}
function gotStat(err, stat) {
if (err) return cb(err);
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// known symbolic link. no need to stat again.
return gotResolvedLink(cache[base]);
}
// 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);
}
return fs.lstat(base, gotStat);
}
// 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);
function gotStat(err, stat) {
if (err) return cb(err);
fs.readlink(base, function(err, target) {
gotTarget(err, seenLinks[id] = target);
});
});
// 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);
}
function gotTarget(err, target, base) {
// 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);
var resolvedLink = pathModule.resolve(previous, target);
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink);
}
fs.readlink(base, function(err, target) {
gotTarget(err, seenLinks[id] = target);
});
});
}
function gotResolvedLink(resolvedLink) {
function gotTarget(err, target, base) {
if (err) return cb(err);
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
pos = 0;
previous = base = current = '';
var resolvedLink = pathModule.resolve(previous, target);
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink);
}
return process.nextTick(LOOP);
}
};
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;

Loading…
Cancel
Save