#ifndef SRC_NODE_FILE_H_ #define SRC_NODE_FILE_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "node.h" #include "req_wrap-inl.h" 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 { class FSReqBase : public ReqWrap { public: FSReqBase(Environment* env, Local req, AsyncWrap::ProviderType type) : ReqWrap(env, req, type) { Wrap(object(), this); } virtual ~FSReqBase() { ClearWrap(object()); } void Init(const char* syscall, const char* data = nullptr, size_t len = 0, enum encoding encoding = UTF8) { syscall_ = syscall; encoding_ = encoding; if (data != nullptr) { CHECK_EQ(data_, nullptr); buffer_.AllocateSufficientStorage(len + 1); buffer_.SetLengthAndZeroTerminate(len); memcpy(*buffer_, data, len); data_ = *buffer_; } } virtual void FillStatsArray(const uv_stat_t* stat) = 0; virtual void Reject(Local reject) = 0; virtual void Resolve(Local value) = 0; virtual void ResolveStat() = 0; virtual void SetReturnValue(const FunctionCallbackInfo& args) = 0; const char* syscall() const { return syscall_; } const char* data() const { return data_; } enum encoding encoding() const { return encoding_; } size_t self_size() const override { return sizeof(*this); } private: enum encoding encoding_ = UTF8; const char* syscall_ = nullptr; const char* data_ = nullptr; MaybeStackBuffer buffer_; DISALLOW_COPY_AND_ASSIGN(FSReqBase); }; class FSReqWrap : public FSReqBase { public: FSReqWrap(Environment* env, Local req) : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQWRAP) { } void FillStatsArray(const uv_stat_t* stat) override; void Reject(Local reject) override; void Resolve(Local value) override; void ResolveStat() override; void SetReturnValue(const FunctionCallbackInfo& args) override; private: DISALLOW_COPY_AND_ASSIGN(FSReqWrap); }; class FSReqPromise : public FSReqBase { public: explicit FSReqPromise(Environment* env); ~FSReqPromise() override; void FillStatsArray(const uv_stat_t* stat) override; void Reject(Local reject) override; void Resolve(Local value) override; void ResolveStat() override; void SetReturnValue(const FunctionCallbackInfo& args) override; private: bool finished_ = false; AliasedBuffer stats_field_array_; DISALLOW_COPY_AND_ASSIGN(FSReqPromise); }; class FSReqAfterScope { public: FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req); ~FSReqAfterScope(); bool Proceed(); void Reject(uv_fs_t* req); private: FSReqBase* wrap_ = nullptr; uv_fs_t* req_ = nullptr; HandleScope handle_scope_; Context::Scope context_scope_; }; // A wrapper for a file descriptor that will automatically close the fd when // the object is garbage collected class FileHandle : public AsyncWrap { public: FileHandle(Environment* env, int fd); virtual ~FileHandle(); int fd() const { return fd_; } size_t self_size() const override { return sizeof(*this); } // Will asynchronously close the FD and return a Promise that will // be resolved once closing is complete. static void Close(const FunctionCallbackInfo& args); private: // Synchronous close that emits a warning inline void Close(); class CloseReq : public ReqWrap { public: CloseReq(Environment* env, Local promise, Local ref) : ReqWrap(env, env->fdclose_constructor_template() ->NewInstance(env->context()).ToLocalChecked(), AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) { Wrap(object(), this); promise_.Reset(env->isolate(), promise); ref_.Reset(env->isolate(), ref); } ~CloseReq() { uv_fs_req_cleanup(req()); promise_.Reset(); ref_.Reset(); } FileHandle* file_handle(); size_t self_size() const override { return sizeof(*this); } void Resolve(); void Reject(Local reason); private: Persistent promise_; Persistent ref_; }; // Asynchronous close inline MaybeLocal ClosePromise(); int fd_; bool closing_ = false; bool closed_ = false; DISALLOW_COPY_AND_ASSIGN(FileHandle); }; } // namespace fs } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_NODE_FILE_H_