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