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: 156 173 90.2 %
Date: 2019-02-13 22:28:58 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
4615
class FSContinuationData : public MemoryRetainer {
26
 public:
27
4607
  FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
28
4607
      : req(req), mode(mode), done_cb(done_cb) {
29
4607
  }
30
31
  uv_fs_t* req;
32
  int mode;
33
  std::vector<std::string> paths{};
34
35
34
  void PushPath(std::string&& path) {
36
34
    paths.emplace_back(std::move(path));
37
34
  }
38
39
4599
  void PushPath(const std::string& path) {
40
4599
    paths.push_back(path);
41
4599
  }
42
43
4633
  std::string PopPath() {
44
4633
    CHECK_GT(paths.size(), 0);
45
4633
    std::string path = std::move(paths.back());
46
4633
    paths.pop_back();
47
4633
    return path;
48
  }
49
50
8
  void Done(int result) {
51
8
    req->result = result;
52
8
    done_cb(req);
53
8
  }
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
171815
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
171823
  FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
72
            bool use_bigint)
73
171823
      : ReqWrap(env, req, type), use_bigint_(use_bigint) {
74
171823
  }
75
76
171767
  void Init(const char* syscall,
77
            const char* data,
78
            size_t len,
79
            enum encoding encoding) {
80
171767
    syscall_ = syscall;
81
171767
    encoding_ = encoding;
82
83
171767
    if (data != nullptr) {
84
36
      CHECK(!has_data_);
85
36
      buffer_.AllocateSufficientStorage(len + 1);
86
36
      buffer_.SetLengthAndZeroTerminate(len);
87
36
      memcpy(*buffer_, data, len);
88
36
      has_data_ = true;
89
    }
90
171767
  }
91
92
38
  FSReqBuffer& Init(const char* syscall, size_t len,
93
                    enum encoding encoding) {
94
38
    syscall_ = syscall;
95
38
    encoding_ = encoding;
96
97
38
    buffer_.AllocateSufficientStorage(len + 1);
98
38
    has_data_ = false;  // so that the data does not show up in error messages
99
38
    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
1936
  const char* syscall() const { return syscall_; }
108
1936
  const char* data() const { return has_data_ ? *buffer_ : nullptr; }
109
4875
  enum encoding encoding() const { return encoding_; }
110
111
3154
  bool use_bigint() const { return use_bigint_; }
112
113
171847
  static FSReqBase* from_req(uv_fs_t* req) {
114
171847
    return static_cast<FSReqBase*>(ReqWrap::from_req(req));
115
  }
116
117
 private:
118
  enum encoding encoding_ = UTF8;
119
  bool has_data_ = false;
120
  const char* syscall_ = nullptr;
121
  bool use_bigint_ = false;
122
123
  // Typically, the content of buffer_ is something like a file name, so
124
  // something around 64 bytes should be enough.
125
  FSReqBuffer buffer_;
126
127
  DISALLOW_COPY_AND_ASSIGN(FSReqBase);
128
};
129
130
342948
class FSReqCallback : public FSReqBase {
131
 public:
132
171482
  FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
133
171482
      : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) { }
134
135
  void Reject(Local<Value> reject) override;
136
  void Resolve(Local<Value> value) override;
137
  void ResolveStat(const uv_stat_t* stat) override;
138
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override;
139
140
  void MemoryInfo(MemoryTracker* tracker) const override {
141
    tracker->TrackField("continuation_data", continuation_data);
142
  }
143
144
  SET_MEMORY_INFO_NAME(FSReqCallback)
145
  SET_SELF_SIZE(FSReqCallback)
146
147
 private:
148
  DISALLOW_COPY_AND_ASSIGN(FSReqCallback);
149
};
150
151
// Wordaround a GCC4.9 bug that C++14 N3652 was not implemented
152
// Refs: https://www.gnu.org/software/gcc/projects/cxx-status.html#cxx14
153
// Refs: https://isocpp.org/files/papers/N3652.html
154
#if __cpp_constexpr < 201304
155
#  define constexpr inline
156
#endif
157
158
template <typename NativeT,
159
          // SFINAE limit NativeT to arithmetic types
160
          typename = std::enable_if<std::is_arithmetic<NativeT>::value>>
161
constexpr NativeT ToNative(uv_timespec_t ts) {
162
  // This template has exactly two specializations below.
163
  static_assert(std::is_arithmetic<NativeT>::value == false, "Not implemented");
164
  UNREACHABLE();
165
}
166
167
template <>
168
2354120
constexpr double ToNative(uv_timespec_t ts) {
169
  // We need to do a static_cast since the original FS values are ulong.
170
  /* NOLINTNEXTLINE(runtime/int) */
171
2354120
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
172
2354120
  const double full_sec = u_sec * 1000.0;
173
  /* NOLINTNEXTLINE(runtime/int) */
174
2354120
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
175
2354120
  const double full_nsec = u_nsec / 1000'000.0;
176
2354120
  return full_sec + full_nsec;
177
}
178
179
template <>
180
52
constexpr uint64_t ToNative(uv_timespec_t ts) {
181
  // We need to do a static_cast since the original FS values are ulong.
182
  /* NOLINTNEXTLINE(runtime/int) */
183
52
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
184
52
  const auto full_sec = static_cast<uint64_t>(u_sec) * 1000UL;
185
  /* NOLINTNEXTLINE(runtime/int) */
186
52
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
187
52
  const auto full_nsec = static_cast<uint64_t>(u_nsec) / 1000'000UL;
188
52
  return full_sec + full_nsec;
189
}
190
191
#undef constexpr  // end N3652 bug workaround
192
193
template <typename NativeT, typename V8T>
194
588543
constexpr void FillStatsArray(AliasedBuffer<NativeT, V8T>* fields,
195
                              const uv_stat_t* s, const size_t offset = 0) {
196
588543
  fields->SetValue(offset + 0, s->st_dev);
197
588543
  fields->SetValue(offset + 1, s->st_mode);
198
588543
  fields->SetValue(offset + 2, s->st_nlink);
199
588543
  fields->SetValue(offset + 3, s->st_uid);
200
588543
  fields->SetValue(offset + 4, s->st_gid);
201
588543
  fields->SetValue(offset + 5, s->st_rdev);
202
#if defined(__POSIX__)
203
588543
  fields->SetValue(offset + 6, s->st_blksize);
204
#else
205
  fields->SetValue(offset + 6, 0);
206
#endif
207
588543
  fields->SetValue(offset + 7, s->st_ino);
208
588543
  fields->SetValue(offset + 8, s->st_size);
209
#if defined(__POSIX__)
210
588543
  fields->SetValue(offset + 9, s->st_blocks);
211
#else
212
  fields->SetValue(offset + 9, 0);
213
#endif
214
// Dates.
215
588543
  fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim));
216
588543
  fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim));
217
588543
  fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim));
218
588543
  fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim));
219
588543
}
220
221
588419
inline Local<Value> FillGlobalStatsArray(Environment* env,
222
                                         const bool use_bigint,
223
                                         const uv_stat_t* s,
224
                                         const bool second = false) {
225
588419
  const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0;
226
588419
  if (use_bigint) {
227
10
    auto* const arr = env->fs_stats_field_bigint_array();
228
10
    FillStatsArray(arr, s, offset);
229
20
    return arr->GetJSArray();
230
  } else {
231
588409
    auto* const arr = env->fs_stats_field_array();
232
588409
    FillStatsArray(arr, s, offset);
233
1176818
    return arr->GetJSArray();
234
  }
235
}
236
237
template <typename NativeT = double, typename V8T = v8::Float64Array>
238
class FSReqPromise : public FSReqBase {
239
 public:
240
341
  static FSReqPromise* New(Environment* env, bool use_bigint) {
241
    v8::Local<Object> obj;
242

682
    if (!env->fsreqpromise_constructor_template()
243
1023
             ->NewInstance(env->context())
244
1023
             .ToLocal(&obj)) {
245
      return nullptr;
246
    }
247
    v8::Local<v8::Promise::Resolver> resolver;
248




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



1705
        obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
250
      return nullptr;
251
    }
252
341
    return new FSReqPromise(env, obj, use_bigint);
253
  }
254
255
682
  ~FSReqPromise() override {
256
    // Validate that the promise was explicitly resolved or rejected.
257

341
    CHECK(finished_);
258

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