Skip to content

Commit

Permalink
fs: move sync functions to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Sep 10, 2023
1 parent afea87e commit 783cc2f
Show file tree
Hide file tree
Showing 11 changed files with 275 additions and 72 deletions.
4 changes: 2 additions & 2 deletions lib/internal/fs/read/utf8.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

const { handleErrorFromBinding } = require('internal/fs/utils');

const binding = internalBinding('fs');
const syncBinding = internalBinding('fs_sync');

/**
* @param {string} path
* @param {number} flag
* @return {string}
*/
function readFileSyncUtf8(path, flag) {
const response = binding.readFileSync(path, flag);
const response = syncBinding.readFileUtf8(path, flag);

if (typeof response === 'string') {
return response;
Expand Down
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
'src/node_errors.cc',
'src/node_external_reference.cc',
'src/node_file.cc',
'src/node_file_sync.cc',
'src/node_http_parser.cc',
'src/node_http2.cc',
'src/node_i18n.cc',
Expand Down Expand Up @@ -222,6 +223,7 @@
'src/node_external_reference.h',
'src/node_file.h',
'src/node_file-inl.h',
'src/node_file_sync.h',
'src/node_http_common.h',
'src/node_http_common-inl.h',
'src/node_http2.h',
Expand Down
1 change: 1 addition & 0 deletions src/base_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace node {
#define SERIALIZABLE_BINDING_TYPES(V) \
V(encoding_binding_data, encoding_binding::BindingData) \
V(fs_binding_data, fs::BindingData) \
V(fs_sync_binding_data, fs_sync::BindingData) \
V(mksnapshot_binding_data, mksnapshot::BindingData) \
V(v8_binding_data, v8_utils::BindingData) \
V(blob_binding_data, BlobBindingData) \
Expand Down
1 change: 1 addition & 0 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
V(fs) \
V(fs_dir) \
V(fs_event_wrap) \
V(fs_sync) \
V(heap_utils) \
V(http2) \
V(http_parser) \
Expand Down
1 change: 1 addition & 0 deletions src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
V(contextify) \
V(encoding_binding) \
V(fs) \
V(fs_sync) \
V(mksnapshot) \
V(timers) \
V(process_methods) \
Expand Down
1 change: 1 addition & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class ExternalReferenceRegistry {
V(fs) \
V(fs_dir) \
V(fs_event_wrap) \
V(fs_sync) \
V(handle_wrap) \
V(heap_utils) \
V(messaging) \
Expand Down
70 changes: 0 additions & 70 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1964,74 +1964,6 @@ static inline Maybe<void> CheckOpenPermissions(Environment* env,
return JustVoid();
}

static void ReadFileSync(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
auto isolate = env->isolate();

CHECK_GE(args.Length(), 2);

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);

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

if (CheckOpenPermissions(env, path, flags).IsNothing()) return;

uv_fs_t req;
auto defer_req_cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });

FS_SYNC_TRACE_BEGIN(open);
uv_file file = uv_fs_open(nullptr, &req, *path, flags, 438, nullptr);
FS_SYNC_TRACE_END(open);
if (req.result < 0) {
// req will be cleaned up by scope leave.
Local<Value> out[] = {
Integer::New(isolate, req.result), // errno
FIXED_ONE_BYTE_STRING(isolate, "open"), // syscall
};
return args.GetReturnValue().Set(Array::New(isolate, out, arraysize(out)));
}
uv_fs_req_cleanup(&req);

auto defer_close = OnScopeLeave([file]() {
uv_fs_t close_req;
CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
uv_fs_req_cleanup(&close_req);
});

std::string result{};
char buffer[8192];
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));

FS_SYNC_TRACE_BEGIN(read);
while (true) {
auto r = uv_fs_read(nullptr, &req, file, &buf, 1, -1, nullptr);
if (req.result < 0) {
FS_SYNC_TRACE_END(read);
// req will be cleaned up by scope leave.
Local<Value> out[] = {
Integer::New(isolate, req.result), // errno
FIXED_ONE_BYTE_STRING(isolate, "read"), // syscall
};
return args.GetReturnValue().Set(
Array::New(isolate, out, arraysize(out)));
}
uv_fs_req_cleanup(&req);
if (r <= 0) {
break;
}
result.append(buf.base, r);
}
FS_SYNC_TRACE_END(read);

args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
result.data(),
v8::NewStringType::kNormal,
result.size())
.ToLocalChecked());
}

static void Open(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand Down Expand Up @@ -3188,7 +3120,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
SetMethod(isolate, target, "stat", Stat);
SetMethod(isolate, target, "lstat", LStat);
SetMethod(isolate, target, "fstat", FStat);
SetMethodNoSideEffect(isolate, target, "readFileSync", ReadFileSync);
SetMethod(isolate, target, "statfs", StatFs);
SetMethod(isolate, target, "link", Link);
SetMethod(isolate, target, "symlink", Symlink);
Expand Down Expand Up @@ -3306,7 +3237,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(Stat);
registry->Register(LStat);
registry->Register(FStat);
registry->Register(ReadFileSync);
registry->Register(StatFs);
registry->Register(Link);
registry->Register(Symlink);
Expand Down
214 changes: 214 additions & 0 deletions src/node_file_sync.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#include "node_file_sync.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file.h"
#include "node_metadata.h"
#include "permission/permission.h"
#include "util-inl.h"
#include "v8-fast-api-calls.h"
#include "v8.h"

#include "tracing/trace_event.h"

#include "string_bytes.h"

#include <fcntl.h>

namespace node {
namespace fs_sync {

using v8::Array;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
using v8::Int32;
using v8::Integer;
using v8::Isolate;
using v8::JustVoid;
using v8::Local;
using v8::Maybe;
using v8::NewStringType;
using v8::Nothing;
using v8::Object;
using v8::ObjectTemplate;
using v8::String;
using v8::Value;

#define TRACE_NAME(name) "fs.sync." #name
#define GET_TRACE_ENABLED \
(*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \
TRACING_CATEGORY_NODE2(fs, sync)) != 0)
#define FS_SYNC_TRACE_BEGIN(syscall, ...) \
if (GET_TRACE_ENABLED) \
TRACE_EVENT_BEGIN( \
TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
#define FS_SYNC_TRACE_END(syscall, ...) \
if (GET_TRACE_ENABLED) \
TRACE_EVENT_END( \
TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);

// TODO(@anonrig): Remove the duplicate code from both node_file.cc and here.
static inline Maybe<void> CheckOpenPermissions(Environment* env,
const BufferValue& path,
int flags) {
// These flags capture the intention of the open() call.
const int rwflags = flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);

// These flags have write-like side effects even with O_RDONLY, at least on
// some operating systems. On Windows, for example, O_RDONLY | O_TEMPORARY
// can be used to delete a file. Bizarre.
const int write_as_side_effect = flags & (UV_FS_O_APPEND | UV_FS_O_CREAT |
UV_FS_O_TRUNC | UV_FS_O_TEMPORARY);

// TODO(rafaelgss): it can be optimized to avoid two permission checks
auto pathView = path.ToStringView();
if (rwflags != UV_FS_O_WRONLY) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env,
permission::PermissionScope::kFileSystemRead,
pathView,
Nothing<void>());
}
if (rwflags != UV_FS_O_RDONLY || write_as_side_effect) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env,
permission::PermissionScope::kFileSystemWrite,
pathView,
Nothing<void>());
}
return JustVoid();
}

void BindingData::MemoryInfo(MemoryTracker* tracker) const {
// TODO(@anonrig): Implement this
}

BindingData::BindingData(Realm* realm, v8::Local<v8::Object> object)
: SnapshotableObject(realm, object, type_int) {
// TODO(@anonrig): Implement this
}

bool BindingData::PrepareForSerialization(v8::Local<v8::Context> context,
v8::SnapshotCreator* creator) {
// Return true because we need to maintain the reference to the binding from
// JS land.
return true;
}

InternalFieldInfoBase* BindingData::Serialize(int index) {
DCHECK_IS_SNAPSHOT_SLOT(index);
InternalFieldInfo* info =
InternalFieldInfoBase::New<InternalFieldInfo>(type());
return info;
}

void BindingData::Deserialize(v8::Local<v8::Context> context,
v8::Local<v8::Object> holder,
int index,
InternalFieldInfoBase* info) {
DCHECK_IS_SNAPSHOT_SLOT(index);
v8::HandleScope scope(context->GetIsolate());
Realm* realm = Realm::GetCurrent(context);
BindingData* binding = realm->AddBindingData<BindingData>(holder);
CHECK_NOT_NULL(binding);
}

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

CHECK_GE(args.Length(), 2);

BufferValue path(env->isolate(), args[0]);
CHECK_NOT_NULL(*path);

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

if (CheckOpenPermissions(env, path, flags).IsNothing()) return;

uv_fs_t req;
auto defer_req_cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });

FS_SYNC_TRACE_BEGIN(open);
uv_file file = uv_fs_open(nullptr, &req, *path, flags, 438, nullptr);
FS_SYNC_TRACE_END(open);
if (req.result < 0) {
// req will be cleaned up by scope leave.
Local<Value> out[] = {
Integer::New(isolate, req.result), // errno
FIXED_ONE_BYTE_STRING(isolate, "open"), // syscall
};
return args.GetReturnValue().Set(Array::New(isolate, out, arraysize(out)));
}
uv_fs_req_cleanup(&req);

auto defer_close = OnScopeLeave([file]() {
uv_fs_t close_req;
CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
uv_fs_req_cleanup(&close_req);
});

std::string result{};
char buffer[8192];
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));

FS_SYNC_TRACE_BEGIN(read);
while (true) {
auto r = uv_fs_read(nullptr, &req, file, &buf, 1, -1, nullptr);
if (req.result < 0) {
FS_SYNC_TRACE_END(read);
// req will be cleaned up by scope leave.
Local<Value> out[] = {
Integer::New(isolate, req.result), // errno
FIXED_ONE_BYTE_STRING(isolate, "read"), // syscall
};
return args.GetReturnValue().Set(
Array::New(isolate, out, arraysize(out)));
}
uv_fs_req_cleanup(&req);
if (r <= 0) {
break;
}
result.append(buf.base, r);
}
FS_SYNC_TRACE_END(read);

args.GetReturnValue().Set(String::NewFromUtf8(env->isolate(),
result.data(),
v8::NewStringType::kNormal,
result.size())
.ToLocalChecked());
}

void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
SetMethodNoSideEffect(isolate, target, "readFileUtf8", ReadFileUtf8);
}

void BindingData::CreatePerContextProperties(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
Realm* realm = Realm::GetCurrent(context);
realm->AddBindingData<BindingData>(target);
}

void BindingData::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(ReadFileUtf8);
}

} // namespace fs_sync

} // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(
fs_sync, node::fs_sync::BindingData::CreatePerContextProperties)
NODE_BINDING_PER_ISOLATE_INIT(
fs_sync, node::fs_sync::BindingData::CreatePerIsolateProperties)
NODE_BINDING_EXTERNAL_REFERENCE(
fs_sync, node::fs_sync::BindingData::RegisterExternalReferences)
Loading

0 comments on commit 783cc2f

Please sign in to comment.