GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_file.h Lines: 187 200 93.5 %
Date: 2019-10-08 22:34:21 Branches: 95 154 61.7 %

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 "node.h"
7
#include "aliased_buffer.h"
8
#include "stream_base.h"
9
#include "memory_tracker-inl.h"
10
#include "req_wrap-inl.h"
11
#include <iostream>
12
13
namespace node {
14
15
using v8::Context;
16
using v8::FunctionCallbackInfo;
17
using v8::HandleScope;
18
using v8::Local;
19
using v8::MaybeLocal;
20
using v8::Object;
21
using v8::Promise;
22
using v8::Undefined;
23
using v8::Value;
24
25
namespace fs {
26
27
// structure used to store state during a complex operation, e.g., mkdirp.
28
5133
class FSContinuationData : public MemoryRetainer {
29
 public:
30
5123
  FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
31
5123
      : req(req), mode(mode), done_cb(done_cb) {
32
5123
  }
33
34
  uv_fs_t* req;
35
  int mode;
36
  std::vector<std::string> paths{};
37
38
72
  void PushPath(std::string&& path) {
39
72
    paths.emplace_back(std::move(path));
40
72
  }
41
42
5113
  void PushPath(const std::string& path) {
43
5113
    paths.push_back(path);
44
5113
  }
45
46
5185
  std::string PopPath() {
47
5185
    CHECK_GT(paths.size(), 0);
48
5185
    std::string path = std::move(paths.back());
49
5185
    paths.pop_back();
50
5185
    return path;
51
  }
52
53
10
  void Done(int result) {
54
10
    req->result = result;
55
10
    done_cb(req);
56
10
  }
57
58
  void MemoryInfo(MemoryTracker* tracker) const override {
59
    tracker->TrackField("paths", paths);
60
  }
61
62
  SET_MEMORY_INFO_NAME(FSContinuationData)
63
  SET_SELF_SIZE(FSContinuationData)
64
65
 private:
66
  uv_fs_cb done_cb;
67
};
68
69
61134
class FSReqBase : public ReqWrap<uv_fs_t> {
70
 public:
71
  typedef MaybeStackBuffer<char, 64> FSReqBuffer;
72
  std::unique_ptr<FSContinuationData> continuation_data = nullptr;
73
74
61144
  FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
75
            bool use_bigint)
76
61144
      : ReqWrap(env, req, type), use_bigint_(use_bigint) {
77
61144
  }
78
79
60983
  void Init(const char* syscall,
80
            const char* data,
81
            size_t len,
82
            enum encoding encoding) {
83
60983
    syscall_ = syscall;
84
60983
    encoding_ = encoding;
85
86
60983
    if (data != nullptr) {
87
363
      CHECK(!has_data_);
88
363
      buffer_.AllocateSufficientStorage(len + 1);
89
363
      buffer_.SetLengthAndZeroTerminate(len);
90
363
      memcpy(*buffer_, data, len);
91
363
      has_data_ = true;
92
    }
93
60983
  }
94
95
142
  FSReqBuffer& Init(const char* syscall, size_t len,
96
                    enum encoding encoding) {
97
142
    syscall_ = syscall;
98
142
    encoding_ = encoding;
99
100
142
    buffer_.AllocateSufficientStorage(len + 1);
101
142
    has_data_ = false;  // so that the data does not show up in error messages
102
142
    return buffer_;
103
  }
104
105
  virtual void Reject(Local<Value> reject) = 0;
106
  virtual void Resolve(Local<Value> value) = 0;
107
  virtual void ResolveStat(const uv_stat_t* stat) = 0;
108
  virtual void SetReturnValue(const FunctionCallbackInfo<Value>& args) = 0;
109
110
5091
  const char* syscall() const { return syscall_; }
111
5091
  const char* data() const { return has_data_ ? *buffer_ : nullptr; }
112
6002
  enum encoding encoding() const { return encoding_; }
113
114
5849
  bool use_bigint() const { return use_bigint_; }
115
116
61173
  static FSReqBase* from_req(uv_fs_t* req) {
117
61173
    return static_cast<FSReqBase*>(ReqWrap::from_req(req));
118
  }
119
120
  FSReqBase(const FSReqBase&) = delete;
121
  FSReqBase& operator=(const FSReqBase&) = delete;
122
123
 private:
124
  enum encoding encoding_ = UTF8;
125
  bool has_data_ = false;
126
  const char* syscall_ = nullptr;
127
  bool use_bigint_ = false;
128
129
  // Typically, the content of buffer_ is something like a file name, so
130
  // something around 64 bytes should be enough.
131
  FSReqBuffer buffer_;
132
};
133
134
119826
class FSReqCallback : public FSReqBase {
135
 public:
136
59923
  FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
137
59923
      : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) { }
138
139
  void Reject(Local<Value> reject) override;
140
  void Resolve(Local<Value> value) override;
141
  void ResolveStat(const uv_stat_t* stat) override;
142
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
143
144
1
  void MemoryInfo(MemoryTracker* tracker) const override {
145
1
    tracker->TrackField("continuation_data", continuation_data);
146
1
  }
147
148
1
  SET_MEMORY_INFO_NAME(FSReqCallback)
149
1
  SET_SELF_SIZE(FSReqCallback)
150
151
  FSReqCallback(const FSReqCallback&) = delete;
152
  FSReqCallback& operator=(const FSReqCallback&) = delete;
153
};
154
155
template <typename NativeT, typename V8T>
156
204396
constexpr void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
157
                              const uv_stat_t* s,
158
                              const size_t offset = 0) {
159
#define SET_FIELD_WITH_STAT(stat_offset, stat)                               \
160
  fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \
161
                   static_cast<NativeT>(stat))
162
163
#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat)                          \
164
  /* NOLINTNEXTLINE(runtime/int) */                                          \
165
  SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat))
166
167
204396
  SET_FIELD_WITH_STAT(kDev, s->st_dev);
168
204396
  SET_FIELD_WITH_STAT(kMode, s->st_mode);
169
204396
  SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
170
204396
  SET_FIELD_WITH_STAT(kUid, s->st_uid);
171
204396
  SET_FIELD_WITH_STAT(kGid, s->st_gid);
172
204396
  SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
173
204396
  SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
174
204396
  SET_FIELD_WITH_STAT(kIno, s->st_ino);
175
204396
  SET_FIELD_WITH_STAT(kSize, s->st_size);
176
204396
  SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);
177
178
204396
  SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
179
204396
  SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
180
204396
  SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
181
204396
  SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
182
204396
  SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
183
204396
  SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
184
204396
  SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
185
204396
  SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec);
186
187
#undef SET_FIELD_WITH_TIME_STAT
188
#undef SET_FIELD_WITH_STAT
189
204396
}
190
191
204081
inline Local<Value> FillGlobalStatsArray(Environment* env,
192
                                         const bool use_bigint,
193
                                         const uv_stat_t* s,
194
                                         const bool second = false) {
195
  const ptrdiff_t offset =
196
204081
      second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
197
204081
  if (use_bigint) {
198
10
    auto* const arr = env->fs_stats_field_bigint_array();
199
10
    FillStatsArray(arr, s, offset);
200
20
    return arr->GetJSArray();
201
  } else {
202
204071
    auto* const arr = env->fs_stats_field_array();
203
204071
    FillStatsArray(arr, s, offset);
204
408142
    return arr->GetJSArray();
205
  }
206
}
207
208
template <typename AliasedBufferT>
209
class FSReqPromise : public FSReqBase {
210
 public:
211
1221
  static FSReqPromise* New(Environment* env, bool use_bigint) {
212
    v8::Local<Object> obj;
213

2442
    if (!env->fsreqpromise_constructor_template()
214
3663
             ->NewInstance(env->context())
215
3663
             .ToLocal(&obj)) {
216
      return nullptr;
217
    }
218
    v8::Local<v8::Promise::Resolver> resolver;
219




6105
    if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
220



6105
        obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
221
      return nullptr;
222
    }
223
1221
    return new FSReqPromise(env, obj, use_bigint);
224
  }
225
226
2442
  ~FSReqPromise() override {
227
    // Validate that the promise was explicitly resolved or rejected.
228

1221
    CHECK(finished_);
229

3663
  }
230
231
77
  void Reject(Local<Value> reject) override {
232
77
    finished_ = true;
233
77
    HandleScope scope(env()->isolate());
234
154
    InternalCallbackScope callback_scope(this);
235
    Local<Value> value =
236
77
        object()->Get(env()->context(),
237
385
                      env()->promise_string()).ToLocalChecked();
238
77
    Local<Promise::Resolver> resolver = value.As<Promise::Resolver>();
239
308
    USE(resolver->Reject(env()->context(), reject).FromJust());
240
77
  }
241
242
1144
  void Resolve(Local<Value> value) override {
243
1144
    finished_ = true;
244
1144
    HandleScope scope(env()->isolate());
245
2288
    InternalCallbackScope callback_scope(this);
246
    Local<Value> val =
247
1144
        object()->Get(env()->context(),
248
5720
                      env()->promise_string()).ToLocalChecked();
249
1144
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
250
4576
    USE(resolver->Resolve(env()->context(), value).FromJust());
251
1144
  }
252
253
315
  void ResolveStat(const uv_stat_t* stat) override {
254
315
    FillStatsArray(&stats_field_array_, stat);
255
630
    Resolve(stats_field_array_.GetJSArray());
256
315
  }
257
258
1221
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
259
    Local<Value> val =
260
1221
        object()->Get(env()->context(),
261
6105
                      env()->promise_string()).ToLocalChecked();
262
1221
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
263
3663
    args.GetReturnValue().Set(resolver->GetPromise());
264
1221
  }
265
266
3
  void MemoryInfo(MemoryTracker* tracker) const override {
267
3
    tracker->TrackField("stats_field_array", stats_field_array_);
268
3
    tracker->TrackField("continuation_data", continuation_data);
269
3
  }
270
271
3
  SET_MEMORY_INFO_NAME(FSReqPromise)
272
3
  SET_SELF_SIZE(FSReqPromise)
273
274
  FSReqPromise(const FSReqPromise&) = delete;
275
  FSReqPromise& operator=(const FSReqPromise&) = delete;
276
  FSReqPromise(const FSReqPromise&&) = delete;
277
  FSReqPromise& operator=(const FSReqPromise&&) = delete;
278
279
 private:
280
1221
  FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint)
281
      : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
282
        stats_field_array_(
283
            env->isolate(),
284
1221
            static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
285
286
  bool finished_ = false;
287
  AliasedBufferT stats_field_array_;
288
};
289
290
class FSReqAfterScope {
291
 public:
292
  FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req);
293
  ~FSReqAfterScope();
294
295
  bool Proceed();
296
297
  void Reject(uv_fs_t* req);
298
299
  FSReqAfterScope(const FSReqAfterScope&) = delete;
300
  FSReqAfterScope& operator=(const FSReqAfterScope&) = delete;
301
  FSReqAfterScope(const FSReqAfterScope&&) = delete;
302
  FSReqAfterScope& operator=(const FSReqAfterScope&&) = delete;
303
304
 private:
305
  FSReqBase* wrap_ = nullptr;
306
  uv_fs_t* req_ = nullptr;
307
  HandleScope handle_scope_;
308
  Context::Scope context_scope_;
309
};
310
311
class FileHandle;
312
313
// A request wrap specifically for uv_fs_read()s scheduled for reading
314
// from a FileHandle.
315
30
class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
316
 public:
317
  FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj);
318
319
221
  static inline FileHandleReadWrap* from_req(uv_fs_t* req) {
320
221
    return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
321
  }
322
323
  void MemoryInfo(MemoryTracker* tracker) const override;
324
2
  SET_MEMORY_INFO_NAME(FileHandleReadWrap)
325
2
  SET_SELF_SIZE(FileHandleReadWrap)
326
327
 private:
328
  FileHandle* file_handle_;
329
  uv_buf_t buffer_;
330
331
  friend class FileHandle;
332
};
333
334
// A wrapper for a file descriptor that will automatically close the fd when
335
// the object is garbage collected
336
class FileHandle : public AsyncWrap, public StreamBase {
337
 public:
338
  static FileHandle* New(Environment* env,
339
                         int fd,
340
                         v8::Local<v8::Object> obj = v8::Local<v8::Object>());
341
  ~FileHandle() override;
342
343
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
344
345
  int fd() const { return fd_; }
346
347
  // Will asynchronously close the FD and return a Promise that will
348
  // be resolved once closing is complete.
349
  static void Close(const FunctionCallbackInfo<Value>& args);
350
351
  // Releases ownership of the FD.
352
  static void ReleaseFD(const FunctionCallbackInfo<Value>& args);
353
354
  // StreamBase interface:
355
  int ReadStart() override;
356
  int ReadStop() override;
357
358
227
  bool IsAlive() override { return !closed_; }
359
227
  bool IsClosing() override { return closing_; }
360
313
  AsyncWrap* GetAsyncWrap() override { return this; }
361
362
  // In the case of file streams, shutting down corresponds to closing.
363
  ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
364
  int DoShutdown(ShutdownWrap* req_wrap) override;
365
366
  int DoWrite(WriteWrap* w,
367
              uv_buf_t* bufs,
368
              size_t count,
369
              uv_stream_t* send_handle) override {
370
    return UV_ENOSYS;  // Not implemented (yet).
371
  }
372
373
2
  void MemoryInfo(MemoryTracker* tracker) const override {
374
2
    tracker->TrackField("current_read", current_read_);
375
2
  }
376
377
2
  SET_MEMORY_INFO_NAME(FileHandle)
378
2
  SET_SELF_SIZE(FileHandle)
379
380
  FileHandle(const FileHandle&) = delete;
381
  FileHandle& operator=(const FileHandle&) = delete;
382
  FileHandle(const FileHandle&&) = delete;
383
  FileHandle& operator=(const FileHandle&&) = delete;
384
385
 private:
386
  FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd);
387
388
  // Synchronous close that emits a warning
389
  void Close();
390
  void AfterClose();
391
392
  class CloseReq : public ReqWrap<uv_fs_t> {
393
   public:
394
256
    CloseReq(Environment* env,
395
             Local<Object> obj,
396
             Local<Promise> promise,
397
             Local<Value> ref)
398
512
        : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
399
256
      promise_.Reset(env->isolate(), promise);
400
256
      ref_.Reset(env->isolate(), ref);
401
256
    }
402
403
1280
    ~CloseReq() override {
404
256
      uv_fs_req_cleanup(req());
405
256
      promise_.Reset();
406
256
      ref_.Reset();
407
512
    }
408
409
    FileHandle* file_handle();
410
411
    void MemoryInfo(MemoryTracker* tracker) const override {
412
      tracker->TrackField("promise", promise_);
413
      tracker->TrackField("ref", ref_);
414
    }
415
416
    SET_MEMORY_INFO_NAME(CloseReq)
417
    SET_SELF_SIZE(CloseReq)
418
419
    void Resolve();
420
421
    void Reject(Local<Value> reason);
422
423
256
    static CloseReq* from_req(uv_fs_t* req) {
424
256
      return static_cast<CloseReq*>(ReqWrap::from_req(req));
425
    }
426
427
    CloseReq(const CloseReq&) = delete;
428
    CloseReq& operator=(const CloseReq&) = delete;
429
    CloseReq(const CloseReq&&) = delete;
430
    CloseReq& operator=(const CloseReq&&) = delete;
431
432
   private:
433
    v8::Global<Promise> promise_{};
434
    v8::Global<Value> ref_{};
435
  };
436
437
  // Asynchronous close
438
  inline MaybeLocal<Promise> ClosePromise();
439
440
  int fd_;
441
  bool closing_ = false;
442
  bool closed_ = false;
443
  int64_t read_offset_ = -1;
444
  int64_t read_length_ = -1;
445
446
  bool reading_ = false;
447
  std::unique_ptr<FileHandleReadWrap> current_read_ = nullptr;
448
};
449
450
int MKDirpSync(uv_loop_t* loop,
451
               uv_fs_t* req,
452
               const std::string& path,
453
               int mode,
454
               uv_fs_cb cb = nullptr);
455
456
class FSReqWrapSync {
457
 public:
458
593326
  FSReqWrapSync() = default;
459
593326
  ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
460
  uv_fs_t req;
461
462
  FSReqWrapSync(const FSReqWrapSync&) = delete;
463
  FSReqWrapSync& operator=(const FSReqWrapSync&) = delete;
464
};
465
466
// TODO(addaleax): Currently, callers check the return value and assume
467
// that nullptr indicates a synchronous call, rather than a failure.
468
// Failure conditions should be disambiguated and handled appropriately.
469
654451
inline FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
470
                             bool use_bigint = false) {
471
654451
  if (value->IsObject()) {
472
59904
    return Unwrap<FSReqBase>(value.As<Object>());
473
1189094
  } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
474
1221
    if (use_bigint) {
475
3
      return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
476
    } else {
477
1218
      return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
478
    }
479
  }
480
593326
  return nullptr;
481
}
482
483
// Returns nullptr if the operation fails from the start.
484
template <typename Func, typename... Args>
485
60983
inline FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
486
                                const v8::FunctionCallbackInfo<Value>& args,
487
                                const char* syscall, const char* dest,
488
                                size_t len, enum encoding enc, uv_fs_cb after,
489
                                Func fn, Args... fn_args) {
490







60983
  CHECK_NOT_NULL(req_wrap);
491
60983
  req_wrap->Init(syscall, dest, len, enc);
492
60983
  int err = req_wrap->Dispatch(fn, fn_args..., after);
493







60983
  if (err < 0) {
494
1
    uv_fs_t* uv_req = req_wrap->req();
495
1
    uv_req->result = err;
496
1
    uv_req->path = nullptr;
497
1
    after(uv_req);  // after may delete req_wrap if there is an error
498
1
    req_wrap = nullptr;
499
  } else {
500
60982
    req_wrap->SetReturnValue(args);
501
  }
502
503
60983
  return req_wrap;
504
}
505
506
// Returns nullptr if the operation fails from the start.
507
template <typename Func, typename... Args>
508
60620
inline FSReqBase* AsyncCall(Environment* env,
509
                            FSReqBase* req_wrap,
510
                            const v8::FunctionCallbackInfo<Value>& args,
511
                            const char* syscall, enum encoding enc,
512
                            uv_fs_cb after, Func fn, Args... fn_args) {
513
  return AsyncDestCall(env, req_wrap, args,
514
                       syscall, nullptr, 0, enc,
515
60620
                       after, fn, fn_args...);
516
}
517
518
// Template counterpart of SYNC_CALL, except that it only puts
519
// the error number and the syscall in the context instead of
520
// creating an error in the C++ land.
521
// ctx must be checked using value->IsObject() before being passed.
522
template <typename Func, typename... Args>
523
593326
inline int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
524
                    FSReqWrapSync* req_wrap, const char* syscall,
525
                    Func fn, Args... args) {
526
593326
  env->PrintSyncTrace();
527
593326
  int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
528







593326
  if (err < 0) {
529
8201
    v8::Local<Context> context = env->context();
530
8201
    v8::Local<Object> ctx_obj = ctx.As<v8::Object>();
531
8201
    v8::Isolate* isolate = env->isolate();
532
    ctx_obj->Set(context,
533
                 env->errno_string(),
534
32804
                 v8::Integer::New(isolate, err)).Check();
535
    ctx_obj->Set(context,
536
                 env->syscall_string(),
537
32804
                 OneByteString(isolate, syscall)).Check();
538
  }
539
593326
  return err;
540
}
541
542
}  // namespace fs
543
544
}  // namespace node
545
546
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
547
548
#endif  // SRC_NODE_FILE_H_