GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.h Lines: 41 52 78.8 %
Date: 2022-12-31 04:22:30 Branches: 2 2 100.0 %

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