Spaces:
Sleeping
Sleeping
// Copyright Joyent, Inc. and other Node contributors. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a | |
// copy of this software and associated documentation files (the | |
// "Software"), to deal in the Software without restriction, including | |
// without limitation the rights to use, copy, modify, merge, publish, | |
// distribute, sublicense, and/or sell copies of the Software, and to permit | |
// persons to whom the Software is furnished to do so, subject to the | |
// following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included | |
// in all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
// USE OR OTHER DEALINGS IN THE SOFTWARE. | |
var pathModule = require('path'); | |
var isWindows = process.platform === 'win32'; | |
var fs = require('fs'); | |
// JavaScript implementation of realpath, ported from node pre-v6 | |
var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); | |
function rethrow() { | |
// Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and | |
// is fairly slow to generate. | |
var callback; | |
if (DEBUG) { | |
var backtrace = new Error; | |
callback = debugCallback; | |
} else | |
callback = missingCallback; | |
return callback; | |
function debugCallback(err) { | |
if (err) { | |
backtrace.message = err.message; | |
err = backtrace; | |
missingCallback(err); | |
} | |
} | |
function missingCallback(err) { | |
if (err) { | |
if (process.throwDeprecation) | |
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs | |
else if (!process.noDeprecation) { | |
var msg = 'fs: missing callback ' + (err.stack || err.message); | |
if (process.traceDeprecation) | |
console.trace(msg); | |
else | |
console.error(msg); | |
} | |
} | |
} | |
} | |
function maybeCallback(cb) { | |
return typeof cb === 'function' ? cb : rethrow(); | |
} | |
var normalize = pathModule.normalize; | |
// Regexp that finds the next partion of a (partial) path | |
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] | |
if (isWindows) { | |
var nextPartRe = /(.*?)(?:[\/\\]+|$)/g; | |
} else { | |
var nextPartRe = /(.*?)(?:[\/]+|$)/g; | |
} | |
// Regex to find the device root, including trailing slash. E.g. 'c:\\'. | |
if (isWindows) { | |
var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/; | |
} else { | |
var splitRootRe = /^[\/]*/; | |
} | |
exports.realpathSync = function realpathSync(p, cache) { | |
// make p is absolute | |
p = pathModule.resolve(p); | |
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { | |
return cache[p]; | |
} | |
var original = p, | |
seenLinks = {}, | |
knownHard = {}; | |
// current character position in p | |
var pos; | |
// the partial path so far, including a trailing slash if any | |
var current; | |
// the partial path without a trailing slash (except when pointing at a root) | |
var base; | |
// the partial path scanned in the previous round, with slash | |
var previous; | |
start(); | |
function start() { | |
// Skip over roots | |
var m = splitRootRe.exec(p); | |
pos = m[0].length; | |
current = m[0]; | |
base = m[0]; | |
previous = ''; | |
// On windows, check that the root exists. On unix there is no need. | |
if (isWindows && !knownHard[base]) { | |
fs.lstatSync(base); | |
knownHard[base] = true; | |
} | |
} | |
// 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 | |
if (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 | |
// dev/ino always return 0 on windows, so skip the check. | |
var linkTarget = null; | |
if (!isWindows) { | |
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); | |
if (seenLinks.hasOwnProperty(id)) { | |
linkTarget = seenLinks[id]; | |
} | |
} | |
if (linkTarget === null) { | |
fs.statSync(base); | |
linkTarget = fs.readlinkSync(base); | |
} | |
resolvedLink = pathModule.resolve(previous, linkTarget); | |
// track this, if given a cache. | |
if (cache) cache[base] = resolvedLink; | |
if (!isWindows) seenLinks[id] = linkTarget; | |
} | |
// resolve the link, then start over | |
p = pathModule.resolve(resolvedLink, p.slice(pos)); | |
start(); | |
} | |
if (cache) cache[original] = p; | |
return p; | |
}; | |
exports.realpath = function realpath(p, cache, cb) { | |
if (typeof cb !== 'function') { | |
cb = maybeCallback(cache); | |
cache = null; | |
} | |
// make p is absolute | |
p = pathModule.resolve(p); | |
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { | |
return process.nextTick(cb.bind(null, null, cache[p])); | |
} | |
var original = p, | |
seenLinks = {}, | |
knownHard = {}; | |
// current character position in p | |
var pos; | |
// the partial path so far, including a trailing slash if any | |
var current; | |
// the partial path without a trailing slash (except when pointing at a root) | |
var base; | |
// the partial path scanned in the previous round, with slash | |
var previous; | |
start(); | |
function start() { | |
// Skip over roots | |
var m = splitRootRe.exec(p); | |
pos = m[0].length; | |
current = m[0]; | |
base = m[0]; | |
previous = ''; | |
// On windows, check that the root exists. On unix there is no need. | |
if (isWindows && !knownHard[base]) { | |
fs.lstat(base, function(err) { | |
if (err) return cb(err); | |
knownHard[base] = true; | |
LOOP(); | |
}); | |
} else { | |
process.nextTick(LOOP); | |
} | |
} | |
// walk down the path, swapping out linked pathparts for their real | |
// values | |
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 not a symlink | |
if (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()) { | |
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 | |
// dev/ino always return 0 on windows, so skip the check. | |
if (!isWindows) { | |
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); | |
if (seenLinks.hasOwnProperty(id)) { | |
return gotTarget(null, seenLinks[id], base); | |
} | |
} | |
fs.stat(base, function(err) { | |
if (err) return cb(err); | |
fs.readlink(base, function(err, target) { | |
if (!isWindows) seenLinks[id] = target; | |
gotTarget(err, 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)); | |
start(); | |
} | |
}; | |