};
// Realpath
-
-var path = require('path');
-var normalize = path.normalize;
-var normalizeArray = path.normalizeArray;
-
-// realpath
// Not using realpath(2) because it's bad.
// See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
-fs.realpathSync = realpathSync;
-fs.realpath = realpath;
-function realpathSync(p) {
- if (p.charAt(0) !== '/') {
- p = path.join(process.cwd(), p);
- }
- p = path.split(p);
- var buf = [];
- var seenLinks = {};
- var knownHard = {};
- // walk down the path, swapping out linked pathparts for their real
- // values, and pushing non-link path bits onto the buffer.
- // then return the buffer.
- // NB: path.length changes.
- for (var i = 0; i < p.length; i++) {
- // skip over empty path parts.
- if (p[i] === '') continue;
-
- var part = path.join.apply(path, buf.concat(p[i]));
-
- if (knownHard[part]) {
- buf.push(p[i]);
- continue;
- }
- var stat = fs.lstatSync(part);
- if (!stat.isSymbolicLink()) {
- // not a symlink. easy.
- knownHard[part] = true;
- buf.push(p[i]);
- continue;
- }
+var path = require('path'),
+ normalize = path.normalize,
+ isWindows = process.platform === 'win32';
+
+if (isWindows) {
+ // Node doesn't support symlinks / lstat on windows. Hence realpatch is just
+ // the same as path.resolve that fails if the path doesn't exists.
+
+ // windows version
+ fs.realpathSync = function realpathSync(p) {
+ var p = path.resolve(p);
+ fs.statSync(p);
+ return p;
+ };
+
+ // windows version
+ fs.realpath = function(p, cb) {
+ var p = path.resolve(p);
+ fs.stat(p, function(err) {
+ if (err) cb(err);
+ cb(null, 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;
+
+ // posix version
+ fs.realpathSync = function realpathSync(p) {
+ // make p is absolute
+ p = path.resolve(p);
+
+ var seenLinks = {},
+ knownHard = {};
+
+ var pos = 0, // current character position in p
+ current = "", // the partial path so far, including a trailing slash if any
+ base = "", // the partial path without a trailing slash
+ previous = ""; // the partial path scanned in the previous round, with slash
+
+ // 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]) {
+ continue;
+ }
+ var stat = fs.lstatSync(base);
+ if (!stat.isSymbolicLink()) {
+ knownHard[base] = true;
+ continue;
+ }
- var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
- if (!seenLinks[id]) {
- fs.statSync(part);
- seenLinks[id] = fs.readlinkSync(part);
- }
+ // 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);
+ }
- var target = seenLinks[id];
- if (target.charAt(0) === '/') {
- // absolute. Start over.
- buf = [];
- p = path.normalizeArray(path.split(target).concat(p.slice(i + 1)));
- i = -1;
- continue;
+ // resolve the link, then start over
+ p = path.resolve(previous, seenLinks[id], p.slice(pos));
+ pos = 0;
+ previous = base = current = "";
}
- // not absolute. join and splice.
- if (i === 0 && p[i].charAt(0) === '/') {
- target = '/' + target;
- }
- target = path.split(target);
- Array.prototype.splice.apply(p, [i, 1].concat(target));
- p = path.normalizeArray(p);
- i = -1;
- buf = [];
- }
- return path.join(buf.join('/') || '/');
-}
+ return p;
+ };
-function realpath(p, cb) {
- if (p.charAt(0) !== '/') {
- p = path.join(process.cwd(), p);
- }
- p = path.split(p);
- var buf = [];
- var seenLinks = {};
- var knownHard = {};
- // walk down the path, swapping out linked pathparts for their real
- // values, and pushing non-link path bits onto the buffer.
- // then return the buffer.
- // NB: path.length changes.
- var i = -1;
- var part;
-
- LOOP();
- function LOOP() {
- i++;
- if (!(i < p.length)) return exit();
- // skip over empty path parts.
- if (p[i] === '') return process.nextTick(LOOP);
- part = path.join(buf.join('/') + '/' + p[i]);
- if (knownHard[part]) {
- buf.push(p[i]);
- return process.nextTick(LOOP);
- }
- return fs.lstat(part, gotStat);
- }
+ // posix version
+ fs.realpath = function realpath(p, cb) {
+ // make p is absolute
+ p = path.resolve(p);
- function gotStat(er, stat) {
- if (er) return cb(er);
- if (!stat.isSymbolicLink()) {
- // not a symlink. easy.
- knownHard[part] = true;
- buf.push(p[i]);
- return process.nextTick(LOOP);
+ var seenLinks = {},
+ knownHard = {};
+
+ var pos = 0, // current character position in p
+ current = "", // the partial path so far, including a trailing slash if any
+ base = "", // the partial path without a trailing slash
+ previous = ""; // the partial path scanned in the previous round, with slash
+
+ // 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) {
+ 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
+ if (!base || knownHard[base]) {
+ return process.nextTick(LOOP);
+ }
+
+ return fs.lstat(base, gotStat);
}
- var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
- if (seenLinks[id]) return gotTarget(null, seenLinks[id]);
- fs.stat(part, function(er) {
- if (er) return cb(er);
- fs.readlink(part, function(er, target) {
- gotTarget(er, seenLinks[id] = target);
+ 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;
+ 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]);
+ }
+ 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) {
+ if (err) return cb(err);
+
+ // resolve the link, then start over
+ p = path.resolve(previous, target, p.slice(pos));
+ pos = 0;
+ previous = base = current = "";
- function gotTarget(er, target) {
- if (er) return cb(er);
- if (target.charAt(0) === '/') {
- // absolute. Start over.
- buf = [];
- p = path.normalizeArray(path.split(target).concat(p.slice(i + 1)));
- i = -1;
return process.nextTick(LOOP);
}
- // not absolute. join and splice.
- if (i === 0 && p[i].charAt(0) === '/') {
- target = '/' + target;
- }
- target = path.split(target);
- Array.prototype.splice.apply(p, [i, 1].concat(target));
- p = path.normalizeArray(p);
- i = -1;
- buf = [];
- return process.nextTick(LOOP);
- }
+ };
- function exit() {
- cb(null, path.join(buf.join('/') || '/'));
- }
}
+
var pool;
function allocNewPool() {