var normalize = path.normalize;
var normalizeArray = path.normalizeArray;
-fs.realpathSync = function (path) {
- var seen_links = {}, knownHards = {}, buf, i = 0, part, x, stats;
- if (path.charAt(0) !== '/') {
- var cwd = process.cwd().split('/');
- path = cwd.concat(path.split('/'));
- path = normalizeArray(path);
- i = cwd.length;
- buf = [].concat(cwd);
- } else {
- path = normalizeArray(path.split('/'));
- buf = [''];
- }
- for (; i<path.length; i++) {
- part = path.slice(0, i+1).join('/');
- if (part.length !== 0) {
- if (part in knownHards) {
- buf.push(path[i]);
- } else {
- stats = fs.lstatSync(part);
- if (stats.isSymbolicLink()) {
- x = stats.dev.toString(32)+":"+stats.ino.toString(32);
- if (x in seen_links)
- throw new Error("cyclic link at "+part);
- seen_links[x] = true;
- part = fs.readlinkSync(part);
- if (part.charAt(0) === '/') {
- // absolute
- path = normalizeArray(part.split('/'));
- buf = [''];
- i = 0;
- } else {
- // relative
- Array.prototype.splice.apply(path, [i, 1].concat(part.split('/')));
- part = normalizeArray(path);
- var y = 0, L = Math.max(path.length, part.length), delta;
- for (; y<L && path[y] === part[y]; y++);
- if (y !== L) {
- path = part;
- delta = i-y;
- i = y-1;
- if (delta > 0) buf.splice(y, delta);
- } else {
- i--;
- }
- }
- } else {
- buf.push(path[i]);
- knownHards[buf.join('/')] = true;
- }
- }
+// 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 = p.split('/');
+ 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 = buf.join('/')+'/'+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 id = stat.dev.toString(32)+':'+stat.ino.toString(32);
+ if (seenLinks[id]) throw new Error("cyclic link at "+part);
+ seenLinks[id] = true;
+ var target = fs.readlinkSync(part);
+ if (target.charAt(0) === '/') {
+ // absolute. Start over.
+ buf = [''];
+ p = path.normalizeArray(target.split('/'));
+ i = 0;
+ continue;
+ }
+ // not absolute. join and splice.
+ target = target.split('/');
+ Array.prototype.splice.apply(p, [i, 1].concat(target));
+ p = path.normalizeArray(p);
+ i = 0;
+ buf = [''];
}
return buf.join('/');
}
-
-
-fs.realpath = function (path, callback) {
- var seen_links = {}, knownHards = {}, buf = [''], i = 0, part, x;
- if (path.charAt(0) !== '/') {
- // assumes cwd is canonical
- var cwd = process.cwd().split('/');
- path = cwd.concat(path.split('/'));
- path = normalizeArray(path);
- i = cwd.length-1;
- buf = [].concat(cwd);
- } else {
- path = normalizeArray(path.split('/'));
- }
- function done(err) {
- if (callback) {
- if (!err) callback(err, buf.join('/'));
- else callback(err);
+function realpath (p, cb) {
+ if (p.charAt(0) !== '/') {
+ p = path.join(process.cwd(), p);
+ }
+ p = p.split('/');
+ 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 = 0;
+ 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 = buf.join('/')+'/'+p[i];
+ if (knownHard[part]) {
+ buf.push( p[i] );
+ return process.nextTick(LOOP);
}
- }
- function next() {
- if (++i === path.length) return done();
- part = path.slice(0, i+1).join('/');
- if (part.length === 0) return next();
- if (part in knownHards) {
- buf.push(path[i]);
- next();
- } else {
- fs.lstat(part, function(err, stats){
- if (err) return done(err);
- if (stats.isSymbolicLink()) {
- x = stats.dev.toString(32)+":"+stats.ino.toString(32);
- if (x in seen_links)
- return done(new Error("cyclic link at "+part));
- seen_links[x] = true;
- fs.readlink(part, function(err, npart){
- if (err) return done(err);
- part = npart;
- if (part.charAt(0) === '/') {
- // absolute
- path = normalizeArray(part.split('/'));
- buf = [''];
- i = 0;
- } else {
- // relative
- Array.prototype.splice.apply(path, [i, 1].concat(part.split('/')));
- part = normalizeArray(path);
- var y = 0, L = Math.max(path.length, part.length), delta;
- for (; y<L && path[y] === part[y]; y++);
- if (y !== L) {
- path = part;
- delta = i-y;
- i = y-1; // resolve new node if needed
- if (delta > 0) buf.splice(y, delta);
- }
- else {
- i--; // resolve new node if needed
- }
- }
- next();
- }); // binding.readlink
- }
- else {
- buf.push(path[i]);
- knownHards[buf.join('/')] = true;
- next();
- }
- }); // binding.lstat
+ return fs.lstat(part, gotStat);
+ }
+ 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 id = stat.dev.toString(32)+':'+stat.ino.toString(32);
+ if (seenLinks[id]) return cb(new Error("cyclic link at "+part));
+ seenLinks[id] = true;
+ fs.readlink(part, gotTarget);
+ }
+ function gotTarget (er, target) {
+ if (er) return cb(er);
+ if (target.charAt(0) === '/') {
+ // absolute. Start over.
+ buf = [''];
+ p = path.normalizeArray(target.split('/'));
+ i = 0;
+ return process.nextTick(LOOP);
}
+ // not absolute. join and splice.
+ target = target.split('/');
+ Array.prototype.splice.apply(p, [i, 1].concat(target));
+ p = path.normalizeArray(p);
+ i = 0;
+ buf = [''];
+ return process.nextTick(LOOP);
}
- next();
-};
+ function exit () {
+ cb(null, buf.join('/') || '/');
+ }
+}
var pool;
function allocNewPool () {