Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Expose posix realpath on windows as well
  • Loading branch information
isaacs committed Jun 9, 2012
1 parent 60b45dc commit 6332a4c
Showing 1 changed file with 144 additions and 182 deletions.
326 changes: 144 additions & 182 deletions lib/fs.js
Expand Up @@ -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;
Expand Down

0 comments on commit 6332a4c

Please sign in to comment.