mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
src: clean up node_file.h
- Move inline functions into an `-inl.h` file - Move override function definitions into `.cc` files - Remove `using` statements from header files - Make data fields of classes private - Mark classes at the end of hierarchies as `final` This is also partially being done in an attempt to avoid a particular internal compiler error, see https://github.com/nodejs/node/pull/30475#issuecomment-554740850 for details. PR-URL: https://github.com/nodejs/node/pull/30530 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
committed by
gengjiawen
parent
6c4cf862d0
commit
52a3e35604
1
node.gyp
1
node.gyp
@@ -613,6 +613,7 @@
|
||||
'src/node_dir.h',
|
||||
'src/node_errors.h',
|
||||
'src/node_file.h',
|
||||
'src/node_file-inl.h',
|
||||
'src/node_http2.h',
|
||||
'src/node_http2_state.h',
|
||||
'src/node_i18n.h',
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "node_process.h"
|
||||
#include "node_v8_platform-inl.h"
|
||||
#include "node_worker.h"
|
||||
#include "req_wrap-inl.h"
|
||||
#include "tracing/agent.h"
|
||||
#include "tracing/traced_value.h"
|
||||
#include "util-inl.h"
|
||||
@@ -35,6 +36,7 @@ using v8::HandleScope;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::NewStringType;
|
||||
using v8::Number;
|
||||
using v8::Object;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "node_dir.h"
|
||||
#include "node_file-inl.h"
|
||||
#include "node_process.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "tracing/trace_event.h"
|
||||
|
||||
#include "req_wrap-inl.h"
|
||||
#include "string_bytes.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@@ -85,6 +86,10 @@ DirHandle::~DirHandle() {
|
||||
CHECK(closed_); // We have to be closed at the point
|
||||
}
|
||||
|
||||
void DirHandle::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackFieldWithSize("dir", sizeof(*dir_));
|
||||
}
|
||||
|
||||
// Close the directory handle if it hasn't already been closed. A process
|
||||
// warning will be emitted using a SetImmediate to avoid calling back to
|
||||
// JS during GC. If closing the fd fails at this point, a fatal exception
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "node_file.h"
|
||||
#include "node.h"
|
||||
#include "req_wrap-inl.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -20,16 +18,13 @@ class DirHandle : public AsyncWrap {
|
||||
~DirHandle() override;
|
||||
|
||||
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Open(const v8::FunctionCallbackInfo<Value>& args);
|
||||
static void Read(const v8::FunctionCallbackInfo<Value>& args);
|
||||
static void Close(const v8::FunctionCallbackInfo<Value>& args);
|
||||
static void Open(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
inline uv_dir_t* dir() { return dir_; }
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackFieldWithSize("dir", sizeof(*dir_));
|
||||
}
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
SET_MEMORY_INFO_NAME(DirHandle)
|
||||
SET_SELF_SIZE(DirHandle)
|
||||
|
||||
|
||||
283
src/node_file-inl.h
Normal file
283
src/node_file-inl.h
Normal file
@@ -0,0 +1,283 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
std::string FSContinuationData::PopPath() {
|
||||
CHECK_GT(paths_.size(), 0);
|
||||
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(Environment* env,
|
||||
v8::Local<v8::Object> req,
|
||||
AsyncWrap::ProviderType type,
|
||||
bool use_bigint)
|
||||
: ReqWrap(env, req, type), use_bigint_(use_bigint) {
|
||||
}
|
||||
|
||||
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(Environment* env,
|
||||
v8::Local<v8::Object> req, bool use_bigint)
|
||||
: FSReqBase(env, 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(Environment* env,
|
||||
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 = env->fs_stats_field_bigint_array();
|
||||
FillStatsArray(arr, s, offset);
|
||||
return arr->GetJSArray();
|
||||
} else {
|
||||
auto* const arr = env->fs_stats_field_array();
|
||||
FillStatsArray(arr, s, offset);
|
||||
return arr->GetJSArray();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AliasedBufferT>
|
||||
FSReqPromise<AliasedBufferT>*
|
||||
FSReqPromise<AliasedBufferT>::New(Environment* env, bool use_bigint) {
|
||||
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(env, 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(
|
||||
Environment* env,
|
||||
v8::Local<v8::Object> obj,
|
||||
bool use_bigint)
|
||||
: FSReqBase(env, 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(Environment* env, v8::Local<v8::Value> value,
|
||||
bool use_bigint) {
|
||||
if (value->IsObject()) {
|
||||
return Unwrap<FSReqBase>(value.As<v8::Object>());
|
||||
} else if (value->StrictEquals(env->fs_use_promises_symbol())) {
|
||||
if (use_bigint) {
|
||||
return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
|
||||
} else {
|
||||
return FSReqPromise<AliasedFloat64Array>::New(env, 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_
|
||||
@@ -18,7 +18,8 @@
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include "node_file.h"
|
||||
#include "node_file.h" // NOLINT(build/include_inline)
|
||||
#include "node_file-inl.h"
|
||||
#include "aliased_buffer.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "node_buffer.h"
|
||||
@@ -107,6 +108,19 @@ inline int64_t GetOffset(Local<Value> value) {
|
||||
// functions, and thus does not wrap them properly.
|
||||
typedef void(*uv_fs_callback_t)(uv_fs_t*);
|
||||
|
||||
|
||||
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("paths", paths_);
|
||||
}
|
||||
|
||||
FileHandleReadWrap::~FileHandleReadWrap() {}
|
||||
|
||||
FSReqBase::~FSReqBase() {}
|
||||
|
||||
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("continuation_data", continuation_data_);
|
||||
}
|
||||
|
||||
// The FileHandle object wraps a file descriptor and will close it on garbage
|
||||
// collection if necessary. If that happens, a process warning will be
|
||||
// emitted (or a fatal exception will occur if the fd cannot be closed.)
|
||||
@@ -156,6 +170,16 @@ FileHandle::~FileHandle() {
|
||||
CHECK(closed_); // We have to be closed at the point
|
||||
}
|
||||
|
||||
int FileHandle::DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) {
|
||||
return UV_ENOSYS; // Not implemented (yet).
|
||||
}
|
||||
|
||||
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("current_read", current_read_);
|
||||
}
|
||||
|
||||
// Close the file descriptor if it hasn't already been closed. A process
|
||||
// warning will be emitted using a SetImmediate to avoid calling back to
|
||||
@@ -225,12 +249,34 @@ FileHandle* FileHandle::CloseReq::file_handle() {
|
||||
return Unwrap<FileHandle>(obj);
|
||||
}
|
||||
|
||||
FileHandle::CloseReq::CloseReq(Environment* env,
|
||||
Local<Object> obj,
|
||||
Local<Promise> promise,
|
||||
Local<Value> ref)
|
||||
: ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
|
||||
promise_.Reset(env->isolate(), promise);
|
||||
ref_.Reset(env->isolate(), ref);
|
||||
}
|
||||
|
||||
FileHandle::CloseReq::~CloseReq() {
|
||||
uv_fs_req_cleanup(req());
|
||||
promise_.Reset();
|
||||
ref_.Reset();
|
||||
}
|
||||
|
||||
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
|
||||
tracker->TrackField("promise", promise_);
|
||||
tracker->TrackField("ref", ref_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Closes this FileHandle asynchronously and returns a Promise that will be
|
||||
// resolved when the callback is invoked, or rejects with a UVException if
|
||||
// there was a problem closing the fd. This is the preferred mechanism for
|
||||
// closing the FD object even tho the object will attempt to close
|
||||
// automatically on gc.
|
||||
inline MaybeLocal<Promise> FileHandle::ClosePromise() {
|
||||
MaybeLocal<Promise> FileHandle::ClosePromise() {
|
||||
Isolate* isolate = env()->isolate();
|
||||
EscapableHandleScope scope(isolate);
|
||||
Local<Context> context = env()->context();
|
||||
@@ -1157,13 +1203,13 @@ int MKDirpSync(uv_loop_t* loop,
|
||||
FSContinuationData continuation_data(req, mode, cb);
|
||||
continuation_data.PushPath(std::move(path));
|
||||
|
||||
while (continuation_data.paths.size() > 0) {
|
||||
while (continuation_data.paths().size() > 0) {
|
||||
std::string next_path = continuation_data.PopPath();
|
||||
int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
|
||||
while (true) {
|
||||
switch (err) {
|
||||
case 0:
|
||||
if (continuation_data.paths.size() == 0) {
|
||||
if (continuation_data.paths().size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -1173,7 +1219,7 @@ int MKDirpSync(uv_loop_t* loop,
|
||||
if (dirname != next_path) {
|
||||
continuation_data.PushPath(std::move(next_path));
|
||||
continuation_data.PushPath(std::move(dirname));
|
||||
} else if (continuation_data.paths.size() == 0) {
|
||||
} else if (continuation_data.paths().size() == 0) {
|
||||
err = UV_EEXIST;
|
||||
continue;
|
||||
}
|
||||
@@ -1188,7 +1234,7 @@ int MKDirpSync(uv_loop_t* loop,
|
||||
err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
|
||||
if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
|
||||
uv_fs_req_cleanup(req);
|
||||
if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
|
||||
if (orig_err == UV_EEXIST && continuation_data.paths().size() > 0) {
|
||||
return UV_ENOTDIR;
|
||||
}
|
||||
return UV_EEXIST;
|
||||
@@ -1211,14 +1257,14 @@ int MKDirpAsync(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
FSReqBase* req_wrap = FSReqBase::from_req(req);
|
||||
// on the first iteration of algorithm, stash state information.
|
||||
if (req_wrap->continuation_data == nullptr) {
|
||||
req_wrap->continuation_data =
|
||||
std::make_unique<FSContinuationData>(req, mode, cb);
|
||||
req_wrap->continuation_data->PushPath(std::move(path));
|
||||
if (req_wrap->continuation_data() == nullptr) {
|
||||
req_wrap->set_continuation_data(
|
||||
std::make_unique<FSContinuationData>(req, mode, cb));
|
||||
req_wrap->continuation_data()->PushPath(std::move(path));
|
||||
}
|
||||
|
||||
// on each iteration of algorithm, mkdir directory on top of stack.
|
||||
std::string next_path = req_wrap->continuation_data->PopPath();
|
||||
std::string next_path = req_wrap->continuation_data()->PopPath();
|
||||
int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
|
||||
uv_fs_callback_t{[](uv_fs_t* req) {
|
||||
FSReqBase* req_wrap = FSReqBase::from_req(req);
|
||||
@@ -1230,12 +1276,12 @@ int MKDirpAsync(uv_loop_t* loop,
|
||||
while (true) {
|
||||
switch (err) {
|
||||
case 0: {
|
||||
if (req_wrap->continuation_data->paths.size() == 0) {
|
||||
req_wrap->continuation_data->Done(0);
|
||||
if (req_wrap->continuation_data()->paths().size() == 0) {
|
||||
req_wrap->continuation_data()->Done(0);
|
||||
} else {
|
||||
uv_fs_req_cleanup(req);
|
||||
MKDirpAsync(loop, req, path.c_str(),
|
||||
req_wrap->continuation_data->mode, nullptr);
|
||||
req_wrap->continuation_data()->mode(), nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1243,19 +1289,19 @@ int MKDirpAsync(uv_loop_t* loop,
|
||||
std::string dirname = path.substr(0,
|
||||
path.find_last_of(kPathSeparator));
|
||||
if (dirname != path) {
|
||||
req_wrap->continuation_data->PushPath(std::move(path));
|
||||
req_wrap->continuation_data->PushPath(std::move(dirname));
|
||||
} else if (req_wrap->continuation_data->paths.size() == 0) {
|
||||
req_wrap->continuation_data()->PushPath(std::move(path));
|
||||
req_wrap->continuation_data()->PushPath(std::move(dirname));
|
||||
} else if (req_wrap->continuation_data()->paths().size() == 0) {
|
||||
err = UV_EEXIST;
|
||||
continue;
|
||||
}
|
||||
uv_fs_req_cleanup(req);
|
||||
MKDirpAsync(loop, req, path.c_str(),
|
||||
req_wrap->continuation_data->mode, nullptr);
|
||||
req_wrap->continuation_data()->mode(), nullptr);
|
||||
break;
|
||||
}
|
||||
case UV_EPERM: {
|
||||
req_wrap->continuation_data->Done(err);
|
||||
req_wrap->continuation_data()->Done(err);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1267,14 +1313,14 @@ int MKDirpAsync(uv_loop_t* loop,
|
||||
FSReqBase* req_wrap = FSReqBase::from_req(req);
|
||||
int err = req->result;
|
||||
if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
|
||||
req_wrap->continuation_data->paths.size() > 0) {
|
||||
req_wrap->continuation_data()->paths().size() > 0) {
|
||||
if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
|
||||
Environment* env = req_wrap->env();
|
||||
uv_loop_t* loop = env->event_loop();
|
||||
std::string path = req->path;
|
||||
uv_fs_req_cleanup(req);
|
||||
MKDirpAsync(loop, req, path.c_str(),
|
||||
req_wrap->continuation_data->mode, nullptr);
|
||||
req_wrap->continuation_data()->mode(), nullptr);
|
||||
return;
|
||||
}
|
||||
err = UV_ENOTDIR;
|
||||
@@ -1282,9 +1328,9 @@ int MKDirpAsync(uv_loop_t* loop,
|
||||
// verify that the path pointed to is actually a directory.
|
||||
if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
|
||||
uv_fs_req_cleanup(req);
|
||||
req_wrap->continuation_data->Done(err);
|
||||
req_wrap->continuation_data()->Done(err);
|
||||
}});
|
||||
if (err < 0) req_wrap->continuation_data->Done(err);
|
||||
if (err < 0) req_wrap->continuation_data()->Done(err);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
376
src/node_file.h
376
src/node_file.h
@@ -6,113 +6,70 @@
|
||||
#include "node.h"
|
||||
#include "aliased_buffer.h"
|
||||
#include "stream_base.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "req_wrap-inl.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::Context;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::HandleScope;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::Object;
|
||||
using v8::Promise;
|
||||
using v8::Undefined;
|
||||
using v8::Value;
|
||||
|
||||
namespace fs {
|
||||
|
||||
// structure used to store state during a complex operation, e.g., mkdirp.
|
||||
class FSContinuationData : public MemoryRetainer {
|
||||
public:
|
||||
FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
|
||||
: req(req), mode(mode), done_cb(done_cb) {
|
||||
}
|
||||
inline FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb);
|
||||
|
||||
uv_fs_t* req;
|
||||
int mode;
|
||||
std::vector<std::string> paths{};
|
||||
inline void PushPath(std::string&& path);
|
||||
inline void PushPath(const std::string& path);
|
||||
inline std::string PopPath();
|
||||
inline void Done(int result);
|
||||
|
||||
void PushPath(std::string&& path) {
|
||||
paths.emplace_back(std::move(path));
|
||||
}
|
||||
|
||||
void PushPath(const std::string& path) {
|
||||
paths.push_back(path);
|
||||
}
|
||||
|
||||
std::string PopPath() {
|
||||
CHECK_GT(paths.size(), 0);
|
||||
std::string path = std::move(paths.back());
|
||||
paths.pop_back();
|
||||
return path;
|
||||
}
|
||||
|
||||
void Done(int result) {
|
||||
req->result = result;
|
||||
done_cb(req);
|
||||
}
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackField("paths", paths);
|
||||
}
|
||||
int mode() const { return mode_; }
|
||||
const std::vector<std::string>& paths() const { return paths_; }
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
SET_MEMORY_INFO_NAME(FSContinuationData)
|
||||
SET_SELF_SIZE(FSContinuationData)
|
||||
|
||||
private:
|
||||
uv_fs_cb done_cb;
|
||||
uv_fs_cb done_cb_;
|
||||
uv_fs_t* req_;
|
||||
int mode_;
|
||||
std::vector<std::string> paths_;
|
||||
};
|
||||
|
||||
class FSReqBase : public ReqWrap<uv_fs_t> {
|
||||
public:
|
||||
typedef MaybeStackBuffer<char, 64> FSReqBuffer;
|
||||
std::unique_ptr<FSContinuationData> continuation_data = nullptr;
|
||||
|
||||
FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
|
||||
bool use_bigint)
|
||||
: ReqWrap(env, req, type), use_bigint_(use_bigint) {
|
||||
}
|
||||
inline FSReqBase(Environment* env,
|
||||
v8::Local<v8::Object> req,
|
||||
AsyncWrap::ProviderType type,
|
||||
bool use_bigint);
|
||||
~FSReqBase() override;
|
||||
|
||||
void Init(const char* syscall,
|
||||
const char* data,
|
||||
size_t len,
|
||||
enum encoding encoding) {
|
||||
syscall_ = syscall;
|
||||
encoding_ = encoding;
|
||||
inline void Init(const char* syscall,
|
||||
const char* data,
|
||||
size_t len,
|
||||
enum encoding encoding);
|
||||
inline FSReqBuffer& Init(const char* syscall, size_t len,
|
||||
enum encoding encoding);
|
||||
|
||||
if (data != nullptr) {
|
||||
CHECK(!has_data_);
|
||||
buffer_.AllocateSufficientStorage(len + 1);
|
||||
buffer_.SetLengthAndZeroTerminate(len);
|
||||
memcpy(*buffer_, data, len);
|
||||
has_data_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
FSReqBuffer& 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_;
|
||||
}
|
||||
|
||||
virtual void Reject(Local<Value> reject) = 0;
|
||||
virtual void Resolve(Local<Value> value) = 0;
|
||||
virtual void Reject(v8::Local<v8::Value> reject) = 0;
|
||||
virtual void Resolve(v8::Local<v8::Value> value) = 0;
|
||||
virtual void ResolveStat(const uv_stat_t* stat) = 0;
|
||||
virtual void SetReturnValue(const FunctionCallbackInfo<Value>& args) = 0;
|
||||
virtual void SetReturnValue(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) = 0;
|
||||
|
||||
const char* syscall() const { return syscall_; }
|
||||
const char* data() const { return has_data_ ? *buffer_ : nullptr; }
|
||||
enum encoding encoding() const { return encoding_; }
|
||||
|
||||
bool use_bigint() const { return use_bigint_; }
|
||||
|
||||
FSContinuationData* continuation_data() const {
|
||||
return continuation_data_.get();
|
||||
}
|
||||
void set_continuation_data(std::unique_ptr<FSContinuationData> data) {
|
||||
continuation_data_ = std::move(data);
|
||||
}
|
||||
|
||||
static FSReqBase* from_req(uv_fs_t* req) {
|
||||
return static_cast<FSReqBase*>(ReqWrap::from_req(req));
|
||||
}
|
||||
@@ -120,7 +77,10 @@ class FSReqBase : public ReqWrap<uv_fs_t> {
|
||||
FSReqBase(const FSReqBase&) = delete;
|
||||
FSReqBase& operator=(const FSReqBase&) = delete;
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<FSContinuationData> continuation_data_;
|
||||
enum encoding encoding_ = UTF8;
|
||||
bool has_data_ = false;
|
||||
const char* syscall_ = nullptr;
|
||||
@@ -131,19 +91,16 @@ class FSReqBase : public ReqWrap<uv_fs_t> {
|
||||
FSReqBuffer buffer_;
|
||||
};
|
||||
|
||||
class FSReqCallback : public FSReqBase {
|
||||
class FSReqCallback final : public FSReqBase {
|
||||
public:
|
||||
FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
|
||||
: FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) { }
|
||||
inline FSReqCallback(Environment* env,
|
||||
v8::Local<v8::Object> req,
|
||||
bool use_bigint);
|
||||
|
||||
void Reject(Local<Value> reject) override;
|
||||
void Resolve(Local<Value> value) override;
|
||||
void Reject(v8::Local<v8::Value> reject) override;
|
||||
void Resolve(v8::Local<v8::Value> value) override;
|
||||
void ResolveStat(const uv_stat_t* stat) override;
|
||||
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackField("continuation_data", continuation_data);
|
||||
}
|
||||
void SetReturnValue(const v8::FunctionCallbackInfo<v8::Value>& args) override;
|
||||
|
||||
SET_MEMORY_INFO_NAME(FSReqCallback)
|
||||
SET_SELF_SIZE(FSReqCallback)
|
||||
@@ -153,120 +110,27 @@ class FSReqCallback : public FSReqBase {
|
||||
};
|
||||
|
||||
template <typename NativeT, typename V8T>
|
||||
constexpr void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
|
||||
const uv_stat_t* s,
|
||||
const size_t offset = 0) {
|
||||
#define SET_FIELD_WITH_STAT(stat_offset, stat) \
|
||||
fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \
|
||||
static_cast<NativeT>(stat))
|
||||
void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
|
||||
const uv_stat_t* s,
|
||||
const size_t offset = 0);
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
inline Local<Value> FillGlobalStatsArray(Environment* env,
|
||||
const bool use_bigint,
|
||||
const uv_stat_t* s,
|
||||
const bool second = false) {
|
||||
const ptrdiff_t offset =
|
||||
second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
|
||||
if (use_bigint) {
|
||||
auto* const arr = env->fs_stats_field_bigint_array();
|
||||
FillStatsArray(arr, s, offset);
|
||||
return arr->GetJSArray();
|
||||
} else {
|
||||
auto* const arr = env->fs_stats_field_array();
|
||||
FillStatsArray(arr, s, offset);
|
||||
return arr->GetJSArray();
|
||||
}
|
||||
}
|
||||
inline v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
|
||||
const bool use_bigint,
|
||||
const uv_stat_t* s,
|
||||
const bool second = false);
|
||||
|
||||
template <typename AliasedBufferT>
|
||||
class FSReqPromise : public FSReqBase {
|
||||
class FSReqPromise final : public FSReqBase {
|
||||
public:
|
||||
static FSReqPromise* New(Environment* env, bool use_bigint) {
|
||||
v8::Local<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(env, obj, use_bigint);
|
||||
}
|
||||
static inline FSReqPromise* New(Environment* env, bool use_bigint);
|
||||
inline ~FSReqPromise() override;
|
||||
|
||||
~FSReqPromise() override {
|
||||
// Validate that the promise was explicitly resolved or rejected.
|
||||
CHECK(finished_);
|
||||
}
|
||||
|
||||
void Reject(Local<Value> reject) override {
|
||||
finished_ = true;
|
||||
HandleScope scope(env()->isolate());
|
||||
InternalCallbackScope callback_scope(this);
|
||||
Local<Value> value =
|
||||
object()->Get(env()->context(),
|
||||
env()->promise_string()).ToLocalChecked();
|
||||
Local<Promise::Resolver> resolver = value.As<Promise::Resolver>();
|
||||
USE(resolver->Reject(env()->context(), reject).FromJust());
|
||||
}
|
||||
|
||||
void Resolve(Local<Value> value) override {
|
||||
finished_ = true;
|
||||
HandleScope scope(env()->isolate());
|
||||
InternalCallbackScope callback_scope(this);
|
||||
Local<Value> val =
|
||||
object()->Get(env()->context(),
|
||||
env()->promise_string()).ToLocalChecked();
|
||||
Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
|
||||
USE(resolver->Resolve(env()->context(), value).FromJust());
|
||||
}
|
||||
|
||||
void ResolveStat(const uv_stat_t* stat) override {
|
||||
FillStatsArray(&stats_field_array_, stat);
|
||||
Resolve(stats_field_array_.GetJSArray());
|
||||
}
|
||||
|
||||
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
|
||||
Local<Value> val =
|
||||
object()->Get(env()->context(),
|
||||
env()->promise_string()).ToLocalChecked();
|
||||
Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
|
||||
args.GetReturnValue().Set(resolver->GetPromise());
|
||||
}
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackField("stats_field_array", stats_field_array_);
|
||||
tracker->TrackField("continuation_data", continuation_data);
|
||||
}
|
||||
inline void Reject(v8::Local<v8::Value> reject) override;
|
||||
inline void Resolve(v8::Local<v8::Value> value) override;
|
||||
inline void ResolveStat(const uv_stat_t* stat) override;
|
||||
inline void SetReturnValue(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) override;
|
||||
inline void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
||||
SET_MEMORY_INFO_NAME(FSReqPromise)
|
||||
SET_SELF_SIZE(FSReqPromise)
|
||||
@@ -277,17 +141,15 @@ class FSReqPromise : public FSReqBase {
|
||||
FSReqPromise& operator=(const FSReqPromise&&) = delete;
|
||||
|
||||
private:
|
||||
FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint)
|
||||
: FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
|
||||
stats_field_array_(
|
||||
env->isolate(),
|
||||
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
|
||||
inline FSReqPromise(Environment* env,
|
||||
v8::Local<v8::Object> obj,
|
||||
bool use_bigint);
|
||||
|
||||
bool finished_ = false;
|
||||
AliasedBufferT stats_field_array_;
|
||||
};
|
||||
|
||||
class FSReqAfterScope {
|
||||
class FSReqAfterScope final {
|
||||
public:
|
||||
FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req);
|
||||
~FSReqAfterScope();
|
||||
@@ -304,17 +166,18 @@ class FSReqAfterScope {
|
||||
private:
|
||||
FSReqBase* wrap_ = nullptr;
|
||||
uv_fs_t* req_ = nullptr;
|
||||
HandleScope handle_scope_;
|
||||
Context::Scope context_scope_;
|
||||
v8::HandleScope handle_scope_;
|
||||
v8::Context::Scope context_scope_;
|
||||
};
|
||||
|
||||
class FileHandle;
|
||||
|
||||
// A request wrap specifically for uv_fs_read()s scheduled for reading
|
||||
// from a FileHandle.
|
||||
class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
|
||||
class FileHandleReadWrap final : public ReqWrap<uv_fs_t> {
|
||||
public:
|
||||
FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj);
|
||||
~FileHandleReadWrap() override;
|
||||
|
||||
static inline FileHandleReadWrap* from_req(uv_fs_t* req) {
|
||||
return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
|
||||
@@ -333,7 +196,7 @@ class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
|
||||
|
||||
// A wrapper for a file descriptor that will automatically close the fd when
|
||||
// the object is garbage collected
|
||||
class FileHandle : public AsyncWrap, public StreamBase {
|
||||
class FileHandle final : public AsyncWrap, public StreamBase {
|
||||
public:
|
||||
static FileHandle* New(Environment* env,
|
||||
int fd,
|
||||
@@ -346,10 +209,10 @@ class FileHandle : public AsyncWrap, public StreamBase {
|
||||
|
||||
// Will asynchronously close the FD and return a Promise that will
|
||||
// be resolved once closing is complete.
|
||||
static void Close(const FunctionCallbackInfo<Value>& args);
|
||||
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
// Releases ownership of the FD.
|
||||
static void ReleaseFD(const FunctionCallbackInfo<Value>& args);
|
||||
static void ReleaseFD(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
// StreamBase interface:
|
||||
int ReadStart() override;
|
||||
@@ -366,13 +229,9 @@ class FileHandle : public AsyncWrap, public StreamBase {
|
||||
int DoWrite(WriteWrap* w,
|
||||
uv_buf_t* bufs,
|
||||
size_t count,
|
||||
uv_stream_t* send_handle) override {
|
||||
return UV_ENOSYS; // Not implemented (yet).
|
||||
}
|
||||
uv_stream_t* send_handle) override;
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackField("current_read", current_read_);
|
||||
}
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
||||
SET_MEMORY_INFO_NAME(FileHandle)
|
||||
SET_SELF_SIZE(FileHandle)
|
||||
@@ -389,36 +248,24 @@ class FileHandle : public AsyncWrap, public StreamBase {
|
||||
void Close();
|
||||
void AfterClose();
|
||||
|
||||
class CloseReq : public ReqWrap<uv_fs_t> {
|
||||
class CloseReq final : public ReqWrap<uv_fs_t> {
|
||||
public:
|
||||
CloseReq(Environment* env,
|
||||
Local<Object> obj,
|
||||
Local<Promise> promise,
|
||||
Local<Value> ref)
|
||||
: ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
|
||||
promise_.Reset(env->isolate(), promise);
|
||||
ref_.Reset(env->isolate(), ref);
|
||||
}
|
||||
|
||||
~CloseReq() override {
|
||||
uv_fs_req_cleanup(req());
|
||||
promise_.Reset();
|
||||
ref_.Reset();
|
||||
}
|
||||
v8::Local<v8::Object> obj,
|
||||
v8::Local<v8::Promise> promise,
|
||||
v8::Local<v8::Value> ref);
|
||||
~CloseReq() override;
|
||||
|
||||
FileHandle* file_handle();
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||
tracker->TrackField("promise", promise_);
|
||||
tracker->TrackField("ref", ref_);
|
||||
}
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
||||
SET_MEMORY_INFO_NAME(CloseReq)
|
||||
SET_SELF_SIZE(CloseReq)
|
||||
|
||||
void Resolve();
|
||||
|
||||
void Reject(Local<Value> reason);
|
||||
void Reject(v8::Local<v8::Value> reason);
|
||||
|
||||
static CloseReq* from_req(uv_fs_t* req) {
|
||||
return static_cast<CloseReq*>(ReqWrap::from_req(req));
|
||||
@@ -430,12 +277,12 @@ class FileHandle : public AsyncWrap, public StreamBase {
|
||||
CloseReq& operator=(const CloseReq&&) = delete;
|
||||
|
||||
private:
|
||||
v8::Global<Promise> promise_{};
|
||||
v8::Global<Value> ref_{};
|
||||
v8::Global<v8::Promise> promise_{};
|
||||
v8::Global<v8::Value> ref_{};
|
||||
};
|
||||
|
||||
// Asynchronous close
|
||||
inline MaybeLocal<Promise> ClosePromise();
|
||||
v8::MaybeLocal<v8::Promise> ClosePromise();
|
||||
|
||||
int fd_;
|
||||
bool closing_ = false;
|
||||
@@ -467,53 +314,23 @@ class FSReqWrapSync {
|
||||
// that nullptr indicates a synchronous call, rather than a failure.
|
||||
// Failure conditions should be disambiguated and handled appropriately.
|
||||
inline FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
|
||||
bool use_bigint = false) {
|
||||
if (value->IsObject()) {
|
||||
return Unwrap<FSReqBase>(value.As<Object>());
|
||||
} else if (value->StrictEquals(env->fs_use_promises_symbol())) {
|
||||
if (use_bigint) {
|
||||
return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
|
||||
} else {
|
||||
return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
bool use_bigint = false);
|
||||
|
||||
// Returns nullptr if the operation fails from the start.
|
||||
template <typename Func, typename... Args>
|
||||
inline FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
|
||||
const v8::FunctionCallbackInfo<Value>& args,
|
||||
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;
|
||||
}
|
||||
Func fn, Args... fn_args);
|
||||
|
||||
// Returns nullptr if the operation fails from the start.
|
||||
template <typename Func, typename... Args>
|
||||
inline FSReqBase* AsyncCall(Environment* env,
|
||||
FSReqBase* req_wrap,
|
||||
const v8::FunctionCallbackInfo<Value>& args,
|
||||
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...);
|
||||
}
|
||||
uv_fs_cb after, Func fn, Args... fn_args);
|
||||
|
||||
// Template counterpart of SYNC_CALL, except that it only puts
|
||||
// the error number and the syscall in the context instead of
|
||||
@@ -522,22 +339,7 @@ inline FSReqBase* AsyncCall(Environment* env,
|
||||
template <typename Func, typename... Args>
|
||||
inline 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<Context> context = env->context();
|
||||
v8::Local<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;
|
||||
}
|
||||
Func fn, Args... args);
|
||||
|
||||
} // namespace fs
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "node_stat_watcher.h"
|
||||
#include "async_wrap-inl.h"
|
||||
#include "env.h"
|
||||
#include "node_file.h"
|
||||
#include "node_file-inl.h"
|
||||
#include "util-inl.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -120,7 +120,7 @@ struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> {
|
||||
using F = void(*)(ReqT* req, Args... args);
|
||||
|
||||
static void Wrapper(ReqT* req, Args... args) {
|
||||
ReqWrap<ReqT>* req_wrap = ContainerOf(&ReqWrap<ReqT>::req_, req);
|
||||
ReqWrap<ReqT>* req_wrap = ReqWrap<ReqT>::from_req(req);
|
||||
req_wrap->env()->DecreaseWaitingRequestCounter();
|
||||
F original_callback = reinterpret_cast<F>(req_wrap->original_callback_);
|
||||
original_callback(req, args...);
|
||||
|
||||
@@ -50,9 +50,10 @@ class ReqWrap : public AsyncWrap, public ReqWrapBase {
|
||||
|
||||
private:
|
||||
friend int GenDebugSymbols();
|
||||
template <typename ReqT, typename U>
|
||||
friend struct MakeLibuvRequestCallback;
|
||||
|
||||
// Adding `friend struct MakeLibuvRequestCallback` is not enough anymore
|
||||
// for some reason. Consider this private.
|
||||
public:
|
||||
typedef void (*callback_t)();
|
||||
callback_t original_callback_ = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user