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-26 22:23:30 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
4667
class FSContinuationData : public MemoryRetainer {
26
 public:
27
4659
  FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
28
4659
      : req(req), mode(mode), done_cb(done_cb) {
29
4659
  }
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
4651
  void PushPath(const std::string& path) {
40
4651
    paths.push_back(path);
41
4651
  }
42
43
4685
  std::string PopPath() {
44
4685
    CHECK_GT(paths.size(), 0);
45
4685
    std::string path = std::move(paths.back());
46
4685
    paths.pop_back();
47
4685
    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
171687
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
171695
  FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
72
            bool use_bigint)
73
171695
      : ReqWrap(env, req, type), use_bigint_(use_bigint) {
74
171695
  }
75
76
171639
  void Init(const char* syscall,
77
            const char* data,
78
            size_t len,
79
            enum encoding encoding) {
80
171639
    syscall_ = syscall;
81
171639
    encoding_ = encoding;
82
83
171639
    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
171639
  }
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
1946
  const char* syscall() const { return syscall_; }
108
1946
  const char* data() const { return has_data_ ? *buffer_ : nullptr; }
109
4900
  enum encoding encoding() const { return encoding_; }
110
111
3111
  bool use_bigint() const { return use_bigint_; }
112
113
171719
  static FSReqBase* from_req(uv_fs_t* req) {
114
171719
    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
342690
class FSReqCallback : public FSReqBase {
131
 public:
132
171353
  FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
133
171353
      : 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
758160
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
758160
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
172
758160
  const double full_sec = u_sec * 1000.0;
173
  /* NOLINTNEXTLINE(runtime/int) */
174
758160
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
175
758160
  const double full_nsec = u_nsec / 1000'000.0;
176
758160
  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
189553
constexpr void FillStatsArray(AliasedBuffer<NativeT, V8T>* fields,
195
                              const uv_stat_t* s, const size_t offset = 0) {
196
189553
  fields->SetValue(offset + 0, s->st_dev);
197
189553
  fields->SetValue(offset + 1, s->st_mode);
198
189553
  fields->SetValue(offset + 2, s->st_nlink);
199
189553
  fields->SetValue(offset + 3, s->st_uid);
200
189553
  fields->SetValue(offset + 4, s->st_gid);
201
189553
  fields->SetValue(offset + 5, s->st_rdev);
202
189553
  fields->SetValue(offset + 6, s->st_blksize);
203
189553
  fields->SetValue(offset + 7, s->st_ino);
204
189553
  fields->SetValue(offset + 8, s->st_size);
205
189553
  fields->SetValue(offset + 9, s->st_blocks);
206
// Dates.
207
189553
  fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim));
208
189553
  fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim));
209
189553
  fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim));
210
189553
  fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim));
211
189553
}
212
213
189428
inline Local<Value> FillGlobalStatsArray(Environment* env,
214
                                         const bool use_bigint,
215
                                         const uv_stat_t* s,
216
                                         const bool second = false) {
217
189428
  const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0;
218
189428
  if (use_bigint) {
219
10
    auto* const arr = env->fs_stats_field_bigint_array();
220
10
    FillStatsArray(arr, s, offset);
221
20
    return arr->GetJSArray();
222
  } else {
223
189418
    auto* const arr = env->fs_stats_field_array();
224
189418
    FillStatsArray(arr, s, offset);
225
378836
    return arr->GetJSArray();
226
  }
227
}
228
229
template <typename NativeT = double, typename V8T = v8::Float64Array>
230
class FSReqPromise : public FSReqBase {
231
 public:
232
342
  static FSReqPromise* New(Environment* env, bool use_bigint) {
233
    v8::Local<Object> obj;
234

684
    if (!env->fsreqpromise_constructor_template()
235
1026
             ->NewInstance(env->context())
236
1026
             .ToLocal(&obj)) {
237
      return nullptr;
238
    }
239
    v8::Local<v8::Promise::Resolver> resolver;
240




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



1710
        obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
242
      return nullptr;
243
    }
244
342
    return new FSReqPromise(env, obj, use_bigint);
245
  }
246
247
684
  ~FSReqPromise() override {
248
    // Validate that the promise was explicitly resolved or rejected.
249

342
    CHECK(finished_);
250

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