• 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;
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