GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file-inl.h Lines: 150 157 95.5 %
Date: 2022-12-07 04:23:16 Branches: 27 38 71.1 %

Line Branch Exec Source
1
#ifndef SRC_NODE_FILE_INL_H_
2
#define SRC_NODE_FILE_INL_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "node_file.h"
7
#include "req_wrap-inl.h"
8
9
namespace node {
10
namespace fs {
11
12
7045
FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
13
7045
  : done_cb_(done_cb), req_(req), mode_(mode) {
14
7045
}
15
16
750
void FSContinuationData::PushPath(std::string&& path) {
17
750
  paths_.emplace_back(std::move(path));
18
750
}
19
20
6915
void FSContinuationData::PushPath(const std::string& path) {
21
6915
  paths_.push_back(path);
22
6915
}
23
24
725
void FSContinuationData::MaybeSetFirstPath(const std::string& path) {
25
725
  if (first_path_.empty()) {
26
536
    first_path_ = path;
27
  }
28
725
}
29
30
7665
std::string FSContinuationData::PopPath() {
31
7665
  CHECK(!paths_.empty());
32
7665
  std::string path = std::move(paths_.back());
33
7665
  paths_.pop_back();
34
7665
  return path;
35
}
36
37
363
void FSContinuationData::Done(int result) {
38
363
  req_->result = result;
39
363
  done_cb_(req_);
40
363
}
41
42
58073
FSReqBase::FSReqBase(BindingData* binding_data,
43
                     v8::Local<v8::Object> req,
44
                     AsyncWrap::ProviderType type,
45
58073
                     bool use_bigint)
46
  : ReqWrap(binding_data->env(), req, type),
47
    use_bigint_(use_bigint),
48
58073
    binding_data_(binding_data) {
49
58073
}
50
51
57992
void FSReqBase::Init(const char* syscall,
52
                     const char* data,
53
                     size_t len,
54
                     enum encoding encoding) {
55
57992
  syscall_ = syscall;
56
57992
  encoding_ = encoding;
57
58
57992
  if (data != nullptr) {
59
244
    CHECK(!has_data_);
60
244
    buffer_.AllocateSufficientStorage(len + 1);
61
244
    buffer_.SetLengthAndZeroTerminate(len);
62
244
    memcpy(*buffer_, data, len);
63
244
    has_data_ = true;
64
  }
65
57992
}
66
67
FSReqBase::FSReqBuffer&
68
81
FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) {
69
81
  syscall_ = syscall;
70
81
  encoding_ = encoding;
71
72
81
  buffer_.AllocateSufficientStorage(len + 1);
73
81
  has_data_ = false;  // so that the data does not show up in error messages
74
81
  return buffer_;
75
}
76
77
52056
FSReqCallback::FSReqCallback(BindingData* binding_data,
78
                             v8::Local<v8::Object> req,
79
52056
                             bool use_bigint)
80
  : FSReqBase(binding_data,
81
              req,
82
              AsyncWrap::PROVIDER_FSREQCALLBACK,
83
52056
              use_bigint) {}
84
85
template <typename NativeT, typename V8T>
86
384100
void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
87
                    const uv_stat_t* s,
88
                    const size_t offset) {
89
#define SET_FIELD_WITH_STAT(stat_offset, stat)                                 \
90
  fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset),   \
91
                   static_cast<NativeT>(stat))
92
93
// On win32, time is stored in uint64_t and starts from 1601-01-01.
94
// libuv calculates tv_sec and tv_nsec from it and converts to signed long,
95
// which causes Y2038 overflow. On the other platforms it is safe to treat
96
// negative values as pre-epoch time.
97
#ifdef _WIN32
98
#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat)                            \
99
  /* NOLINTNEXTLINE(runtime/int) */                                            \
100
  SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat))
101
#else
102
#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat)                            \
103
  SET_FIELD_WITH_STAT(stat_offset, static_cast<double>(stat))
104
#endif  // _WIN32
105
106
384100
  SET_FIELD_WITH_STAT(kDev, s->st_dev);
107
384100
  SET_FIELD_WITH_STAT(kMode, s->st_mode);
108
384100
  SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
109
384100
  SET_FIELD_WITH_STAT(kUid, s->st_uid);
110
384100
  SET_FIELD_WITH_STAT(kGid, s->st_gid);
111
384100
  SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
112
384100
  SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
113
384100
  SET_FIELD_WITH_STAT(kIno, s->st_ino);
114
384100
  SET_FIELD_WITH_STAT(kSize, s->st_size);
115
384100
  SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);
116
117
384100
  SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
118
384100
  SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
119
384100
  SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
120
384100
  SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
121
384100
  SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
122
384100
  SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
123
384100
  SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
124
384100
  SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec);
125
126
#undef SET_FIELD_WITH_TIME_STAT
127
#undef SET_FIELD_WITH_STAT
128
384100
}
129
130
190249
v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data,
131
                                          const bool use_bigint,
132
                                          const uv_stat_t* s,
133
                                          const bool second) {
134
190249
  const ptrdiff_t offset =
135
190249
      second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
136
190249
  if (use_bigint) {
137
114093
    auto* const arr = &binding_data->stats_field_bigint_array;
138
114093
    FillStatsArray(arr, s, offset);
139
228186
    return arr->GetJSArray();
140
  } else {
141
76156
    auto* const arr = &binding_data->stats_field_array;
142
76156
    FillStatsArray(arr, s, offset);
143
152312
    return arr->GetJSArray();
144
  }
145
}
146
147
template <typename AliasedBufferT>
148
FSReqPromise<AliasedBufferT>*
149
12034
FSReqPromise<AliasedBufferT>::New(BindingData* binding_data,
150
                                  bool use_bigint) {
151
12034
  Environment* env = binding_data->env();
152
  v8::Local<v8::Object> obj;
153
12034
  if (!env->fsreqpromise_constructor_template()
154
12034
           ->NewInstance(env->context())
155
12034
           .ToLocal(&obj)) {
156
    return nullptr;
157
  }
158
  v8::Local<v8::Promise::Resolver> resolver;
159
36102
  if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
160

48136
      obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
161
    return nullptr;
162
  }
163
12034
  return new FSReqPromise(binding_data, obj, use_bigint);
164
}
165
166
template <typename AliasedBufferT>
167
24052
FSReqPromise<AliasedBufferT>::~FSReqPromise() {
168
  // Validate that the promise was explicitly resolved or rejected but only if
169
  // the Isolate is not terminating because in this case the promise might have
170
  // not finished.
171

12026
  CHECK_IMPLIES(!finished_, !env()->can_call_into_js());
172
36078
}
173
174
template <typename AliasedBufferT>
175
12034
FSReqPromise<AliasedBufferT>::FSReqPromise(
176
    BindingData* binding_data,
177
    v8::Local<v8::Object> obj,
178
    bool use_bigint)
179
  : FSReqBase(binding_data,
180
              obj,
181
              AsyncWrap::PROVIDER_FSREQPROMISE,
182
              use_bigint),
183
    stats_field_array_(
184
        env()->isolate(),
185
12034
        static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
186
187
template <typename AliasedBufferT>
188
1170
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
189
1170
  finished_ = true;
190
2340
  v8::HandleScope scope(env()->isolate());
191
1170
  InternalCallbackScope callback_scope(this);
192
  v8::Local<v8::Value> value =
193
3510
      object()->Get(env()->context(),
194
1170
                    env()->promise_string()).ToLocalChecked();
195
1170
  v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
196
2340
  USE(resolver->Reject(env()->context(), reject).FromJust());
197
1170
}
198
199
template <typename AliasedBufferT>
200
10568
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) {
201
10568
  finished_ = true;
202
21136
  v8::HandleScope scope(env()->isolate());
203
10568
  InternalCallbackScope callback_scope(this);
204
  v8::Local<v8::Value> val =
205
31704
      object()->Get(env()->context(),
206
10568
                    env()->promise_string()).ToLocalChecked();
207
10568
  v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
208
21136
  USE(resolver->Resolve(env()->context(), value).FromJust());
209
10568
}
210
211
template <typename AliasedBufferT>
212
3602
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) {
213
3602
  FillStatsArray(&stats_field_array_, stat);
214
7204
  Resolve(stats_field_array_.GetJSArray());
215
3602
}
216
217
template <typename AliasedBufferT>
218
12034
void FSReqPromise<AliasedBufferT>::SetReturnValue(
219
    const v8::FunctionCallbackInfo<v8::Value>& args) {
220
  v8::Local<v8::Value> val =
221
36102
      object()->Get(env()->context(),
222
12034
                    env()->promise_string()).ToLocalChecked();
223
12034
  v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
224
12034
  args.GetReturnValue().Set(resolver->GetPromise());
225
12034
}
226
227
template <typename AliasedBufferT>
228
2
void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const {
229
2
  FSReqBase::MemoryInfo(tracker);
230
2
  tracker->TrackField("stats_field_array", stats_field_array_);
231
}
232
233
817166
FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
234
                      int index,
235
                      bool use_bigint) {
236
817166
  v8::Local<v8::Value> value = args[index];
237
817166
  if (value->IsObject()) {
238
52056
    return Unwrap<FSReqBase>(value.As<v8::Object>());
239
  }
240
241
765110
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
242
765110
  Environment* env = binding_data->env();
243
1530220
  if (value->StrictEquals(env->fs_use_promises_symbol())) {
244
6017
    if (use_bigint) {
245
414
      return FSReqPromise<AliasedBigInt64Array>::New(binding_data, use_bigint);
246
    } else {
247
5603
      return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint);
248
    }
249
  }
250
759093
  return nullptr;
251
}
252
253
// Returns nullptr if the operation fails from the start.
254
template <typename Func, typename... Args>
255
115984
FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
256
                         const v8::FunctionCallbackInfo<v8::Value>& args,
257
                         const char* syscall, const char* dest,
258
                         size_t len, enum encoding enc, uv_fs_cb after,
259
                         Func fn, Args... fn_args) {
260
115984
  CHECK_NOT_NULL(req_wrap);
261
115984
  req_wrap->Init(syscall, dest, len, enc);
262
115984
  int err = req_wrap->Dispatch(fn, fn_args..., after);
263
115984
  if (err < 0) {
264
    uv_fs_t* uv_req = req_wrap->req();
265
    uv_req->result = err;
266
    uv_req->path = nullptr;
267
    after(uv_req);  // after may delete req_wrap if there is an error
268
    req_wrap = nullptr;
269
  } else {
270
115984
    req_wrap->SetReturnValue(args);
271
  }
272
273
115984
  return req_wrap;
274
}
275
276
// Returns nullptr if the operation fails from the start.
277
template <typename Func, typename... Args>
278
115496
FSReqBase* AsyncCall(Environment* env,
279
                     FSReqBase* req_wrap,
280
                     const v8::FunctionCallbackInfo<v8::Value>& args,
281
                     const char* syscall, enum encoding enc,
282
                     uv_fs_cb after, Func fn, Args... fn_args) {
283
115496
  return AsyncDestCall(env, req_wrap, args,
284
                       syscall, nullptr, 0, enc,
285
115496
                       after, fn, fn_args...);
286
}
287
288
// Template counterpart of SYNC_CALL, except that it only puts
289
// the error number and the syscall in the context instead of
290
// creating an error in the C++ land.
291
// ctx must be checked using value->IsObject() before being passed.
292
template <typename Func, typename... Args>
293
758805
int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
294
             FSReqWrapSync* req_wrap, const char* syscall,
295
             Func fn, Args... args) {
296
758805
  env->PrintSyncTrace();
297
758805
  int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
298
758805
  if (err < 0) {
299
2785
    v8::Local<v8::Context> context = env->context();
300
2785
    v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>();
301
2785
    v8::Isolate* isolate = env->isolate();
302
11140
    ctx_obj->Set(context,
303
                 env->errno_string(),
304
                 v8::Integer::New(isolate, err)).Check();
305
11140
    ctx_obj->Set(context,
306
                 env->syscall_string(),
307
                 OneByteString(isolate, syscall)).Check();
308
  }
309
758805
  return err;
310
}
311
312
}  // namespace fs
313
}  // namespace node
314
315
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
316
317
#endif  // SRC_NODE_FILE_INL_H_