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: 104 165 63.0 %
Date: 2019-02-01 22:03:38 Branches: 12 30 40.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 "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
163
class FSContinuationData : public MemoryRetainer {
26
 public:
27
163
  FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
28
163
      : req(req), mode(mode), done_cb(done_cb) {
29
163
  }
30
31
  uv_fs_t* req;
32
  int mode;
33
  std::vector<std::string> paths{};
34
35
4
  void PushPath(std::string&& path) {
36
4
    paths.emplace_back(std::move(path));
37
4
  }
38
39
163
  void PushPath(const std::string& path) {
40
163
    paths.push_back(path);
41
163
  }
42
43
167
  std::string PopPath() {
44
167
    CHECK_GT(paths.size(), 0);
45
167
    std::string path = std::move(paths.back());
46
167
    paths.pop_back();
47
167
    return path;
48
  }
49
50
  void Done(int result) {
51
    req->result = result;
52
    done_cb(req);
53
  }
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
7064
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
7064
  FSReqBase(Environment* env, Local<Object> req, AsyncWrap::ProviderType type,
72
            bool use_bigint)
73
7064
      : ReqWrap(env, req, type), use_bigint_(use_bigint) {
74
7064
  }
75
76
7064
  void Init(const char* syscall,
77
            const char* data,
78
            size_t len,
79
            enum encoding encoding) {
80
7064
    syscall_ = syscall;
81
7064
    encoding_ = encoding;
82
83
7064
    if (data != nullptr) {
84
4
      CHECK(!has_data_);
85
4
      buffer_.AllocateSufficientStorage(len + 1);
86
4
      buffer_.SetLengthAndZeroTerminate(len);
87
4
      memcpy(*buffer_, data, len);
88
4
      has_data_ = true;
89
    }
90
7064
  }
91
92
  FSReqBuffer& Init(const char* syscall, size_t len,
93
                    enum encoding encoding) {
94
    syscall_ = syscall;
95
    encoding_ = encoding;
96
97
    buffer_.AllocateSufficientStorage(len + 1);
98
    has_data_ = false;  // so that the data does not show up in error messages
99
    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
1787
  const char* syscall() const { return syscall_; }
108
1787
  const char* data() const { return has_data_ ? *buffer_ : nullptr; }
109
143
  enum encoding encoding() const { return encoding_; }
110
111
592
  bool use_bigint() const { return use_bigint_; }
112
113
7064
  static FSReqBase* from_req(uv_fs_t* req) {
114
7064
    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
13938
class FSReqCallback : public FSReqBase {
131
 public:
132
6969
  FSReqCallback(Environment* env, Local<Object> req, bool use_bigint)
133
6969
      : 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
119468
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
119468
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
172
119468
  const double full_sec = u_sec * 1000.0;
173
  /* NOLINTNEXTLINE(runtime/int) */
174
119468
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
175
119468
  const double full_nsec = u_nsec / 1000'000.0;
176
119468
  return full_sec + full_nsec;
177
}
178
179
template <>
180
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
  const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
184
  const auto full_sec = static_cast<uint64_t>(u_sec) * 1000UL;
185
  /* NOLINTNEXTLINE(runtime/int) */
186
  const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
187
  const auto full_nsec = static_cast<uint64_t>(u_nsec) / 1000'000UL;
188
  return full_sec + full_nsec;
189
}
190
191
#undef constexpr  // end N3652 bug workaround
192
193
template <typename NativeT, typename V8T>
194
29867
constexpr void FillStatsArray(AliasedBuffer<NativeT, V8T>* fields,
195
                              const uv_stat_t* s, const size_t offset = 0) {
196
29867
  fields->SetValue(offset + 0, s->st_dev);
197
29867
  fields->SetValue(offset + 1, s->st_mode);
198
29867
  fields->SetValue(offset + 2, s->st_nlink);
199
29867
  fields->SetValue(offset + 3, s->st_uid);
200
29867
  fields->SetValue(offset + 4, s->st_gid);
201
29867
  fields->SetValue(offset + 5, s->st_rdev);
202
#if defined(__POSIX__)
203
29867
  fields->SetValue(offset + 6, s->st_blksize);
204
#else
205
  fields->SetValue(offset + 6, 0);
206
#endif
207
29867
  fields->SetValue(offset + 7, s->st_ino);
208
29867
  fields->SetValue(offset + 8, s->st_size);
209
#if defined(__POSIX__)
210
29867
  fields->SetValue(offset + 9, s->st_blocks);
211
#else
212
  fields->SetValue(offset + 9, 0);
213
#endif
214
// Dates.
215
29867
  fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim));
216
29867
  fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim));
217
29867
  fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim));
218
29867
  fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim));
219
29867
}
220
221
29787
inline Local<Value> FillGlobalStatsArray(Environment* env,
222
                                         const bool use_bigint,
223
                                         const uv_stat_t* s,
224
                                         const bool second = false) {
225
29787
  const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0;
226
29787
  if (use_bigint) {
227
    auto* const arr = env->fs_stats_field_bigint_array();
228
    FillStatsArray(arr, s, offset);
229
    return arr->GetJSArray();
230
  } else {
231
29787
    auto* const arr = env->fs_stats_field_array();
232
29787
    FillStatsArray(arr, s, offset);
233
59574
    return arr->GetJSArray();
234
  }
235
}
236
237
template <typename NativeT = double, typename V8T = v8::Float64Array>
238
class FSReqPromise : public FSReqBase {
239
 public:
240
95
  explicit FSReqPromise(Environment* env, bool use_bigint)
241
      : FSReqBase(env,
242
                  env->fsreqpromise_constructor_template()
243
285
                      ->NewInstance(env->context()).ToLocalChecked(),
244
                  AsyncWrap::PROVIDER_FSREQPROMISE,
245
                  use_bigint),
246
380
        stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {
247
    const auto resolver =
248
190
      Promise::Resolver::New(env->context()).ToLocalChecked();
249
190
    USE(object()->Set(env->context(), env->promise_string(),
250
570
                      resolver).FromJust());
251
95
  }
252
253
190
  ~FSReqPromise() override {
254
    // Validate that the promise was explicitly resolved or rejected.
255

95
    CHECK(finished_);
256

285
  }
257
258
12
  void Reject(Local<Value> reject) override {
259
12
    finished_ = true;
260
12
    HandleScope scope(env()->isolate());
261
24
    InternalCallbackScope callback_scope(this);
262
    Local<Value> value =
263
12
        object()->Get(env()->context(),
264
60
                      env()->promise_string()).ToLocalChecked();
265
12
    Local<Promise::Resolver> resolver = value.As<Promise::Resolver>();
266
48
    USE(resolver->Reject(env()->context(), reject).FromJust());
267
12
  }
268
269
83
  void Resolve(Local<Value> value) override {
270
83
    finished_ = true;
271
83
    HandleScope scope(env()->isolate());
272
166
    InternalCallbackScope callback_scope(this);
273
    Local<Value> val =
274
83
        object()->Get(env()->context(),
275
415
                      env()->promise_string()).ToLocalChecked();
276
83
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
277
332
    USE(resolver->Resolve(env()->context(), value).FromJust());
278
83
  }
279
280
80
  void ResolveStat(const uv_stat_t* stat) override {
281
80
    FillStatsArray(&stats_field_array_, stat);
282
160
    Resolve(stats_field_array_.GetJSArray());
283
80
  }
284
285
95
  void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
286
    Local<Value> val =
287
95
        object()->Get(env()->context(),
288
475
                      env()->promise_string()).ToLocalChecked();
289
95
    Local<Promise::Resolver> resolver = val.As<Promise::Resolver>();
290
285
    args.GetReturnValue().Set(resolver->GetPromise());
291
95
  }
292
293
  void MemoryInfo(MemoryTracker* tracker) const override {
294
    tracker->TrackField("stats_field_array", stats_field_array_);
295
    tracker->TrackField("continuation_data", continuation_data);
296
  }
297
298
  SET_MEMORY_INFO_NAME(FSReqPromise)
299
  SET_SELF_SIZE(FSReqPromise)
300
301
  FSReqPromise(const FSReqPromise&) = delete;
302
  FSReqPromise& operator=(const FSReqPromise&) = delete;
303
  FSReqPromise(const FSReqPromise&&) = delete;
304
  FSReqPromise& operator=(const FSReqPromise&&) = delete;
305
306
 private:
307
  bool finished_ = false;
308
  AliasedBuffer<NativeT, V8T> 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
class FileHandleReadWrap : public ReqWrap<uv_fs_t> {
337
 public:
338
  FileHandleReadWrap(FileHandle* handle, v8::Local<v8::Object> obj);
339
340
  static inline FileHandleReadWrap* from_req(uv_fs_t* req) {
341
    return static_cast<FileHandleReadWrap*>(ReqWrap::from_req(req));
342
  }
343
344
  void MemoryInfo(MemoryTracker* tracker) const override;
345
  SET_MEMORY_INFO_NAME(FileHandleReadWrap)
346
  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
  FileHandle(Environment* env,
360
             int fd,
361
             v8::Local<v8::Object> obj = v8::Local<v8::Object>());
362
  virtual ~FileHandle();
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
  bool IsAlive() override { return !closed_; }
380
  bool IsClosing() override { return closing_; }
381
  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
  void MemoryInfo(MemoryTracker* tracker) const override {
395
    tracker->TrackField("current_read", current_read_);
396
  }
397
398
  SET_MEMORY_INFO_NAME(FileHandle)
399
  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
  // Synchronous close that emits a warning
408
  void Close();
409
  void AfterClose();
410
411
  class CloseReq : public ReqWrap<uv_fs_t> {
412
   public:
413
    CloseReq(Environment* env,
414
             Local<Promise> promise,
415
             Local<Value> ref)
416
        : ReqWrap(env,
417
                  env->fdclose_constructor_template()
418
                      ->NewInstance(env->context()).ToLocalChecked(),
419
                  AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
420
      promise_.Reset(env->isolate(), promise);
421
      ref_.Reset(env->isolate(), ref);
422
    }
423
424
    ~CloseReq() override {
425
      uv_fs_req_cleanup(req());
426
      promise_.Reset();
427
      ref_.Reset();
428
    }
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
    static CloseReq* from_req(uv_fs_t* req) {
445
      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
    Persistent<Promise> promise_{};
455
    Persistent<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
}  // namespace fs
472
473
}  // namespace node
474
475
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
476
477
#endif  // SRC_NODE_FILE_H_