GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
6945 |
FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb) |
|
13 |
6945 |
: done_cb_(done_cb), req_(req), mode_(mode) { |
|
14 |
6945 |
} |
|
15 |
|||
16 |
965 |
void FSContinuationData::PushPath(std::string&& path) { |
|
17 |
965 |
paths_.emplace_back(std::move(path)); |
|
18 |
965 |
} |
|
19 |
|||
20 |
6582 |
void FSContinuationData::PushPath(const std::string& path) { |
|
21 |
6582 |
paths_.push_back(path); |
|
22 |
6582 |
} |
|
23 |
|||
24 |
716 |
void FSContinuationData::MaybeSetFirstPath(const std::string& path) { |
|
25 |
✓✓ | 716 |
if (first_path_.empty()) { |
26 |
534 |
first_path_ = path; |
|
27 |
} |
||
28 |
716 |
} |
|
29 |
|||
30 |
7547 |
std::string FSContinuationData::PopPath() { |
|
31 |
✗✓ | 7547 |
CHECK(!paths_.empty()); |
32 |
7547 |
std::string path = std::move(paths_.back()); |
|
33 |
7547 |
paths_.pop_back(); |
|
34 |
7547 |
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 |
58211 |
FSReqBase::FSReqBase(BindingData* binding_data, |
|
43 |
v8::Local<v8::Object> req, |
||
44 |
AsyncWrap::ProviderType type, |
||
45 |
58211 |
bool use_bigint) |
|
46 |
: ReqWrap(binding_data->env(), req, type), |
||
47 |
use_bigint_(use_bigint), |
||
48 |
58211 |
binding_data_(binding_data) { |
|
49 |
58211 |
} |
|
50 |
|||
51 |
58130 |
void FSReqBase::Init(const char* syscall, |
|
52 |
const char* data, |
||
53 |
size_t len, |
||
54 |
enum encoding encoding) { |
||
55 |
58130 |
syscall_ = syscall; |
|
56 |
58130 |
encoding_ = encoding; |
|
57 |
|||
58 |
✓✓ | 58130 |
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 |
58130 |
} |
|
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 |
52845 |
FSReqCallback::FSReqCallback(BindingData* binding_data, |
|
78 |
v8::Local<v8::Object> req, |
||
79 |
52845 |
bool use_bigint) |
|
80 |
: FSReqBase(binding_data, |
||
81 |
req, |
||
82 |
AsyncWrap::PROVIDER_FSREQCALLBACK, |
||
83 |
52845 |
use_bigint) {} |
|
84 |
|||
85 |
template <typename NativeT, typename V8T> |
||
86 |
192847 |
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 |
192847 |
SET_FIELD_WITH_STAT(kDev, s->st_dev); |
|
107 |
192847 |
SET_FIELD_WITH_STAT(kMode, s->st_mode); |
|
108 |
192847 |
SET_FIELD_WITH_STAT(kNlink, s->st_nlink); |
|
109 |
192847 |
SET_FIELD_WITH_STAT(kUid, s->st_uid); |
|
110 |
192847 |
SET_FIELD_WITH_STAT(kGid, s->st_gid); |
|
111 |
192847 |
SET_FIELD_WITH_STAT(kRdev, s->st_rdev); |
|
112 |
192847 |
SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize); |
|
113 |
192847 |
SET_FIELD_WITH_STAT(kIno, s->st_ino); |
|
114 |
192847 |
SET_FIELD_WITH_STAT(kSize, s->st_size); |
|
115 |
192847 |
SET_FIELD_WITH_STAT(kBlocks, s->st_blocks); |
|
116 |
|||
117 |
192847 |
SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec); |
|
118 |
192847 |
SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec); |
|
119 |
192847 |
SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec); |
|
120 |
192847 |
SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec); |
|
121 |
192847 |
SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec); |
|
122 |
192847 |
SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec); |
|
123 |
192847 |
SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec); |
|
124 |
192847 |
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 |
192847 |
} |
|
129 |
|||
130 |
191203 |
v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data, |
|
131 |
const bool use_bigint, |
||
132 |
const uv_stat_t* s, |
||
133 |
const bool second) { |
||
134 |
191203 |
const ptrdiff_t offset = |
|
135 |
✓✓ | 191203 |
second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0; |
136 |
✓✓ | 191203 |
if (use_bigint) { |
137 |
114468 |
auto* const arr = &binding_data->stats_field_bigint_array; |
|
138 |
114468 |
FillStatsArray(arr, s, offset); |
|
139 |
228936 |
return arr->GetJSArray(); |
|
140 |
} else { |
||
141 |
76735 |
auto* const arr = &binding_data->stats_field_array; |
|
142 |
76735 |
FillStatsArray(arr, s, offset); |
|
143 |
153470 |
return arr->GetJSArray(); |
|
144 |
} |
||
145 |
} |
||
146 |
|||
147 |
template <typename AliasedBufferT> |
||
148 |
FSReqPromise<AliasedBufferT>* |
||
149 |
5366 |
FSReqPromise<AliasedBufferT>::New(BindingData* binding_data, |
|
150 |
bool use_bigint) { |
||
151 |
5366 |
Environment* env = binding_data->env(); |
|
152 |
v8::Local<v8::Object> obj; |
||
153 |
✗✓✗✓ |
16098 |
if (!env->fsreqpromise_constructor_template() |
154 |
10732 |
->NewInstance(env->context()) |
|
155 |
5366 |
.ToLocal(&obj)) { |
|
156 |
return nullptr; |
||
157 |
} |
||
158 |
v8::Local<v8::Promise::Resolver> resolver; |
||
159 |
✓✗✗✓ ✗✓✓✗ ✗✓✗✓ |
21464 |
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) || |
160 |
26830 |
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) { |
|
161 |
return nullptr; |
||
162 |
} |
||
163 |
5366 |
return new FSReqPromise(binding_data, obj, use_bigint); |
|
164 |
} |
||
165 |
|||
166 |
template <typename AliasedBufferT> |
||
167 |
10724 |
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 |
✗✓✗✗ ✗✓✓✓ ✗✓✗✓ |
5362 |
CHECK_IMPLIES(!finished_, !env()->can_call_into_js()); |
172 |
16086 |
} |
|
173 |
|||
174 |
template <typename AliasedBufferT> |
||
175 |
5366 |
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 |
5366 |
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {} |
|
186 |
|||
187 |
template <typename AliasedBufferT> |
||
188 |
408 |
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) { |
|
189 |
408 |
finished_ = true; |
|
190 |
816 |
v8::HandleScope scope(env()->isolate()); |
|
191 |
816 |
InternalCallbackScope callback_scope(this); |
|
192 |
408 |
v8::Local<v8::Value> value = |
|
193 |
1632 |
object()->Get(env()->context(), |
|
194 |
env()->promise_string()).ToLocalChecked(); |
||
195 |
408 |
v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>(); |
|
196 |
816 |
USE(resolver->Reject(env()->context(), reject).FromJust()); |
|
197 |
408 |
} |
|
198 |
|||
199 |
template <typename AliasedBufferT> |
||
200 |
4812 |
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) { |
|
201 |
4812 |
finished_ = true; |
|
202 |
9624 |
v8::HandleScope scope(env()->isolate()); |
|
203 |
9624 |
InternalCallbackScope callback_scope(this); |
|
204 |
4812 |
v8::Local<v8::Value> val = |
|
205 |
19248 |
object()->Get(env()->context(), |
|
206 |
env()->promise_string()).ToLocalChecked(); |
||
207 |
4812 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
|
208 |
9624 |
USE(resolver->Resolve(env()->context(), value).FromJust()); |
|
209 |
4812 |
} |
|
210 |
|||
211 |
template <typename AliasedBufferT> |
||
212 |
1644 |
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) { |
|
213 |
1644 |
FillStatsArray(&stats_field_array_, stat); |
|
214 |
3288 |
Resolve(stats_field_array_.GetJSArray()); |
|
215 |
1644 |
} |
|
216 |
|||
217 |
template <typename AliasedBufferT> |
||
218 |
5366 |
void FSReqPromise<AliasedBufferT>::SetReturnValue( |
|
219 |
const v8::FunctionCallbackInfo<v8::Value>& args) { |
||
220 |
5366 |
v8::Local<v8::Value> val = |
|
221 |
21464 |
object()->Get(env()->context(), |
|
222 |
env()->promise_string()).ToLocalChecked(); |
||
223 |
5366 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
|
224 |
16098 |
args.GetReturnValue().Set(resolver->GetPromise()); |
|
225 |
5366 |
} |
|
226 |
|||
227 |
template <typename AliasedBufferT> |
||
228 |
1 |
void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const { |
|
229 |
1 |
FSReqBase::MemoryInfo(tracker); |
|
230 |
1 |
tracker->TrackField("stats_field_array", stats_field_array_); |
|
231 |
1 |
} |
|
232 |
|||
233 |
807908 |
FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args, |
|
234 |
int index, |
||
235 |
bool use_bigint) { |
||
236 |
807908 |
v8::Local<v8::Value> value = args[index]; |
|
237 |
✓✓ | 807908 |
if (value->IsObject()) { |
238 |
52845 |
return Unwrap<FSReqBase>(value.As<v8::Object>()); |
|
239 |
} |
||
240 |
|||
241 |
755063 |
BindingData* binding_data = Environment::GetBindingData<BindingData>(args); |
|
242 |
755063 |
Environment* env = binding_data->env(); |
|
243 |
✓✓ | 1510126 |
if (value->StrictEquals(env->fs_use_promises_symbol())) { |
244 |
✓✓ | 5366 |
if (use_bigint) { |
245 |
414 |
return FSReqPromise<AliasedBigInt64Array>::New(binding_data, use_bigint); |
|
246 |
} else { |
||
247 |
4952 |
return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint); |
|
248 |
} |
||
249 |
} |
||
250 |
749697 |
return nullptr; |
|
251 |
} |
||
252 |
|||
253 |
// Returns nullptr if the operation fails from the start. |
||
254 |
template <typename Func, typename... Args> |
||
255 |
58130 |
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 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✗ ✗✓✗✓ ✗✓✗✓ |
58130 |
CHECK_NOT_NULL(req_wrap); |
261 |
58130 |
req_wrap->Init(syscall, dest, len, enc); |
|
262 |
58130 |
int err = req_wrap->Dispatch(fn, fn_args..., after); |
|
263 |
✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✓ ✗✓✗✗ ✗✓✗✓ ✗✓✗✓ |
58130 |
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 |
58130 |
req_wrap->SetReturnValue(args); |
|
271 |
} |
||
272 |
|||
273 |
58130 |
return req_wrap; |
|
274 |
} |
||
275 |
|||
276 |
// Returns nullptr if the operation fails from the start. |
||
277 |
template <typename Func, typename... Args> |
||
278 |
57886 |
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 |
return AsyncDestCall(env, req_wrap, args, |
||
284 |
syscall, nullptr, 0, enc, |
||
285 |
57886 |
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 |
749410 |
int SyncCall(Environment* env, v8::Local<v8::Value> ctx, |
|
294 |
FSReqWrapSync* req_wrap, const char* syscall, |
||
295 |
Func fn, Args... args) { |
||
296 |
749410 |
env->PrintSyncTrace(); |
|
297 |
749410 |
int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr); |
|
298 |
✓✓✓✓ ✓✓✓✓ ✓✓✗✓ ✓✓✓✓ ✓✓✓✓ ✓✓✗✗ ✓✓✓✓ |
749410 |
if (err < 0) { |
299 |
2698 |
v8::Local<v8::Context> context = env->context(); |
|
300 |
2698 |
v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>(); |
|
301 |
2698 |
v8::Isolate* isolate = env->isolate(); |
|
302 |
10792 |
ctx_obj->Set(context, |
|
303 |
env->errno_string(), |
||
304 |
v8::Integer::New(isolate, err)).Check(); |
||
305 |
10792 |
ctx_obj->Set(context, |
|
306 |
env->syscall_string(), |
||
307 |
OneByteString(isolate, syscall)).Check(); |
||
308 |
} |
||
309 |
749410 |
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_ |
Generated by: GCOVR (Version 4.2) |