diff --git a/lib/fs.js b/lib/fs.js index 7c622375e3a..d339be9d0bf 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -293,9 +293,7 @@ function makeCallback(cb) { return function() {}; } - return function() { - return cb.apply(null, arguments); - }; + return util._bindHistory(cb); } @@ -362,7 +360,7 @@ fs.read = function(fd, buffer, offset, length, position, callback) { callback && callback(err, bytesRead || 0, buffer); } - binding.read(fd, buffer, offset, length, position, wrapper); + binding.read(fd, buffer, offset, length, position, makeCallback(wrapper)); }; fs.readSync = function(fd, buffer, offset, length, position) { @@ -412,7 +410,7 @@ fs.write = function(fd, buffer, offset, length, position, callback) { callback && callback(err, written || 0, buffer); } - binding.write(fd, buffer, offset, length, position, wrapper); + binding.write(fd, buffer, offset, length, position, makeCallback(wrapper)); }; fs.writeSync = function(fd, buffer, offset, length, position) { diff --git a/lib/util.js b/lib/util.js index 65888920c8d..50342b049ba 100644 --- a/lib/util.js +++ b/lib/util.js @@ -519,6 +519,76 @@ exports.pump = function(readStream, writeStream, callback) { }); }; +// This will bind the current history stack, to the async +// callback error object +exports._bindHistory = function (callback) { + var history = new Error(); + + return function (error) { + // merge history intro error + if (isError(error)) appendHistory(error, history); + + callback.apply(null, arguments); + }; +}; + +function appendHistory(error, history) { + // get the current error.stack handler + var orig = Error.prepareStackTrace; + + // get the history stack list + Error.prepareStackTrace = function (errorObject, stackObject) { + return stackObject; + }; + var historyStack = history.stack; + + // Include the history stack list in the error + Error.prepareStackTrace = function (errorObject, stackObject) { + var modifiedStack = historyStack.slice(1).concat(stackObject); + + if (typeof orig === 'function') { + return orig(errorObject, modifiedStack); + } else { + return FormatStackTrace(errorObject, modifiedStack); + } + }; + // This will need to be performed, so Error.prepareStackTrace is executed + var errorStack = error.stack; + + // the returned error.stack value is cached, so it is safe to restore + // the error.stack handler + Error.prepareStackTrace = orig; +} + +// copyed from deps/v8/src/messages.js +function FormatStackTrace(error, frames) { + var lines = []; + try { + lines.push(error.toString()); + } catch (e) { + try { + lines.push(""); + } catch (ee) { + lines.push(""); + } + } + for (var i = 0; i < frames.length; i++) { + var frame = frames[i]; + var line; + try { + line = frame.toString(); + } catch (e) { + try { + line = ""; + } catch (ee) { + // Any code that reaches this point is seriously nasty! + line = ""; + } + } + lines.push(" at " + line); + } + return lines.join("\n"); +} /** * Inherit the prototype methods from one constructor into another.