Skip to content

Commit

Permalink
fs: reimplement accessSync
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Sep 10, 2023
1 parent 80c845b commit 8a748c4
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 21 deletions.
29 changes: 29 additions & 0 deletions benchmark/fs/bench-accessSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const common = require('../common');
const fs = require('fs');
const tmpdir = require('../../test/common/tmpdir');
tmpdir.refresh();

const paths = [
__filename,
tmpdir.resolve(`.non-existing-file-${process.pid}`),
];

const bench = common.createBenchmark(main, {
n: [1e5],
});

function main({ n }) {
bench.start();
for (let i = 0; i < n; i++) {
for (let j = 0; j < paths.length; j++) {
try {
fs.accessSync(paths[j]);
} catch {
// do nothing
}
}
}
bench.end(n);
}
7 changes: 1 addition & 6 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,7 @@ function access(path, mode, callback) {
* @returns {void}
*/
function accessSync(path, mode) {
path = getValidatedPath(path);
mode = getValidMode(mode, 'access');

const ctx = { path };
binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx);
handleErrorFromBinding(ctx);
syncFs.access(path, mode);
}

/**
Expand Down
14 changes: 13 additions & 1 deletion lib/internal/fs/sync.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const pathModule = require('path');
const { handleErrorFromBinding, getValidatedPath, stringToFlags } = require('internal/fs/utils');
const { handleErrorFromBinding, getValidatedPath, stringToFlags, getValidMode } = require('internal/fs/utils');

const syncBinding = internalBinding('fs_sync');

Expand Down Expand Up @@ -32,7 +32,19 @@ function exists(path) {
return syncBinding.exists(pathModule.toNamespacedPath(path));
}

function access(path, mode) {
path = getValidatedPath(path);
mode = getValidMode(mode, 'access');

const errno = syncBinding.access(pathModule.toNamespacedPath(path), mode);

if (errno !== undefined) {
handleErrorFromBinding({ errno, syscall: 'access', path });
}
}

module.exports = {
readFileUtf8,
exists,
access,
};
54 changes: 41 additions & 13 deletions src/node_file_sync.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "node_constants.h"
#include "node_file_sync.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
#include "node_constants.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file.h"
Expand All @@ -27,12 +27,12 @@ namespace fs_sync {
using v8::Array;
using v8::CFunction;
using v8::Context;
using v8::FastOneByteString;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
using v8::Int32;
using v8::Integer;
using v8::Isolate;
using v8::FastOneByteString;
using v8::JustVoid;
using v8::Local;
using v8::Maybe;
Expand Down Expand Up @@ -122,23 +122,49 @@ void BindingData::Deserialize(v8::Local<v8::Context> context,
CHECK_NOT_NULL(binding);
}

void BindingData::Access(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();

const int argc = args.Length();
CHECK_GE(argc, 2);

CHECK(args[1]->IsInt32());
int mode = args[1].As<Int32>()->Value();

BufferValue path(isolate, args[0]);
CHECK_NOT_NULL(*path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());

uv_fs_t req;
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
FS_SYNC_TRACE_BEGIN(access);
uv_fs_access(nullptr, &req, *path, mode, nullptr);
FS_SYNC_TRACE_END(access);

if (req.result < 0) {
return args.GetReturnValue().Set(int(req.result));
}
}

bool BindingData::ExistsInternal(const std::string_view path) {
uv_fs_t req;
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
FS_SYNC_TRACE_BEGIN(access);
int err = uv_fs_access(nullptr, &req, path.data(), F_OK, nullptr);
FS_SYNC_TRACE_END(access);

#ifdef _WIN32
// In case of an invalid symlink, `binding.access()` on win32
// will **not** return an error and is therefore not enough.
// Double check with `stat()`.
if (err != 0) {
FS_SYNC_TRACE_BEGIN(stat);
err = uv_fs_stat(nullptr, &req, path.data, nullptr);
FS_SYNC_TRACE_END(stat);
}
#endif // _WIN32
// In case of an invalid symlink, `binding.access()` on win32
// will **not** return an error and is therefore not enough.
// Double check with `stat()`.
if (err != 0) {
FS_SYNC_TRACE_BEGIN(stat);
err = uv_fs_stat(nullptr, &req, path.data, nullptr);
FS_SYNC_TRACE_END(stat);
}
#endif // _WIN32

return err == 0;
}
Expand All @@ -159,7 +185,7 @@ void BindingData::Exists(const FunctionCallbackInfo<Value>& args) {
}

bool BindingData::FastExists(Local<Value> receiver,
const FastOneByteString& path) {
const FastOneByteString& path) {
// TODO(@anonrig): Add "THROW_IF_INSUFFICIENT_PERMISSIONS"
return ExistsInternal(std::string_view(path.data, path.length));
}
Expand Down Expand Up @@ -237,6 +263,7 @@ void BindingData::ReadFileUtf8(const FunctionCallbackInfo<Value>& args) {
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
SetMethodNoSideEffect(isolate, target, "access", Access);
SetFastMethodNoSideEffect(isolate, target, "exists", Exists, &fast_exists_);
SetMethodNoSideEffect(isolate, target, "readFileUtf8", ReadFileUtf8);
}
Expand All @@ -251,6 +278,7 @@ void BindingData::CreatePerContextProperties(Local<Object> target,

void BindingData::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(Access);
registry->Register(Exists);
registry->Register(FastExists);
registry->Register(fast_exists_.GetTypeInfo());
Expand Down
4 changes: 3 additions & 1 deletion src/node_file_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ class BindingData : public SnapshotableObject {
SET_MEMORY_INFO_NAME(BindingData)

static void Exists(const v8::FunctionCallbackInfo<v8::Value>& args);
static bool FastExists(v8::Local<v8::Value> receiver, const v8::FastOneByteString& path);
static bool FastExists(v8::Local<v8::Value> receiver,
const v8::FastOneByteString& path);

static void Access(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ReadFileUtf8(const v8::FunctionCallbackInfo<v8::Value>& args);

static void CreatePerIsolateProperties(IsolateData* isolate_data,
Expand Down

0 comments on commit 8a748c4

Please sign in to comment.