-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fs: move sync functions to separate file
- Loading branch information
Showing
11 changed files
with
275 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ | |
V(fs) \ | ||
V(fs_dir) \ | ||
V(fs_event_wrap) \ | ||
V(fs_sync) \ | ||
V(heap_utils) \ | ||
V(http2) \ | ||
V(http_parser) \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Oops, something went wrong.