Skip to content

Commit

Permalink
fs.stat third parameter controlling error creation
Browse files Browse the repository at this point in the history
In some environment (especially when coffescript is involved) module.js
will spend a lot of time looking up nonexisting files. This is caused by the
lengthy error creation. Those errors are then immediately caught.

This change makes the lookup much faster, by avoiding the unnecessary error
creation.

module::statPath now uses the new second parameter of fs.statSync function of the
fs.js. There is a similar change for the fs.stat, adding the third parameter.

Apply suggestions from libuv pull request

Thanks saghul: joyent/libuv#1428

Fix the datastructures for async

Documentation update

Add tests and simplify Stat function

Apply the code review comments
  • Loading branch information
errendir committed Sep 3, 2014
1 parent 912b5e0 commit e430f80
Show file tree
Hide file tree
Showing 7 changed files with 351 additions and 119 deletions.
10 changes: 8 additions & 2 deletions doc/api/fs.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,15 @@ Only available on Mac OS X.

Synchronous lchmod(2).

## fs.stat(path, callback)
## fs.stat(path, callback, [throwSafe])

Asynchronous stat(2). The callback gets two arguments `(err, stats)` where
`stats` is a [fs.Stats](#fs_class_fs_stats) object. See the [fs.Stats](#fs_class_fs_stats)
section below for more information.

Setting the throwSafe parameter to true prevents the error creation. If the call
fails, the first parameter of the callback will be true.

## fs.lstat(path, callback)

Asynchronous lstat(2). The callback gets two arguments `(err, stats)` where
Expand All @@ -187,10 +190,13 @@ Asynchronous fstat(2). The callback gets two arguments `(err, stats)` where
`stats` is a `fs.Stats` object. `fstat()` is identical to `stat()`, except that
the file to be stat-ed is specified by the file descriptor `fd`.

## fs.statSync(path)
## fs.statSync(path, [throwSafe])

Synchronous stat(2). Returns an instance of `fs.Stats`.

Setting the throwSafe parameter to true prevents the error creation. If the call
fails `fs.statSync` returns `false`.

## fs.lstatSync(path)

Synchronous lstat(2). Returns an instance of `fs.Stats`.
Expand Down
66 changes: 43 additions & 23 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,16 @@ function assertEncoding(encoding) {
}
}

function nullCheck(path, callback) {
function nullCheck(path, callback, throwSafe) {
if (('' + path).indexOf('\u0000') !== -1) {
var er = new Error('Path must be a string without null bytes.');
if (!callback)
throw er;
process.nextTick(function() {
callback(er);
});
if (!throwSafe) {
var er = new Error('Path must be a string without null bytes.');
if (!callback)
throw er;
process.nextTick(function() {
callback(er);
});
}
return false;
}
return true;
Expand Down Expand Up @@ -181,21 +183,30 @@ fs.Stats.prototype.isSocket = function() {
};

fs.exists = function(path, callback) {
if (!nullCheck(path, cb)) return;
binding.stat(pathModule._makeLong(path), cb);
function cb(err, stats) {
if (callback) callback(err ? false : true);
if (!nullCheck(path, undefined, true)) {
process.nextTick(function() {
cb(true, false);
});
return;
}
binding.stat(pathModule._makeLong(path), cb, true);
function cb(err, result) {
if (callback) {
if (err) {
callback(false);
} else {
callback(!!result);
}
}
}
};

fs.existsSync = function(path) {
try {
nullCheck(path);
binding.stat(pathModule._makeLong(path));
return true;
} catch (e) {
if (!nullCheck(path, undefined, true))
return false;
}
if (!binding.stat(pathModule._makeLong(path), undefined, true))
return false;
return true;
};

fs.readFile = function(path, options, callback_) {
Expand Down Expand Up @@ -701,10 +712,17 @@ fs.lstat = function(path, callback) {
binding.lstat(pathModule._makeLong(path), callback);
};

fs.stat = function(path, callback) {
fs.stat = function(path, callback, throwSafe) {
callback = makeCallback(callback);
if (!nullCheck(path, callback)) return;
binding.stat(pathModule._makeLong(path), callback);
if (!nullCheck(path, callback, throwSafe)) {
if (throwSafe) {
process.nextTick(function() {
callback(true, false);
});
}
return;
}
binding.stat(pathModule._makeLong(path), callback, throwSafe);
};

fs.fstatSync = function(fd) {
Expand All @@ -716,9 +734,11 @@ fs.lstatSync = function(path) {
return binding.lstat(pathModule._makeLong(path));
};

fs.statSync = function(path) {
nullCheck(path);
return binding.stat(pathModule._makeLong(path));
fs.statSync = function(path, throwSafe) {
if (!nullCheck(path, undefined, throwSafe))
return false;

return binding.stat(pathModule._makeLong(path), undefined, throwSafe);
};

fs.readlink = function(path, callback) {
Expand Down
7 changes: 3 additions & 4 deletions lib/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,9 @@ var debug = Module._debug;
// -> a/index.<ext>

function statPath(path) {
try {
return fs.statSync(path);
} catch (ex) {}
return false;
var fs = NativeModule.require('fs');

return fs.statSync(path, true);
}

// check if the directory is a package.json dir
Expand Down
Loading

0 comments on commit e430f80

Please sign in to comment.