1 #ifndef SRC_NODE_FILE_H_ 2 #define SRC_NODE_FILE_H_ 3 4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 5 6 #include "node.h" 7 #include "aliased_buffer.h" 8 #include "node_messaging.h" 9 #include "stream_base.h" 10 #include <iostream> 11 12 namespace node { 13 namespace fs { 14 15 class FileHandleReadWrap; 16 17 class BindingData : public BaseObject { 18 public: BindingData(Environment * env,v8::Local<v8::Object> wrap)19 explicit BindingData(Environment* env, v8::Local<v8::Object> wrap) 20 : BaseObject(env, wrap), 21 stats_field_array(env->isolate(), kFsStatsBufferLength), 22 stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {} 23 24 AliasedFloat64Array stats_field_array; 25 AliasedBigUint64Array stats_field_bigint_array; 26 27 std::vector<BaseObjectPtr<FileHandleReadWrap>> 28 file_handle_read_wrap_freelist; 29 30 static constexpr FastStringKey type_name { "fs" }; 31 32 void MemoryInfo(MemoryTracker* tracker) const override; 33 SET_SELF_SIZE(BindingData) 34 SET_MEMORY_INFO_NAME(BindingData) 35 }; 36 37 // structure used to store state during a complex operation, e.g., mkdirp. 38 class FSContinuationData : public MemoryRetainer { 39 public: 40 inline FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb); 41 42 inline void PushPath(std::string&& path); 43 inline void PushPath(const std::string& path); 44 inline std::string PopPath(); 45 // Used by mkdirp to track the first path created: 46 inline void MaybeSetFirstPath(const std::string& path); 47 inline void Done(int result); 48 mode()49 int mode() const { return mode_; } paths()50 const std::vector<std::string>& paths() const { return paths_; } first_path()51 const std::string& first_path() const { return first_path_; } 52 53 void MemoryInfo(MemoryTracker* tracker) const override; 54 SET_MEMORY_INFO_NAME(FSContinuationData) 55 SET_SELF_SIZE(FSContinuationData) 56 57 private: 58 uv_fs_cb done_cb_; 59 uv_fs_t* req_; 60 int mode_; 61 std::vector<std::string> paths_; 62 std::string first_path_; 63 }; 64 65 class FSReqBase : public ReqWrap<uv_fs_t> { 66 public: 67 typedef MaybeStackBuffer<char, 64> FSReqBuffer; 68 69 inline FSReqBase(BindingData* binding_data, 70 v8::Local<v8::Object> req, 71 AsyncWrap::ProviderType type, 72 bool use_bigint); 73 ~FSReqBase() override; 74 75 inline void Init(const char* syscall, 76 const char* data, 77 size_t len, 78 enum encoding encoding); 79 inline FSReqBuffer& Init(const char* syscall, size_t len, 80 enum encoding encoding); 81 82 virtual void Reject(v8::Local<v8::Value> reject) = 0; 83 virtual void Resolve(v8::Local<v8::Value> value) = 0; 84 virtual void ResolveStat(const uv_stat_t* stat) = 0; 85 virtual void SetReturnValue( 86 const v8::FunctionCallbackInfo<v8::Value>& args) = 0; 87 syscall()88 const char* syscall() const { return syscall_; } data()89 const char* data() const { return has_data_ ? *buffer_ : nullptr; } encoding()90 enum encoding encoding() const { return encoding_; } use_bigint()91 bool use_bigint() const { return use_bigint_; } is_plain_open()92 bool is_plain_open() const { return is_plain_open_; } 93 set_is_plain_open(bool value)94 void set_is_plain_open(bool value) { is_plain_open_ = value; } 95 continuation_data()96 FSContinuationData* continuation_data() const { 97 return continuation_data_.get(); 98 } set_continuation_data(std::unique_ptr<FSContinuationData> data)99 void set_continuation_data(std::unique_ptr<FSContinuationData> data) { 100 continuation_data_ = std::move(data); 101 } 102 from_req(uv_fs_t * req)103 static FSReqBase* from_req(uv_fs_t* req) { 104 return static_cast<FSReqBase*>(ReqWrap::from_req(req)); 105 } 106 107 FSReqBase(const FSReqBase&) = delete; 108 FSReqBase& operator=(const FSReqBase&) = delete; 109 110 void MemoryInfo(MemoryTracker* tracker) const override; 111 112 BindingData* binding_data(); 113 114 private: 115 std::unique_ptr<FSContinuationData> continuation_data_; 116 enum encoding encoding_ = UTF8; 117 bool has_data_ = false; 118 bool use_bigint_ = false; 119 bool is_plain_open_ = false; 120 const char* syscall_ = nullptr; 121 122 BaseObjectPtr<BindingData> binding_data_; 123 124 // Typically, the content of buffer_ is something like a file name, so 125 // something around 64 bytes should be enough. 126 FSReqBuffer buffer_; 127 }; 128 129 class FSReqCallback final : public FSReqBase { 130 public: 131 inline FSReqCallback(BindingData* binding_data, 132 v8::Local<v8::Object> req, 133 bool use_bigint); 134 135 void Reject(v8::Local<v8::Value> reject) override; 136 void Resolve(v8::Local<v8::Value> value) override; 137 void ResolveStat(const uv_stat_t* stat) override; 138 void SetReturnValue(const v8::FunctionCallbackInfo<v8::Value>& args) override; 139 140 SET_MEMORY_INFO_NAME(FSReqCallback) 141 SET_SELF_SIZE(FSReqCallback) 142 143 FSReqCallback(const FSReqCallback&) = delete; 144 FSReqCallback& operator=(const FSReqCallback&) = delete; 145 }; 146 147 template <typename NativeT, typename V8T> 148 void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields, 149 const uv_stat_t* s, 150 const size_t offset = 0); 151 152 inline v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data, 153 const bool use_bigint, 154 const uv_stat_t* s, 155 const bool second = false); 156 157 template <typename AliasedBufferT> 158 class FSReqPromise final : public FSReqBase { 159 public: 160 static inline FSReqPromise* New(BindingData* binding_data, 161 bool use_bigint); 162 inline ~FSReqPromise() override; 163 164 inline void Reject(v8::Local<v8::Value> reject) override; 165 inline void Resolve(v8::Local<v8::Value> value) override; 166 inline void ResolveStat(const uv_stat_t* stat) override; 167 inline void SetReturnValue( 168 const v8::FunctionCallbackInfo<v8::Value>& args) override; 169 inline void MemoryInfo(MemoryTracker* tracker) const override; 170 171 SET_MEMORY_INFO_NAME(FSReqPromise) 172 SET_SELF_SIZE(FSReqPromise) 173 174 FSReqPromise(const FSReqPromise&) = delete; 175 FSReqPromise& operator=(const FSReqPromise&) = delete; 176 FSReqPromise(const FSReqPromise&&) = delete; 177 FSReqPromise& operator=(const FSReqPromise&&) = delete; 178 179 private: 180 inline FSReqPromise(BindingData* binding_data, 181 v8::Local<v8::Object> obj, 182 bool use_bigint); 183 184 bool finished_ = false; 185 AliasedBufferT stats_field_array_; 186 }; 187 188 class FSReqAfterScope final { 189 public: 190 FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req); 191 ~FSReqAfterScope(); 192 void Clear(); 193 194 bool Proceed(); 195 196 void Reject(uv_fs_t* req); 197 198 FSReqAfterScope(const FSReqAfterScope&) = delete; 199 FSReqAfterScope& operator=(const FSReqAfterScope&) = delete; 200 FSReqAfterScope(const FSReqAfterScope&&) = delete; 201 FSReqAfterScope& operator=(const FSReqAfterScope&&) = delete; 202 203 private: 204 BaseObjectPtr<FSReqBase> wrap_; 205 uv_fs_t* req_ = nullptr; 206 v8::HandleScope handle_scope_; 207 v8::Context::Scope context_scope_; 208 }; 209 210 class FileHandle; 211 212 // A request wrap specifically for uv_fs_read()s scheduled for reading 213 // from a FileHandle. 214 class FileHandleReadWrap final : public ReqWrap<uv_fs_t> { 215 public: 216 FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj); 217 ~FileHandleReadWrap() override; 218 from_req(uv_fs_t * req)219 static inline FileHandleReadWrap* from_req(uv_fs_t* req) { 220 return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req)); 221 } 222 223 void MemoryInfo(MemoryTracker* tracker) const override; 224 SET_MEMORY_INFO_NAME(FileHandleReadWrap) 225 SET_SELF_SIZE(FileHandleReadWrap) 226 227 private: 228 FileHandle* file_handle_; 229 uv_buf_t buffer_; 230 231 friend class FileHandle; 232 }; 233 234 // A wrapper for a file descriptor that will automatically close the fd when 235 // the object is garbage collected 236 class FileHandle final : public AsyncWrap, public StreamBase { 237 public: 238 static FileHandle* New(BindingData* binding_data, 239 int fd, 240 v8::Local<v8::Object> obj = v8::Local<v8::Object>()); 241 ~FileHandle() override; 242 243 static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 244 GetFD()245 int GetFD() override { return fd_; } 246 247 // Will asynchronously close the FD and return a Promise that will 248 // be resolved once closing is complete. 249 static void Close(const v8::FunctionCallbackInfo<v8::Value>& args); 250 251 // Releases ownership of the FD. 252 static void ReleaseFD(const v8::FunctionCallbackInfo<v8::Value>& args); 253 254 // StreamBase interface: 255 int ReadStart() override; 256 int ReadStop() override; 257 IsAlive()258 bool IsAlive() override { return !closed_; } IsClosing()259 bool IsClosing() override { return closing_; } GetAsyncWrap()260 AsyncWrap* GetAsyncWrap() override { return this; } 261 262 // In the case of file streams, shutting down corresponds to closing. 263 ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override; 264 int DoShutdown(ShutdownWrap* req_wrap) override; 265 266 int DoWrite(WriteWrap* w, 267 uv_buf_t* bufs, 268 size_t count, 269 uv_stream_t* send_handle) override; 270 271 void MemoryInfo(MemoryTracker* tracker) const override; 272 273 SET_MEMORY_INFO_NAME(FileHandle) 274 SET_SELF_SIZE(FileHandle) 275 276 FileHandle(const FileHandle&) = delete; 277 FileHandle& operator=(const FileHandle&) = delete; 278 FileHandle(const FileHandle&&) = delete; 279 FileHandle& operator=(const FileHandle&&) = delete; 280 281 TransferMode GetTransferMode() const override; 282 std::unique_ptr<worker::TransferData> TransferForMessaging() override; 283 284 private: 285 class TransferData : public worker::TransferData { 286 public: 287 explicit TransferData(int fd); 288 ~TransferData(); 289 290 BaseObjectPtr<BaseObject> Deserialize( 291 Environment* env, 292 v8::Local<v8::Context> context, 293 std::unique_ptr<worker::TransferData> self) override; 294 295 SET_NO_MEMORY_INFO() 296 SET_MEMORY_INFO_NAME(FileHandleTransferData) 297 SET_SELF_SIZE(TransferData) 298 299 private: 300 int fd_; 301 }; 302 303 FileHandle(BindingData* binding_data, v8::Local<v8::Object> obj, int fd); 304 305 // Synchronous close that emits a warning 306 void Close(); 307 void AfterClose(); 308 309 class CloseReq final : public ReqWrap<uv_fs_t> { 310 public: 311 CloseReq(Environment* env, 312 v8::Local<v8::Object> obj, 313 v8::Local<v8::Promise> promise, 314 v8::Local<v8::Value> ref); 315 ~CloseReq() override; 316 317 FileHandle* file_handle(); 318 319 void MemoryInfo(MemoryTracker* tracker) const override; 320 321 SET_MEMORY_INFO_NAME(CloseReq) 322 SET_SELF_SIZE(CloseReq) 323 324 void Resolve(); 325 326 void Reject(v8::Local<v8::Value> reason); 327 from_req(uv_fs_t * req)328 static CloseReq* from_req(uv_fs_t* req) { 329 return static_cast<CloseReq*>(ReqWrap::from_req(req)); 330 } 331 332 CloseReq(const CloseReq&) = delete; 333 CloseReq& operator=(const CloseReq&) = delete; 334 CloseReq(const CloseReq&&) = delete; 335 CloseReq& operator=(const CloseReq&&) = delete; 336 337 private: 338 v8::Global<v8::Promise> promise_{}; 339 v8::Global<v8::Value> ref_{}; 340 }; 341 342 // Asynchronous close 343 v8::MaybeLocal<v8::Promise> ClosePromise(); 344 345 int fd_; 346 bool closing_ = false; 347 bool closed_ = false; 348 bool reading_ = false; 349 int64_t read_offset_ = -1; 350 int64_t read_length_ = -1; 351 352 BaseObjectPtr<FileHandleReadWrap> current_read_; 353 354 BaseObjectPtr<BindingData> binding_data_; 355 }; 356 357 int MKDirpSync(uv_loop_t* loop, 358 uv_fs_t* req, 359 const std::string& path, 360 int mode, 361 uv_fs_cb cb = nullptr); 362 363 class FSReqWrapSync { 364 public: 365 FSReqWrapSync() = default; ~FSReqWrapSync()366 ~FSReqWrapSync() { uv_fs_req_cleanup(&req); } 367 uv_fs_t req; 368 continuation_data()369 FSContinuationData* continuation_data() const { 370 return continuation_data_.get(); 371 } set_continuation_data(std::unique_ptr<FSContinuationData> data)372 void set_continuation_data(std::unique_ptr<FSContinuationData> data) { 373 continuation_data_ = std::move(data); 374 } 375 376 FSReqWrapSync(const FSReqWrapSync&) = delete; 377 FSReqWrapSync& operator=(const FSReqWrapSync&) = delete; 378 379 private: 380 std::unique_ptr<FSContinuationData> continuation_data_; 381 }; 382 383 // TODO(addaleax): Currently, callers check the return value and assume 384 // that nullptr indicates a synchronous call, rather than a failure. 385 // Failure conditions should be disambiguated and handled appropriately. 386 inline FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args, 387 int index, 388 bool use_bigint = false); 389 390 // Returns nullptr if the operation fails from the start. 391 template <typename Func, typename... Args> 392 inline FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap, 393 const v8::FunctionCallbackInfo<v8::Value>& args, 394 const char* syscall, const char* dest, 395 size_t len, enum encoding enc, uv_fs_cb after, 396 Func fn, Args... fn_args); 397 398 // Returns nullptr if the operation fails from the start. 399 template <typename Func, typename... Args> 400 inline FSReqBase* AsyncCall(Environment* env, 401 FSReqBase* req_wrap, 402 const v8::FunctionCallbackInfo<v8::Value>& args, 403 const char* syscall, enum encoding enc, 404 uv_fs_cb after, Func fn, Args... fn_args); 405 406 // Template counterpart of SYNC_CALL, except that it only puts 407 // the error number and the syscall in the context instead of 408 // creating an error in the C++ land. 409 // ctx must be checked using value->IsObject() before being passed. 410 template <typename Func, typename... Args> 411 inline int SyncCall(Environment* env, v8::Local<v8::Value> ctx, 412 FSReqWrapSync* req_wrap, const char* syscall, 413 Func fn, Args... args); 414 415 } // namespace fs 416 417 } // namespace node 418 419 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS 420 421 #endif // SRC_NODE_FILE_H_ 422