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: 161 174 92.5 %
Date: 2019-05-05 22:32:45 Branches: 35 62 56.5 %

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 "stream_base.h"
8
#include "req_wrap-inl.h"
9
10
namespace node {
11
12
using v8::Context;
13
using v8::FunctionCallbackInfo;
14
using v8::HandleScope;
15
using v8::Local;
16
using v8::MaybeLocal;
17
using v8::Object;
18
using v8::Promise;
19
using v8::Undefined;
20
using v8::Value;
21
22
namespace fs {
23
24
// structure used to store state during a complex operation, e.g., mkdirp.
25
4494
class FSContinuationData : public MemoryRetainer {
26
 public:
27
4484
  FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
28
4484
      : req(req), mode(mode), done_cb(done_cb) {
29
4484
  }
30
31
  uv_fs_t* req;
32
  int mode;
33
  std::vector<std::string> paths{};
34
35
36
  void PushPath(std::string&& path) {
36
36
    paths.emplace_back(std::move(path));
37
36
  }
38
39
4474
  void PushPath(const std::string& path) {
40
4474
    paths.push_back(path);
41
4474
  }
42
43
4510
  std::string PopPath() {
44
4510
    CHECK_GT(paths.size(), 0);
45
4510
    std::string path = std::move(paths.back());
46
4510
    paths.pop_back();
47
4510
    return path;
48
  }
49
50
10
  void Done(int result) {
51
10
    req->result = result;
52
10
    done_cb(req);
53
10
  }
54
55
  void MemoryInfo(MemoryTracker* tracker) const override {
56
    tracker->TrackField("paths", paths);
57
  }
58
59
  SET_MEMORY_INFO_NAME(FSContinuationData)
60
  SET_SELF_SIZE(FSContinuationData)
61
62
 private:
63
  uv_fs_cb done_cb;
64
};
65
66
58872
class FSReqBase : public ReqWrap<uv_fs_t> {
67
 public:
68
  typedef MaybeStackBuffer<char, 64> FSReqBuffer;
69
  std::unique_ptr<FSContinuationData> continuation_data = nullptr;
70
71
58880
  FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
72
            bool use_bigint)
73
58880
      : ReqWrap(env, req, type), use_bigint_(use_bigint) {
74
58880
  }
75
76
58701
  void Init(const char* syscall,
77
            const char* data,
78
            size_t len,
79
            enum encoding encoding) {
80
58701
    syscall_ = syscall;
81
58701
    encoding_ = encoding;
82
83
58701
    if (data != nullptr) {
84
425
      CHECK(!has_data_);
85
425
      buffer_.AllocateSufficientStorage(len + 1);
86
425
      buffer_.SetLengthAndZeroTerminate(len);
87
425
      memcpy(*buffer_, data, len);
88
425
      has_data_ = true;
89
    }
90
58701
  }
91
92
161
  FSReqBuffer& Init(const char* syscall, size_t len,
93
                    enum encoding encoding) {
94
161
    syscall_ = syscall;
95
161
    encoding_ = encoding;
96
97
161
    buffer_.AllocateSufficientStorage(len + 1);
98
161
    has_data_ = false;  // so that the data does not show up in error messages
99
161
    return buffer_;
100
  }
101
102
  virtual void Reject(Local<Value> reject) = 0;
103
  virtual void Resolve(Local<Value> value) = 0;
104
  virtual void ResolveStat(const uv_stat_t* stat) = 0;
105
  virtual void SetReturnValue(const FunctionCallbackInfo<Value>& args) = 0;
106
107
5076
  const char* syscall() const { return syscall_; }
108
5076
  const char* data() const { return has_data_ ? *buffer_ : nullptr; }
109
5906
  enum encoding encoding() const { return encoding_; }
110
111
6357
  bool use_bigint() const { return use_bigint_; }
112
113
58910
  static FSReqBase* from_req(uv_fs_t* req) {
114
58910
    return static_cast<FSReqBase*>(ReqWrap::from_req(req));
115
  }
116
117
  FSReqBase(const FSReqBase&) = delete;
118
  FSReqBase& operator=(const FSReqBase&) = delete;
119
120
 private:
121
  enum encoding encoding_ = UTF8;
122
  bool has_data_ = false;
123
  const char* syscall_ = nullptr;
124
  bool use_bigint_ = false;
125
126
  // Typically, the content of buffer_ is something like a file name, so
127
  // something around 64 bytes should be enough.
128
  FSReqBuffer buffer_;
129
};
130
131
117050
class FSReqCallback : public FSReqBase {
132
 public:
133
58533
  FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
134
58533
      : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) { }
135
136
  void Reject(Local<Value> reject) override;
137
  void Resolve(Local<Value> value) override;
138
  void ResolveStat(const uv_stat_t* stat) override;
139
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
140
141
1
  void MemoryInfo(MemoryTracker* tracker) const override {
142
1
    tracker->TrackField("continuation_data", continuation_data);
143
1
  }
144
145
1
  SET_MEMORY_INFO_NAME(FSReqCallback)
146
1
  SET_SELF_SIZE(FSReqCallback)
147
148
  FSReqCallback(const FSReqCallback&) = delete;
149
  FSReqCallback& operator=(const FSReqCallback&) = delete;
150
};
151
152
// Wordaround a GCC4.9 bug that C++14 N3652 was not implemented
153
// Refs: https://www.gnu.org/software/gcc/projects/cxx-status.html#cxx14
154
// Refs: https://isocpp.org/files/papers/N3652.html
155
#if __cpp_constexpr < 201304
156
#  define constexpr inline
157
#endif
158
159
template <typename NativeT,
160
          // SFINAE limit NativeT to arithmetic types
161
          typename = std::enable_if<std::is_arithmetic<NativeT>::value>>
162
constexpr NativeT ToNative(uv_timespec_t ts) {
163
  // This template has exactly two specializations below.
164
  static_assert(std::is_arithmetic<NativeT>::value == false, "Not implemented");
165
  UNREACHABLE();
166
}
167
168
template <>
169
820292
constexpr double ToNative(uv_timespec_t ts) {
170
  // We need to do a static_cast since the original FS values are ulong.
171
  /* NOLINTNEXTLINE(runtime/int) */
172
820292
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
173
820292
  const double full_sec = u_sec * 1000.0;
174
  /* NOLINTNEXTLINE(runtime/int) */
175
820292
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
176
820292
  const double full_nsec = u_nsec / 1000'000.0;
177
820292
  return full_sec + full_nsec;
178
}
179
180
template <>
181
52
constexpr uint64_t ToNative(uv_timespec_t ts) {
182
  // We need to do a static_cast since the original FS values are ulong.
183
  /* NOLINTNEXTLINE(runtime/int) */
184
52
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
185
52
  const auto full_sec = static_cast<uint64_t>(u_sec) * 1000UL;
186
  /* NOLINTNEXTLINE(runtime/int) */
187
52
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
188
52
  const auto full_nsec = static_cast<uint64_t>(u_nsec) / 1000'000UL;
189
52
  return full_sec + full_nsec;
190
}
191
192
#undef constexpr  // end N3652 bug workaround
193
194
template <typename NativeT, typename V8T>
195
205086
constexpr void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
196
                              const uv_stat_t* s,
197
                              const size_t offset = 0) {
198
205086
  fields->SetValue(offset + 0, static_cast<NativeT>(s->st_dev));
199
205086
  fields->SetValue(offset + 1, static_cast<NativeT>(s->st_mode));
200
205086
  fields->SetValue(offset + 2, static_cast<NativeT>(s->st_nlink));
201
205086
  fields->SetValue(offset + 3, static_cast<NativeT>(s->st_uid));
202
205086
  fields->SetValue(offset + 4, static_cast<NativeT>(s->st_gid));
203
205086
  fields->SetValue(offset + 5, static_cast<NativeT>(s->st_rdev));
204
205086
  fields->SetValue(offset + 6, static_cast<NativeT>(s->st_blksize));
205
205086
  fields->SetValue(offset + 7, static_cast<NativeT>(s->st_ino));
206
205086
  fields->SetValue(offset + 8, static_cast<NativeT>(s->st_size));
207
205086
  fields->SetValue(offset + 9, static_cast<NativeT>(s->st_blocks));
208
// Dates.
209
205086
  fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim));
210
205086
  fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim));
211
205086
  fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim));
212
205086
  fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim));
213
205086
}
214
215
204961
inline Local<Value> FillGlobalStatsArray(Environment* env,
216
                                         const bool use_bigint,
217
                                         const uv_stat_t* s,
218
                                         const bool second = false) {
219
204961
  const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0;
220
204961
  if (use_bigint) {
221
10
    auto* const arr = env->fs_stats_field_bigint_array();
222
10
    FillStatsArray(arr, s, offset);
223
20
    return arr->GetJSArray();
224
  } else {
225
204951
    auto* const arr = env->fs_stats_field_array();
226
204951
    FillStatsArray(arr, s, offset);
227
409902
    return arr->GetJSArray();
228
  }
229
}
230
231
template <typename AliasedBufferT>
232
class FSReqPromise : public FSReqBase {
233
 public:
234
347
  static FSReqPromise* New(Environment* env, bool use_bigint) {
235
    v8::Local<Object> obj;
236

694
    if (!env->fsreqpromise_constructor_template()
237
1041
             ->NewInstance(env->context())
238
1041
             .ToLocal(&obj)) {
239
      return nullptr;
240
    }
241
    v8::Local<v8::Promise::Resolver> resolver;
242




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



1735
        obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
244
      return nullptr;
245
    }
246
347
    return new FSReqPromise(env, obj, use_bigint);
247
  }
248
249
694
  ~FSReqPromise() override {
250
    // Validate that the promise was explicitly resolved or rejected.
251

347
    CHECK(finished_);
252

1041
  }
253
254
17
  void Reject(Local<Value> reject) override {
255
17
    finished_ = true;
256
17
    HandleScope scope(env()->isolate());
257
34
    InternalCallbackScope callback_scope(this);
258
    Local<Value> value =
259
17
        object()->Get(env()->context(),
260
85
                      env()->promise_string()).ToLocalChecked();
261
17
    Local<Promise::Resolver> resolver = value.As<Promise::Resolver>();
262
68
    USE(resolver->Reject(env()->context(), reject).FromJust());
263
17
  }
264
265
330
  void Resolve(Local<Value> value) override {
266
330
    finished_ = true;
267
330
    HandleScope scope(env()->isolate());
268
660
    InternalCallbackScope callback_scope(this);
269
    Local<Value> val =
270
330
        object()->Get(env()->context(),
271
1650
                      env()->promise_string()).ToLocalChecked();
272
330
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
273
1320
    USE(resolver->Resolve(env()->context(), value).FromJust());
274
330
  }
275
276
125
  void ResolveStat(const uv_stat_t* stat) override {
277
125
    FillStatsArray(&stats_field_array_, stat);
278
250
    Resolve(stats_field_array_.GetJSArray());
279
125
  }
280
281
347
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
282
    Local<Value> val =
283
347
        object()->Get(env()->context(),
284
1735
                      env()->promise_string()).ToLocalChecked();
285
347
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
286
1041
    args.GetReturnValue().Set(resolver->GetPromise());
287
347
  }
288
289
3
  void MemoryInfo(MemoryTracker* tracker) const override {
290
3
    tracker->TrackField("stats_field_array", stats_field_array_);
291
3
    tracker->TrackField("continuation_data", continuation_data);
292
3
  }
293
294
3
  SET_MEMORY_INFO_NAME(FSReqPromise)
295
3
  SET_SELF_SIZE(FSReqPromise)
296
297
  FSReqPromise(const FSReqPromise&) = delete;
298
  FSReqPromise& operator=(const FSReqPromise&) = delete;
299
  FSReqPromise(const FSReqPromise&&) = delete;
300
  FSReqPromise& operator=(const FSReqPromise&&) = delete;
301
302
 private:
303
347
  FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint)
304
      : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
305
347
        stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {}
306
307
  bool finished_ = false;
308
  AliasedBufferT stats_field_array_;
309
};
310
311
class FSReqAfterScope {
312
 public:
313
  FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req);
314
  ~FSReqAfterScope();
315
316
  bool Proceed();
317
318
  void Reject(uv_fs_t* req);
319
320
  FSReqAfterScope(const FSReqAfterScope&) = delete;
321
  FSReqAfterScope& operator=(const FSReqAfterScope&) = delete;
322
  FSReqAfterScope(const FSReqAfterScope&&) = delete;
323
  FSReqAfterScope& operator=(const FSReqAfterScope&&) = delete;
324
325
 private:
326
  FSReqBase* wrap_ = nullptr;
327
  uv_fs_t* req_ = nullptr;
328
  HandleScope handle_scope_;
329
  Context::Scope context_scope_;
330
};
331
332
class FileHandle;
333
334
// A request wrap specifically for uv_fs_read()s scheduled for reading
335
// from a FileHandle.
336
30
class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
337
 public:
338
  FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj);
339
340
221
  static inline FileHandleReadWrap* from_req(uv_fs_t* req) {
341
221
    return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
342
  }
343
344
  void MemoryInfo(MemoryTracker* tracker) const override;
345
2
  SET_MEMORY_INFO_NAME(FileHandleReadWrap)
346
2
  SET_SELF_SIZE(FileHandleReadWrap)
347
348
 private:
349
  FileHandle* file_handle_;
350
  uv_buf_t buffer_;
351
352
  friend class FileHandle;
353
};
354
355
// A wrapper for a file descriptor that will automatically close the fd when
356
// the object is garbage collected
357
class FileHandle : public AsyncWrap, public StreamBase {
358
 public:
359
  static FileHandle* New(Environment* env,
360
                         int fd,
361
                         v8::Local<v8::Object> obj = v8::Local<v8::Object>());
362
  ~FileHandle() override;
363
364
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
365
366
  int fd() const { return fd_; }
367
368
  // Will asynchronously close the FD and return a Promise that will
369
  // be resolved once closing is complete.
370
  static void Close(const FunctionCallbackInfo<Value>& args);
371
372
  // Releases ownership of the FD.
373
  static void ReleaseFD(const FunctionCallbackInfo<Value>& args);
374
375
  // StreamBase interface:
376
  int ReadStart() override;
377
  int ReadStop() override;
378
379
227
  bool IsAlive() override { return !closed_; }
380
227
  bool IsClosing() override { return closing_; }
381
122
  AsyncWrap* GetAsyncWrap() override { return this; }
382
383
  // In the case of file streams, shutting down corresponds to closing.
384
  ShutdownWrap* CreateShutdownWrap(v8::Local<v8::Object> object) override;
385
  int DoShutdown(ShutdownWrap* req_wrap) override;
386
387
  int DoWrite(WriteWrap* w,
388
              uv_buf_t* bufs,
389
              size_t count,
390
              uv_stream_t* send_handle) override {
391
    return UV_ENOSYS;  // Not implemented (yet).
392
  }
393
394
2
  void MemoryInfo(MemoryTracker* tracker) const override {
395
2
    tracker->TrackField("current_read", current_read_);
396
2
  }
397
398
2
  SET_MEMORY_INFO_NAME(FileHandle)
399
2
  SET_SELF_SIZE(FileHandle)
400
401
  FileHandle(const FileHandle&) = delete;
402
  FileHandle& operator=(const FileHandle&) = delete;
403
  FileHandle(const FileHandle&&) = delete;
404
  FileHandle& operator=(const FileHandle&&) = delete;
405
406
 private:
407
  FileHandle(Environment* env, v8::Local<v8::Object> obj, int fd);
408
409
  // Synchronous close that emits a warning
410
  void Close();
411
  void AfterClose();
412
413
  class CloseReq : public ReqWrap<uv_fs_t> {
414
   public:
415
42
    CloseReq(Environment* env,
416
             Local<Object> obj,
417
             Local<Promise> promise,
418
             Local<Value> ref)
419
84
        : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
420
42
      promise_.Reset(env->isolate(), promise);
421
42
      ref_.Reset(env->isolate(), ref);
422
42
    }
423
424
210
    ~CloseReq() override {
425
42
      uv_fs_req_cleanup(req());
426
42
      promise_.Reset();
427
42
      ref_.Reset();
428
84
    }
429
430
    FileHandle* file_handle();
431
432
    void MemoryInfo(MemoryTracker* tracker) const override {
433
      tracker->TrackField("promise", promise_);
434
      tracker->TrackField("ref", ref_);
435
    }
436
437
    SET_MEMORY_INFO_NAME(CloseReq)
438
    SET_SELF_SIZE(CloseReq)
439
440
    void Resolve();
441
442
    void Reject(Local<Value> reason);
443
444
42
    static CloseReq* from_req(uv_fs_t* req) {
445
42
      return static_cast<CloseReq*>(ReqWrap::from_req(req));
446
    }
447
448
    CloseReq(const CloseReq&) = delete;
449
    CloseReq& operator=(const CloseReq&) = delete;
450
    CloseReq(const CloseReq&&) = delete;
451
    CloseReq& operator=(const CloseReq&&) = delete;
452
453
   private:
454
    v8::Global<Promise> promise_{};
455
    v8::Global<Value> ref_{};
456
  };
457
458
  // Asynchronous close
459
  inline MaybeLocal<Promise> ClosePromise();
460
461
  int fd_;
462
  bool closing_ = false;
463
  bool closed_ = false;
464
  int64_t read_offset_ = -1;
465
  int64_t read_length_ = -1;
466
467
  bool reading_ = false;
468
  std::unique_ptr<FileHandleReadWrap> current_read_ = nullptr;
469
};
470
471
int MKDirpSync(uv_loop_t* loop,
472
               uv_fs_t* req,
473
               const std::string& path,
474
               int mode,
475
               uv_fs_cb cb = nullptr);
476
}  // namespace fs
477
478
}  // namespace node
479
480
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
481
482
#endif  // SRC_NODE_FILE_H_