• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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