const assert = require('assert').ok;
const fs = require('fs');
const path = require('path');
+const internalModuleStat = process.binding('fs').internalModuleStat;
// If obj.hasOwnProperty has been overridden, then calling
// -> a.<ext>
// -> a/index.<ext>
-function statPath(path) {
- try {
- return fs.statSync(path);
- } catch (ex) {}
- return false;
-}
-
// check if the directory is a package.json dir
const packageMainCache = {};
if (!pkg) return false;
var filename = path.resolve(requestPath, pkg);
- return tryFile(filename, null) || tryExtensions(filename, exts) ||
+ return tryFile(filename) || tryExtensions(filename, exts) ||
tryExtensions(path.resolve(filename, 'index'), exts);
}
Module._realpathCache = {};
// check if the file exists and is not a directory
-function tryFile(requestPath, stats) {
- stats = stats || statPath(requestPath);
- if (stats && !stats.isDirectory()) {
- return fs.realpathSync(requestPath, Module._realpathCache);
- }
- return false;
+function tryFile(requestPath) {
+ const rc = internalModuleStat(requestPath);
+ return rc === 0 && toRealPath(requestPath);
+}
+
+function toRealPath(requestPath) {
+ return fs.realpathSync(requestPath, Module._realpathCache);
}
// given a path check a the file exists with any of the set extensions
function tryExtensions(p, exts) {
for (var i = 0, EL = exts.length; i < EL; i++) {
- var filename = tryFile(p + exts[i], null);
+ var filename = tryFile(p + exts[i]);
if (filename) {
return filename;
var filename;
if (!trailingSlash) {
- var stats = statPath(basePath);
- // try to join the request to the path
- filename = tryFile(basePath, stats);
-
- if (!filename && stats && stats.isDirectory()) {
+ const rc = internalModuleStat(basePath);
+ if (rc === 0) { // File.
+ filename = toRealPath(basePath);
+ } else if (rc === 1) { // Directory.
filename = tryPackage(basePath, exts);
}
return handle_scope.Escape(stats);
}
+// Used to speed up module loading. Returns 0 if the path refers to
+// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
+// The speedup comes from not creating thousands of Stat and Error objects.
+static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsString());
+ node::Utf8Value path(env->isolate(), args[0]);
+
+ uv_fs_t req;
+ int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
+ if (rc == 0) {
+ const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
+ rc = !!(s->st_mode & S_IFDIR);
+ }
+ uv_fs_req_cleanup(&req);
+
+ args.GetReturnValue().Set(rc);
+}
+
static void Stat(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->SetMethod(target, "rmdir", RMDir);
env->SetMethod(target, "mkdir", MKDir);
env->SetMethod(target, "readdir", ReadDir);
+ env->SetMethod(target, "internalModuleStat", InternalModuleStat);
env->SetMethod(target, "stat", Stat);
env->SetMethod(target, "lstat", LStat);
env->SetMethod(target, "fstat", FStat);