diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 44abacb41a3430..8276e0693c7dc6 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -102,7 +102,7 @@ const { containsModuleSyntax } = internalBinding('contextify'); const assert = require('internal/assert'); const fs = require('fs'); const path = require('path'); -const { internalModuleStat } = internalBinding('fs'); +const internalFsBinding = internalBinding('fs'); const { safeGetenv } = internalBinding('credentials'); const { privateSymbols: { @@ -194,7 +194,7 @@ function stat(filename) { const result = statCache.get(filename); if (result !== undefined) { return result; } } - const result = internalModuleStat(filename); + const result = internalFsBinding.internalModuleStat(filename); if (statCache !== null && result >= 0) { // Only set cache when `internalModuleStat(filename)` succeeds. statCache.set(filename, result); diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index 54cdbe8e6175ad..c77f8220f9a0b3 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -57,7 +57,7 @@ const { const { Module: CJSModule } = require('internal/modules/cjs/loader'); const { getConditionsSet } = require('internal/modules/esm/utils'); const packageJsonReader = require('internal/modules/package_json_reader'); -const { internalModuleStat } = internalBinding('fs'); +const internalFsBinding = internalBinding('fs'); /** * @typedef {import('internal/modules/esm/package_config.js').PackageConfig} PackageConfig @@ -249,7 +249,7 @@ function finalizeResolution(resolved, base, preserveSymlinks) { throw err; } - const stats = internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? + const stats = internalFsBinding.internalModuleStat(toNamespacedPath(StringPrototypeEndsWith(path, '/') ? StringPrototypeSlice(path, -1) : path)); // Check for stats.isDirectory() @@ -809,8 +809,9 @@ function packageResolve(specifier, base, conditions) { let packageJSONPath = fileURLToPath(packageJSONUrl); let lastPath; do { - const stat = internalModuleStat(toNamespacedPath(StringPrototypeSlice(packageJSONPath, 0, - packageJSONPath.length - 13))); + const stat = internalFsBinding.internalModuleStat( + toNamespacedPath(StringPrototypeSlice(packageJSONPath, 0, packageJSONPath.length - 13)), + ); // Check for !stat.isDirectory() if (stat !== 1) { lastPath = packageJSONPath; diff --git a/src/node_external_reference.h b/src/node_external_reference.h index b952bb7fc5adf8..8d0392a69c9b71 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -15,6 +15,11 @@ using CFunctionCallbackWithOneByteString = using CFunctionCallback = void (*)(v8::Local receiver); using CFunctionCallbackReturnDouble = double (*)(v8::Local receiver); +using CFunctionCallbackReturnInt32 = + int32_t (*)(v8::Local receiver, + const v8::FastOneByteString& input, + // NOLINTNEXTLINE(runtime/references) This is V8 api. + v8::FastApiCallbackOptions& options); using CFunctionCallbackValueReturnDouble = double (*)(v8::Local receiver); using CFunctionCallbackWithInt64 = void (*)(v8::Local receiver, @@ -46,6 +51,7 @@ class ExternalReferenceRegistry { V(CFunctionCallback) \ V(CFunctionCallbackWithOneByteString) \ V(CFunctionCallbackReturnDouble) \ + V(CFunctionCallbackReturnInt32) \ V(CFunctionCallbackValueReturnDouble) \ V(CFunctionCallbackWithInt64) \ V(CFunctionCallbackWithBool) \ diff --git a/src/node_file.cc b/src/node_file.cc index a3e80898cde6b6..2a416ce664172f 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -38,6 +38,7 @@ #include "req_wrap-inl.h" #include "stream_base-inl.h" #include "string_bytes.h" +#include "v8-fast-api-calls.h" #if defined(__MINGW32__) || defined(_MSC_VER) # include @@ -51,6 +52,8 @@ using v8::Array; using v8::BigInt; using v8::Context; using v8::EscapableHandleScope; +using v8::FastApiCallbackOptions; +using v8::FastOneByteString; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -1051,6 +1054,34 @@ static void InternalModuleStat(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(rc); } +static int32_t FastInternalModuleStat( + Local recv, + const FastOneByteString& input, + // NOLINTNEXTLINE(runtime/references) This is V8 api. + FastApiCallbackOptions& options) { + Environment* env = Environment::GetCurrent(recv->GetCreationContextChecked()); + + std::string_view path(input.data, input.length); + if (UNLIKELY(!env->permission()->is_granted( + permission::PermissionScope::kFileSystemRead, path))) { + options.fallback = true; + return -1; + } + + uv_fs_t req; + int rc = uv_fs_stat(env->event_loop(), &req, path.data(), nullptr); + if (rc == 0) { + const uv_stat_t* const s = static_cast(req.ptr); + rc = !!(s->st_mode & S_IFDIR); + } + uv_fs_req_cleanup(&req); + + return rc; +} + +v8::CFunction fast_internal_module_stat_( + v8::CFunction::Make(FastInternalModuleStat)); + constexpr bool is_uv_error_except_no_entry(int result) { return result < 0 && result != UV_ENOENT; } @@ -3145,7 +3176,11 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "rmdir", RMDir); SetMethod(isolate, target, "mkdir", MKDir); SetMethod(isolate, target, "readdir", ReadDir); - SetMethod(isolate, target, "internalModuleStat", InternalModuleStat); + SetFastMethod(isolate, + target, + "internalModuleStat", + InternalModuleStat, + &fast_internal_module_stat_); SetMethod(isolate, target, "stat", Stat); SetMethod(isolate, target, "lstat", LStat); SetMethod(isolate, target, "fstat", FStat); @@ -3266,6 +3301,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(MKDir); registry->Register(ReadDir); registry->Register(InternalModuleStat); + registry->Register(FastInternalModuleStat); + registry->Register(fast_internal_module_stat_.GetTypeInfo()); registry->Register(Stat); registry->Register(LStat); registry->Register(FStat);