mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-06 20:03:51 +00:00
307 lines
10 KiB
C++
307 lines
10 KiB
C++
#ifndef SRC_NODE_FILE_INL_H_
|
|
#define SRC_NODE_FILE_INL_H_
|
|
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
#include "node_file.h"
|
|
#include "req_wrap-inl.h"
|
|
|
|
namespace node {
|
|
namespace fs {
|
|
|
|
FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
|
|
: done_cb_(done_cb), req_(req), mode_(mode) {
|
|
}
|
|
|
|
void FSContinuationData::PushPath(std::string&& path) {
|
|
paths_.emplace_back(std::move(path));
|
|
}
|
|
|
|
void FSContinuationData::PushPath(const std::string& path) {
|
|
paths_.push_back(path);
|
|
}
|
|
|
|
void FSContinuationData::MaybeSetFirstPath(const std::string& path) {
|
|
if (first_path_.empty()) {
|
|
first_path_ = path;
|
|
}
|
|
}
|
|
|
|
std::string FSContinuationData::PopPath() {
|
|
CHECK(!paths_.empty());
|
|
std::string path = std::move(paths_.back());
|
|
paths_.pop_back();
|
|
return path;
|
|
}
|
|
|
|
void FSContinuationData::Done(int result) {
|
|
req_->result = result;
|
|
done_cb_(req_);
|
|
}
|
|
|
|
FSReqBase::FSReqBase(BindingData* binding_data,
|
|
v8::Local<v8::Object> req,
|
|
AsyncWrap::ProviderType type,
|
|
bool use_bigint)
|
|
: ReqWrap(binding_data->env(), req, type),
|
|
use_bigint_(use_bigint),
|
|
binding_data_(binding_data) {
|
|
}
|
|
|
|
void FSReqBase::Init(const char* syscall,
|
|
const char* data,
|
|
size_t len,
|
|
enum encoding encoding) {
|
|
syscall_ = syscall;
|
|
encoding_ = encoding;
|
|
|
|
if (data != nullptr) {
|
|
CHECK(!has_data_);
|
|
buffer_.AllocateSufficientStorage(len + 1);
|
|
buffer_.SetLengthAndZeroTerminate(len);
|
|
memcpy(*buffer_, data, len);
|
|
has_data_ = true;
|
|
}
|
|
}
|
|
|
|
FSReqBase::FSReqBuffer&
|
|
FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) {
|
|
syscall_ = syscall;
|
|
encoding_ = encoding;
|
|
|
|
buffer_.AllocateSufficientStorage(len + 1);
|
|
has_data_ = false; // so that the data does not show up in error messages
|
|
return buffer_;
|
|
}
|
|
|
|
FSReqCallback::FSReqCallback(BindingData* binding_data,
|
|
v8::Local<v8::Object> req,
|
|
bool use_bigint)
|
|
: FSReqBase(binding_data,
|
|
req,
|
|
AsyncWrap::PROVIDER_FSREQCALLBACK,
|
|
use_bigint) {}
|
|
|
|
template <typename NativeT, typename V8T>
|
|
void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
|
|
const uv_stat_t* s,
|
|
const size_t offset) {
|
|
#define SET_FIELD_WITH_STAT(stat_offset, stat) \
|
|
fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \
|
|
static_cast<NativeT>(stat))
|
|
|
|
#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \
|
|
/* NOLINTNEXTLINE(runtime/int) */ \
|
|
SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat))
|
|
|
|
SET_FIELD_WITH_STAT(kDev, s->st_dev);
|
|
SET_FIELD_WITH_STAT(kMode, s->st_mode);
|
|
SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
|
|
SET_FIELD_WITH_STAT(kUid, s->st_uid);
|
|
SET_FIELD_WITH_STAT(kGid, s->st_gid);
|
|
SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
|
|
SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
|
|
SET_FIELD_WITH_STAT(kIno, s->st_ino);
|
|
SET_FIELD_WITH_STAT(kSize, s->st_size);
|
|
SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);
|
|
|
|
SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
|
|
SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
|
|
SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
|
|
SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
|
|
SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
|
|
SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
|
|
SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
|
|
SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec);
|
|
|
|
#undef SET_FIELD_WITH_TIME_STAT
|
|
#undef SET_FIELD_WITH_STAT
|
|
}
|
|
|
|
v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data,
|
|
const bool use_bigint,
|
|
const uv_stat_t* s,
|
|
const bool second) {
|
|
const ptrdiff_t offset =
|
|
second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
|
|
if (use_bigint) {
|
|
auto* const arr = &binding_data->stats_field_bigint_array;
|
|
FillStatsArray(arr, s, offset);
|
|
return arr->GetJSArray();
|
|
} else {
|
|
auto* const arr = &binding_data->stats_field_array;
|
|
FillStatsArray(arr, s, offset);
|
|
return arr->GetJSArray();
|
|
}
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
FSReqPromise<AliasedBufferT>*
|
|
FSReqPromise<AliasedBufferT>::New(BindingData* binding_data,
|
|
bool use_bigint) {
|
|
Environment* env = binding_data->env();
|
|
v8::Local<v8::Object> obj;
|
|
if (!env->fsreqpromise_constructor_template()
|
|
->NewInstance(env->context())
|
|
.ToLocal(&obj)) {
|
|
return nullptr;
|
|
}
|
|
v8::Local<v8::Promise::Resolver> resolver;
|
|
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
|
|
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
|
|
return nullptr;
|
|
}
|
|
return new FSReqPromise(binding_data, obj, use_bigint);
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
FSReqPromise<AliasedBufferT>::~FSReqPromise() {
|
|
// Validate that the promise was explicitly resolved or rejected.
|
|
CHECK(finished_);
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
FSReqPromise<AliasedBufferT>::FSReqPromise(
|
|
BindingData* binding_data,
|
|
v8::Local<v8::Object> obj,
|
|
bool use_bigint)
|
|
: FSReqBase(binding_data,
|
|
obj,
|
|
AsyncWrap::PROVIDER_FSREQPROMISE,
|
|
use_bigint),
|
|
stats_field_array_(
|
|
env()->isolate(),
|
|
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
|
|
|
|
template <typename AliasedBufferT>
|
|
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
|
|
finished_ = true;
|
|
v8::HandleScope scope(env()->isolate());
|
|
InternalCallbackScope callback_scope(this);
|
|
v8::Local<v8::Value> value =
|
|
object()->Get(env()->context(),
|
|
env()->promise_string()).ToLocalChecked();
|
|
v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
|
|
USE(resolver->Reject(env()->context(), reject).FromJust());
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) {
|
|
finished_ = true;
|
|
v8::HandleScope scope(env()->isolate());
|
|
InternalCallbackScope callback_scope(this);
|
|
v8::Local<v8::Value> val =
|
|
object()->Get(env()->context(),
|
|
env()->promise_string()).ToLocalChecked();
|
|
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
|
|
USE(resolver->Resolve(env()->context(), value).FromJust());
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) {
|
|
FillStatsArray(&stats_field_array_, stat);
|
|
Resolve(stats_field_array_.GetJSArray());
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
void FSReqPromise<AliasedBufferT>::SetReturnValue(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
v8::Local<v8::Value> val =
|
|
object()->Get(env()->context(),
|
|
env()->promise_string()).ToLocalChecked();
|
|
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
|
|
args.GetReturnValue().Set(resolver->GetPromise());
|
|
}
|
|
|
|
template <typename AliasedBufferT>
|
|
void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const {
|
|
FSReqBase::MemoryInfo(tracker);
|
|
tracker->TrackField("stats_field_array", stats_field_array_);
|
|
}
|
|
|
|
FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
int index,
|
|
bool use_bigint) {
|
|
v8::Local<v8::Value> value = args[index];
|
|
if (value->IsObject()) {
|
|
return Unwrap<FSReqBase>(value.As<v8::Object>());
|
|
}
|
|
|
|
BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
|
|
Environment* env = binding_data->env();
|
|
if (value->StrictEquals(env->fs_use_promises_symbol())) {
|
|
if (use_bigint) {
|
|
return FSReqPromise<AliasedBigUint64Array>::New(binding_data, use_bigint);
|
|
} else {
|
|
return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Returns nullptr if the operation fails from the start.
|
|
template <typename Func, typename... Args>
|
|
FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
const char* syscall, const char* dest,
|
|
size_t len, enum encoding enc, uv_fs_cb after,
|
|
Func fn, Args... fn_args) {
|
|
CHECK_NOT_NULL(req_wrap);
|
|
req_wrap->Init(syscall, dest, len, enc);
|
|
int err = req_wrap->Dispatch(fn, fn_args..., after);
|
|
if (err < 0) {
|
|
uv_fs_t* uv_req = req_wrap->req();
|
|
uv_req->result = err;
|
|
uv_req->path = nullptr;
|
|
after(uv_req); // after may delete req_wrap if there is an error
|
|
req_wrap = nullptr;
|
|
} else {
|
|
req_wrap->SetReturnValue(args);
|
|
}
|
|
|
|
return req_wrap;
|
|
}
|
|
|
|
// Returns nullptr if the operation fails from the start.
|
|
template <typename Func, typename... Args>
|
|
FSReqBase* AsyncCall(Environment* env,
|
|
FSReqBase* req_wrap,
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
const char* syscall, enum encoding enc,
|
|
uv_fs_cb after, Func fn, Args... fn_args) {
|
|
return AsyncDestCall(env, req_wrap, args,
|
|
syscall, nullptr, 0, enc,
|
|
after, fn, fn_args...);
|
|
}
|
|
|
|
// Template counterpart of SYNC_CALL, except that it only puts
|
|
// the error number and the syscall in the context instead of
|
|
// creating an error in the C++ land.
|
|
// ctx must be checked using value->IsObject() before being passed.
|
|
template <typename Func, typename... Args>
|
|
int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
|
|
FSReqWrapSync* req_wrap, const char* syscall,
|
|
Func fn, Args... args) {
|
|
env->PrintSyncTrace();
|
|
int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
|
|
if (err < 0) {
|
|
v8::Local<v8::Context> context = env->context();
|
|
v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>();
|
|
v8::Isolate* isolate = env->isolate();
|
|
ctx_obj->Set(context,
|
|
env->errno_string(),
|
|
v8::Integer::New(isolate, err)).Check();
|
|
ctx_obj->Set(context,
|
|
env->syscall_string(),
|
|
OneByteString(isolate, syscall)).Check();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
} // namespace fs
|
|
} // namespace node
|
|
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
#endif // SRC_NODE_FILE_INL_H_
|