• 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 // structure used to store state during a complex operation, e.g., mkdirp.
16 class FSContinuationData : public MemoryRetainer {
17  public:
18   inline FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb);
19 
20   inline void PushPath(std::string&& path);
21   inline void PushPath(const std::string& path);
22   inline std::string PopPath();
23   // Used by mkdirp to track the first path created:
24   inline void MaybeSetFirstPath(const std::string& path);
25   inline void Done(int result);
26 
mode()27   int mode() const { return mode_; }
paths()28   const std::vector<std::string>& paths() const { return paths_; }
first_path()29   const std::string& first_path() const { return first_path_; }
30 
31   void MemoryInfo(MemoryTracker* tracker) const override;
32   SET_MEMORY_INFO_NAME(FSContinuationData)
33   SET_SELF_SIZE(FSContinuationData)
34 
35  private:
36   uv_fs_cb done_cb_;
37   uv_fs_t* req_;
38   int mode_;
39   std::vector<std::string> paths_;
40   std::string first_path_;
41 };
42 
43 class FSReqBase : public ReqWrap<uv_fs_t> {
44  public:
45   typedef MaybeStackBuffer<char, 64> FSReqBuffer;
46 
47   inline FSReqBase(Environment* env,
48                    v8::Local<v8::Object> req,
49                    AsyncWrap::ProviderType type,
50                    bool use_bigint);
51   ~FSReqBase() override;
52 
53   inline void Init(const char* syscall,
54                    const char* data,
55                    size_t len,
56                    enum encoding encoding);
57   inline FSReqBuffer& Init(const char* syscall, size_t len,
58                            enum encoding encoding);
59 
60   virtual void Reject(v8::Local<v8::Value> reject) = 0;
61   virtual void Resolve(v8::Local<v8::Value> value) = 0;
62   virtual void ResolveStat(const uv_stat_t* stat) = 0;
63   virtual void SetReturnValue(
64       const v8::FunctionCallbackInfo<v8::Value>& args) = 0;
65 
syscall()66   const char* syscall() const { return syscall_; }
data()67   const char* data() const { return has_data_ ? *buffer_ : nullptr; }
encoding()68   enum encoding encoding() const { return encoding_; }
use_bigint()69   bool use_bigint() const { return use_bigint_; }
is_plain_open()70   bool is_plain_open() const { return is_plain_open_; }
71 
set_is_plain_open(bool value)72   void set_is_plain_open(bool value) { is_plain_open_ = value; }
73 
continuation_data()74   FSContinuationData* continuation_data() const {
75     return continuation_data_.get();
76   }
set_continuation_data(std::unique_ptr<FSContinuationData> data)77   void set_continuation_data(std::unique_ptr<FSContinuationData> data) {
78     continuation_data_ = std::move(data);
79   }
80 
from_req(uv_fs_t * req)81   static FSReqBase* from_req(uv_fs_t* req) {
82     return static_cast<FSReqBase*>(ReqWrap::from_req(req));
83   }
84 
85   FSReqBase(const FSReqBase&) = delete;
86   FSReqBase& operator=(const FSReqBase&) = delete;
87 
88   void MemoryInfo(MemoryTracker* tracker) const override;
89 
90  private:
91   std::unique_ptr<FSContinuationData> continuation_data_;
92   enum encoding encoding_ = UTF8;
93   bool has_data_ = false;
94   bool use_bigint_ = false;
95   bool is_plain_open_ = false;
96   const char* syscall_ = nullptr;
97 
98   // Typically, the content of buffer_ is something like a file name, so
99   // something around 64 bytes should be enough.
100   FSReqBuffer buffer_;
101 };
102 
103 class FSReqCallback final : public FSReqBase {
104  public:
105   inline FSReqCallback(Environment* env,
106                        v8::Local<v8::Object> req,
107                        bool use_bigint);
108 
109   void Reject(v8::Local<v8::Value> reject) override;
110   void Resolve(v8::Local<v8::Value> value) override;
111   void ResolveStat(const uv_stat_t* stat) override;
112   void SetReturnValue(const v8::FunctionCallbackInfo<v8::Value>& args) override;
113 
114   SET_MEMORY_INFO_NAME(FSReqCallback)
115   SET_SELF_SIZE(FSReqCallback)
116 
117   FSReqCallback(const FSReqCallback&) = delete;
118   FSReqCallback& operator=(const FSReqCallback&) = delete;
119 };
120 
121 template <typename NativeT, typename V8T>
122 void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
123                     const uv_stat_t* s,
124                     const size_t offset = 0);
125 
126 inline v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
127                                                  const bool use_bigint,
128                                                  const uv_stat_t* s,
129                                                  const bool second = false);
130 
131 template <typename AliasedBufferT>
132 class FSReqPromise final : public FSReqBase {
133  public:
134   static inline FSReqPromise* New(Environment* env, bool use_bigint);
135   inline ~FSReqPromise() override;
136 
137   inline void Reject(v8::Local<v8::Value> reject) override;
138   inline void Resolve(v8::Local<v8::Value> value) override;
139   inline void ResolveStat(const uv_stat_t* stat) override;
140   inline void SetReturnValue(
141       const v8::FunctionCallbackInfo<v8::Value>& args) override;
142   inline void MemoryInfo(MemoryTracker* tracker) const override;
143 
144   SET_MEMORY_INFO_NAME(FSReqPromise)
145   SET_SELF_SIZE(FSReqPromise)
146 
147   FSReqPromise(const FSReqPromise&) = delete;
148   FSReqPromise& operator=(const FSReqPromise&) = delete;
149   FSReqPromise(const FSReqPromise&&) = delete;
150   FSReqPromise& operator=(const FSReqPromise&&) = delete;
151 
152  private:
153   inline FSReqPromise(Environment* env,
154                       v8::Local<v8::Object> obj,
155                       bool use_bigint);
156 
157   bool finished_ = false;
158   AliasedBufferT stats_field_array_;
159 };
160 
161 class FSReqAfterScope final {
162  public:
163   FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req);
164   ~FSReqAfterScope();
165   void Clear();
166 
167   bool Proceed();
168 
169   void Reject(uv_fs_t* req);
170 
171   FSReqAfterScope(const FSReqAfterScope&) = delete;
172   FSReqAfterScope& operator=(const FSReqAfterScope&) = delete;
173   FSReqAfterScope(const FSReqAfterScope&&) = delete;
174   FSReqAfterScope& operator=(const FSReqAfterScope&&) = delete;
175 
176  private:
177   BaseObjectPtr<FSReqBase> wrap_;
178   uv_fs_t* req_ = nullptr;
179   v8::HandleScope handle_scope_;
180   v8::Context::Scope context_scope_;
181 };
182 
183 class FileHandle;
184 
185 // A request wrap specifically for uv_fs_read()s scheduled for reading
186 // from a FileHandle.
187 class FileHandleReadWrap final : public ReqWrap<uv_fs_t> {
188  public:
189   FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj);
190   ~FileHandleReadWrap() override;
191 
from_req(uv_fs_t * req)192   static inline FileHandleReadWrap* from_req(uv_fs_t* req) {
193     return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
194   }
195 
196   void MemoryInfo(MemoryTracker* tracker) const override;
197   SET_MEMORY_INFO_NAME(FileHandleReadWrap)
198   SET_SELF_SIZE(FileHandleReadWrap)
199 
200  private:
201   FileHandle* file_handle_;
202   uv_buf_t buffer_;
203 
204   friend class FileHandle;
205 };
206 
207 // A wrapper for a file descriptor that will automatically close the fd when
208 // the object is garbage collected
209 class FileHandle final : public AsyncWrap, public StreamBase {
210  public:
211   static FileHandle* New(Environment* env,
212                          int fd,
213                          v8::Local<v8::Object> obj = v8::Local<v8::Object>());
214   ~FileHandle() override;
215 
216   static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
217 
GetFD()218   int GetFD() override { return fd_; }
219 
220   // Will asynchronously close the FD and return a Promise that will
221   // be resolved once closing is complete.
222   static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
223 
224   // Releases ownership of the FD.
225   static void ReleaseFD(const v8::FunctionCallbackInfo<v8::Value>& args);
226 
227   // StreamBase interface:
228   int ReadStart() override;
229   int ReadStop() override;
230 
IsAlive()231   bool IsAlive() override { return !closed_; }
IsClosing()232   bool IsClosing() override { return closing_; }
GetAsyncWrap()233   AsyncWrap* GetAsyncWrap() override { return this; }
234 
235   // In the case of file streams, shutting down corresponds to closing.
236   ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
237   int DoShutdown(ShutdownWrap* req_wrap) override;
238 
239   int DoWrite(WriteWrap* w,
240               uv_buf_t* bufs,
241               size_t count,
242               uv_stream_t* send_handle) override;
243 
244   void MemoryInfo(MemoryTracker* tracker) const override;
245 
246   SET_MEMORY_INFO_NAME(FileHandle)
247   SET_SELF_SIZE(FileHandle)
248 
249   FileHandle(const FileHandle&) = delete;
250   FileHandle& operator=(const FileHandle&) = delete;
251   FileHandle(const FileHandle&&) = delete;
252   FileHandle& operator=(const FileHandle&&) = delete;
253 
254   TransferMode GetTransferMode() const override;
255   std::unique_ptr<worker::TransferData> TransferForMessaging() override;
256 
257  private:
258   class TransferData : public worker::TransferData {
259    public:
260     explicit TransferData(int fd);
261     ~TransferData();
262 
263     BaseObjectPtr<BaseObject> Deserialize(
264         Environment* env,
265         v8::Local<v8::Context> context,
266         std::unique_ptr<worker::TransferData> self) override;
267 
268     SET_NO_MEMORY_INFO()
269     SET_MEMORY_INFO_NAME(FileHandleTransferData)
270     SET_SELF_SIZE(TransferData)
271 
272    private:
273     int fd_;
274   };
275 
276   FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd);
277 
278   // Synchronous close that emits a warning
279   void Close();
280   void AfterClose();
281 
282   class CloseReq final : public ReqWrap<uv_fs_t> {
283    public:
284     CloseReq(Environment* env,
285              v8::Local<v8::Object> obj,
286              v8::Local<v8::Promise> promise,
287              v8::Local<v8::Value> ref);
288     ~CloseReq() override;
289 
290     FileHandle* file_handle();
291 
292     void MemoryInfo(MemoryTracker* tracker) const override;
293 
294     SET_MEMORY_INFO_NAME(CloseReq)
295     SET_SELF_SIZE(CloseReq)
296 
297     void Resolve();
298 
299     void Reject(v8::Local<v8::Value> reason);
300 
from_req(uv_fs_t * req)301     static CloseReq* from_req(uv_fs_t* req) {
302       return static_cast<CloseReq*>(ReqWrap::from_req(req));
303     }
304 
305     CloseReq(const CloseReq&) = delete;
306     CloseReq& operator=(const CloseReq&) = delete;
307     CloseReq(const CloseReq&&) = delete;
308     CloseReq& operator=(const CloseReq&&) = delete;
309 
310    private:
311     v8::Global<v8::Promise> promise_{};
312     v8::Global<v8::Value> ref_{};
313   };
314 
315   // Asynchronous close
316   v8::MaybeLocal<v8::Promise> ClosePromise();
317 
318   int fd_;
319   bool closing_ = false;
320   bool closed_ = false;
321   int64_t read_offset_ = -1;
322   int64_t read_length_ = -1;
323 
324   bool reading_ = false;
325   std::unique_ptr<FileHandleReadWrap> current_read_ = nullptr;
326 };
327 
328 int MKDirpSync(uv_loop_t* loop,
329                uv_fs_t* req,
330                const std::string& path,
331                int mode,
332                uv_fs_cb cb = nullptr);
333 
334 class FSReqWrapSync {
335  public:
336   FSReqWrapSync() = default;
~FSReqWrapSync()337   ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
338   uv_fs_t req;
339 
continuation_data()340   FSContinuationData* continuation_data() const {
341     return continuation_data_.get();
342   }
set_continuation_data(std::unique_ptr<FSContinuationData> data)343   void set_continuation_data(std::unique_ptr<FSContinuationData> data) {
344     continuation_data_ = std::move(data);
345   }
346 
347   FSReqWrapSync(const FSReqWrapSync&) = delete;
348   FSReqWrapSync& operator=(const FSReqWrapSync&) = delete;
349 
350  private:
351   std::unique_ptr<FSContinuationData> continuation_data_;
352 };
353 
354 // TODO(addaleax): Currently, callers check the return value and assume
355 // that nullptr indicates a synchronous call, rather than a failure.
356 // Failure conditions should be disambiguated and handled appropriately.
357 inline FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
358                              bool use_bigint = false);
359 
360 // Returns nullptr if the operation fails from the start.
361 template <typename Func, typename... Args>
362 inline FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
363                                 const v8::FunctionCallbackInfo<v8::Value>& args,
364                                 const char* syscall, const char* dest,
365                                 size_t len, enum encoding enc, uv_fs_cb after,
366                                 Func fn, Args... fn_args);
367 
368 // Returns nullptr if the operation fails from the start.
369 template <typename Func, typename... Args>
370 inline FSReqBase* AsyncCall(Environment* env,
371                             FSReqBase* req_wrap,
372                             const v8::FunctionCallbackInfo<v8::Value>& args,
373                             const char* syscall, enum encoding enc,
374                             uv_fs_cb after, Func fn, Args... fn_args);
375 
376 // Template counterpart of SYNC_CALL, except that it only puts
377 // the error number and the syscall in the context instead of
378 // creating an error in the C++ land.
379 // ctx must be checked using value->IsObject() before being passed.
380 template <typename Func, typename... Args>
381 inline int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
382                     FSReqWrapSync* req_wrap, const char* syscall,
383                     Func fn, Args... args);
384 
385 }  // namespace fs
386 
387 }  // namespace node
388 
389 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
390 
391 #endif  // SRC_NODE_FILE_H_
392