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