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