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 |
|
7096 |
FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb) |
13 |
|
7096 |
: done_cb_(done_cb), req_(req), mode_(mode) { |
14 |
|
7096 |
} |
15 |
|
|
|
16 |
|
766 |
void FSContinuationData::PushPath(std::string&& path) { |
17 |
|
766 |
paths_.emplace_back(std::move(path)); |
18 |
|
766 |
} |
19 |
|
|
|
20 |
|
6736 |
void FSContinuationData::PushPath(const std::string& path) { |
21 |
|
6736 |
paths_.push_back(path); |
22 |
|
6736 |
} |
23 |
|
|
|
24 |
|
613 |
void FSContinuationData::MaybeSetFirstPath(const std::string& path) { |
25 |
✓✓ |
613 |
if (first_path_.empty()) { |
26 |
|
526 |
first_path_ = path; |
27 |
|
|
} |
28 |
|
613 |
} |
29 |
|
|
|
30 |
|
7502 |
std::string FSContinuationData::PopPath() { |
31 |
✗✓ |
7502 |
CHECK(!paths_.empty()); |
32 |
|
7502 |
std::string path = std::move(paths_.back()); |
33 |
|
7502 |
paths_.pop_back(); |
34 |
|
7502 |
return path; |
35 |
|
|
} |
36 |
|
|
|
37 |
|
360 |
void FSContinuationData::Done(int result) { |
38 |
|
360 |
req_->result = result; |
39 |
|
360 |
done_cb_(req_); |
40 |
|
360 |
} |
41 |
|
|
|
42 |
|
57789 |
FSReqBase::FSReqBase(BindingData* binding_data, |
43 |
|
|
v8::Local<v8::Object> req, |
44 |
|
|
AsyncWrap::ProviderType type, |
45 |
|
57789 |
bool use_bigint) |
46 |
|
|
: ReqWrap(binding_data->env(), req, type), |
47 |
|
|
use_bigint_(use_bigint), |
48 |
|
57789 |
binding_data_(binding_data) { |
49 |
|
57789 |
} |
50 |
|
|
|
51 |
|
57710 |
void FSReqBase::Init(const char* syscall, |
52 |
|
|
const char* data, |
53 |
|
|
size_t len, |
54 |
|
|
enum encoding encoding) { |
55 |
|
57710 |
syscall_ = syscall; |
56 |
|
57710 |
encoding_ = encoding; |
57 |
|
|
|
58 |
✓✓ |
57710 |
if (data != nullptr) { |
59 |
✗✓ |
133 |
CHECK(!has_data_); |
60 |
|
133 |
buffer_.AllocateSufficientStorage(len + 1); |
61 |
|
133 |
buffer_.SetLengthAndZeroTerminate(len); |
62 |
|
133 |
memcpy(*buffer_, data, len); |
63 |
|
133 |
has_data_ = true; |
64 |
|
|
} |
65 |
|
57710 |
} |
66 |
|
|
|
67 |
|
|
FSReqBase::FSReqBuffer& |
68 |
|
79 |
FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) { |
69 |
|
79 |
syscall_ = syscall; |
70 |
|
79 |
encoding_ = encoding; |
71 |
|
|
|
72 |
|
79 |
buffer_.AllocateSufficientStorage(len + 1); |
73 |
|
79 |
has_data_ = false; // so that the data does not show up in error messages |
74 |
|
79 |
return buffer_; |
75 |
|
|
} |
76 |
|
|
|
77 |
|
51574 |
FSReqCallback::FSReqCallback(BindingData* binding_data, |
78 |
|
|
v8::Local<v8::Object> req, |
79 |
|
51574 |
bool use_bigint) |
80 |
|
|
: FSReqBase(binding_data, |
81 |
|
|
req, |
82 |
|
|
AsyncWrap::PROVIDER_FSREQCALLBACK, |
83 |
|
51574 |
use_bigint) {} |
84 |
|
|
|
85 |
|
|
template <typename NativeT, typename V8T> |
86 |
|
374772 |
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 |
|
|
#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \ |
94 |
|
|
/* NOLINTNEXTLINE(runtime/int) */ \ |
95 |
|
|
SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat)) |
96 |
|
|
|
97 |
|
187386 |
SET_FIELD_WITH_STAT(kDev, s->st_dev); |
98 |
|
187386 |
SET_FIELD_WITH_STAT(kMode, s->st_mode); |
99 |
|
187386 |
SET_FIELD_WITH_STAT(kNlink, s->st_nlink); |
100 |
|
187386 |
SET_FIELD_WITH_STAT(kUid, s->st_uid); |
101 |
|
187386 |
SET_FIELD_WITH_STAT(kGid, s->st_gid); |
102 |
|
187386 |
SET_FIELD_WITH_STAT(kRdev, s->st_rdev); |
103 |
|
187386 |
SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize); |
104 |
|
187386 |
SET_FIELD_WITH_STAT(kIno, s->st_ino); |
105 |
|
187386 |
SET_FIELD_WITH_STAT(kSize, s->st_size); |
106 |
|
187386 |
SET_FIELD_WITH_STAT(kBlocks, s->st_blocks); |
107 |
|
|
|
108 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec); |
109 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec); |
110 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec); |
111 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec); |
112 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec); |
113 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec); |
114 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec); |
115 |
|
187386 |
SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec); |
116 |
|
|
|
117 |
|
|
#undef SET_FIELD_WITH_TIME_STAT |
118 |
|
|
#undef SET_FIELD_WITH_STAT |
119 |
|
187386 |
} |
120 |
|
|
|
121 |
|
185842 |
v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data, |
122 |
|
|
const bool use_bigint, |
123 |
|
|
const uv_stat_t* s, |
124 |
|
|
const bool second) { |
125 |
|
185842 |
const ptrdiff_t offset = |
126 |
✓✓ |
185842 |
second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0; |
127 |
✓✓ |
185842 |
if (use_bigint) { |
128 |
|
112425 |
auto* const arr = &binding_data->stats_field_bigint_array; |
129 |
|
112425 |
FillStatsArray(arr, s, offset); |
130 |
|
224850 |
return arr->GetJSArray(); |
131 |
|
|
} else { |
132 |
|
73417 |
auto* const arr = &binding_data->stats_field_array; |
133 |
|
73417 |
FillStatsArray(arr, s, offset); |
134 |
|
146834 |
return arr->GetJSArray(); |
135 |
|
|
} |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
template <typename AliasedBufferT> |
139 |
|
|
FSReqPromise<AliasedBufferT>* |
140 |
|
12430 |
FSReqPromise<AliasedBufferT>::New(BindingData* binding_data, |
141 |
|
|
bool use_bigint) { |
142 |
|
12430 |
Environment* env = binding_data->env(); |
143 |
|
|
v8::Local<v8::Object> obj; |
144 |
|
12430 |
if (!env->fsreqpromise_constructor_template() |
145 |
|
12430 |
->NewInstance(env->context()) |
146 |
✗✓ |
12430 |
.ToLocal(&obj)) { |
147 |
|
|
return nullptr; |
148 |
|
|
} |
149 |
|
|
v8::Local<v8::Promise::Resolver> resolver; |
150 |
✓✗ |
37290 |
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) || |
151 |
✗✓✗✓
|
49720 |
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) { |
152 |
|
|
return nullptr; |
153 |
|
|
} |
154 |
|
12430 |
return new FSReqPromise(binding_data, obj, use_bigint); |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
template <typename AliasedBufferT> |
158 |
|
24844 |
FSReqPromise<AliasedBufferT>::~FSReqPromise() { |
159 |
|
|
// Validate that the promise was explicitly resolved or rejected but only if |
160 |
|
|
// the Isolate is not terminating because in this case the promise might have |
161 |
|
|
// not finished. |
162 |
✓✓✗✓
|
12422 |
if (!env()->is_stopping()) CHECK(finished_); |
163 |
|
37266 |
} |
164 |
|
|
|
165 |
|
|
template <typename AliasedBufferT> |
166 |
|
12430 |
FSReqPromise<AliasedBufferT>::FSReqPromise( |
167 |
|
|
BindingData* binding_data, |
168 |
|
|
v8::Local<v8::Object> obj, |
169 |
|
|
bool use_bigint) |
170 |
|
|
: FSReqBase(binding_data, |
171 |
|
|
obj, |
172 |
|
|
AsyncWrap::PROVIDER_FSREQPROMISE, |
173 |
|
|
use_bigint), |
174 |
|
|
stats_field_array_( |
175 |
|
|
env()->isolate(), |
176 |
|
12430 |
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {} |
177 |
|
|
|
178 |
|
|
template <typename AliasedBufferT> |
179 |
|
1130 |
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) { |
180 |
|
1130 |
finished_ = true; |
181 |
|
2260 |
v8::HandleScope scope(env()->isolate()); |
182 |
|
1130 |
InternalCallbackScope callback_scope(this); |
183 |
|
|
v8::Local<v8::Value> value = |
184 |
|
3390 |
object()->Get(env()->context(), |
185 |
|
1130 |
env()->promise_string()).ToLocalChecked(); |
186 |
|
1130 |
v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>(); |
187 |
|
2260 |
USE(resolver->Reject(env()->context(), reject).FromJust()); |
188 |
|
1130 |
} |
189 |
|
|
|
190 |
|
|
template <typename AliasedBufferT> |
191 |
|
9686 |
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) { |
192 |
|
9686 |
finished_ = true; |
193 |
|
19372 |
v8::HandleScope scope(env()->isolate()); |
194 |
|
9686 |
InternalCallbackScope callback_scope(this); |
195 |
|
|
v8::Local<v8::Value> val = |
196 |
|
29058 |
object()->Get(env()->context(), |
197 |
|
9686 |
env()->promise_string()).ToLocalChecked(); |
198 |
|
9686 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
199 |
|
19372 |
USE(resolver->Resolve(env()->context(), value).FromJust()); |
200 |
|
9686 |
} |
201 |
|
|
|
202 |
|
|
template <typename AliasedBufferT> |
203 |
|
3088 |
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) { |
204 |
|
3088 |
FillStatsArray(&stats_field_array_, stat); |
205 |
|
6176 |
Resolve(stats_field_array_.GetJSArray()); |
206 |
|
3088 |
} |
207 |
|
|
|
208 |
|
|
template <typename AliasedBufferT> |
209 |
|
12430 |
void FSReqPromise<AliasedBufferT>::SetReturnValue( |
210 |
|
|
const v8::FunctionCallbackInfo<v8::Value>& args) { |
211 |
|
|
v8::Local<v8::Value> val = |
212 |
|
37290 |
object()->Get(env()->context(), |
213 |
|
12430 |
env()->promise_string()).ToLocalChecked(); |
214 |
|
12430 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
215 |
|
12430 |
args.GetReturnValue().Set(resolver->GetPromise()); |
216 |
|
12430 |
} |
217 |
|
|
|
218 |
|
|
template <typename AliasedBufferT> |
219 |
|
2 |
void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const { |
220 |
|
2 |
FSReqBase::MemoryInfo(tracker); |
221 |
|
2 |
tracker->TrackField("stats_field_array", stats_field_array_); |
222 |
|
|
} |
223 |
|
|
|
224 |
✓✗ |
766763 |
FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args, |
225 |
|
|
int index, |
226 |
|
|
bool use_bigint) { |
227 |
|
766763 |
v8::Local<v8::Value> value = args[index]; |
228 |
✓✓ |
766763 |
if (value->IsObject()) { |
229 |
|
51574 |
return Unwrap<FSReqBase>(value.As<v8::Object>()); |
230 |
|
|
} |
231 |
|
|
|
232 |
|
715189 |
BindingData* binding_data = Environment::GetBindingData<BindingData>(args); |
233 |
|
715189 |
Environment* env = binding_data->env(); |
234 |
✓✓ |
1430378 |
if (value->StrictEquals(env->fs_use_promises_symbol())) { |
235 |
✓✓ |
6215 |
if (use_bigint) { |
236 |
|
420 |
return FSReqPromise<AliasedBigUint64Array>::New(binding_data, use_bigint); |
237 |
|
|
} else { |
238 |
|
5795 |
return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint); |
239 |
|
|
} |
240 |
|
|
} |
241 |
|
708974 |
return nullptr; |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
// Returns nullptr if the operation fails from the start. |
245 |
|
|
template <typename Func, typename... Args> |
246 |
|
115420 |
FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap, |
247 |
|
|
const v8::FunctionCallbackInfo<v8::Value>& args, |
248 |
|
|
const char* syscall, const char* dest, |
249 |
|
|
size_t len, enum encoding enc, uv_fs_cb after, |
250 |
|
|
Func fn, Args... fn_args) { |
251 |
✗✓ |
115420 |
CHECK_NOT_NULL(req_wrap); |
252 |
|
115420 |
req_wrap->Init(syscall, dest, len, enc); |
253 |
|
115420 |
int err = req_wrap->Dispatch(fn, fn_args..., after); |
254 |
✗✓ |
115420 |
if (err < 0) { |
255 |
|
|
uv_fs_t* uv_req = req_wrap->req(); |
256 |
|
|
uv_req->result = err; |
257 |
|
|
uv_req->path = nullptr; |
258 |
|
|
after(uv_req); // after may delete req_wrap if there is an error |
259 |
|
|
req_wrap = nullptr; |
260 |
|
|
} else { |
261 |
|
115420 |
req_wrap->SetReturnValue(args); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
115420 |
return req_wrap; |
265 |
|
|
} |
266 |
|
|
|
267 |
|
|
// Returns nullptr if the operation fails from the start. |
268 |
|
|
template <typename Func, typename... Args> |
269 |
|
115154 |
FSReqBase* AsyncCall(Environment* env, |
270 |
|
|
FSReqBase* req_wrap, |
271 |
|
|
const v8::FunctionCallbackInfo<v8::Value>& args, |
272 |
|
|
const char* syscall, enum encoding enc, |
273 |
|
|
uv_fs_cb after, Func fn, Args... fn_args) { |
274 |
|
115154 |
return AsyncDestCall(env, req_wrap, args, |
275 |
|
|
syscall, nullptr, 0, enc, |
276 |
|
115154 |
after, fn, fn_args...); |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
// Template counterpart of SYNC_CALL, except that it only puts |
280 |
|
|
// the error number and the syscall in the context instead of |
281 |
|
|
// creating an error in the C++ land. |
282 |
|
|
// ctx must be checked using value->IsObject() before being passed. |
283 |
|
|
template <typename Func, typename... Args> |
284 |
|
708691 |
int SyncCall(Environment* env, v8::Local<v8::Value> ctx, |
285 |
|
|
FSReqWrapSync* req_wrap, const char* syscall, |
286 |
|
|
Func fn, Args... args) { |
287 |
|
708691 |
env->PrintSyncTrace(); |
288 |
|
708691 |
int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr); |
289 |
|
708691 |
if (err < 0) { |
290 |
|
2689 |
v8::Local<v8::Context> context = env->context(); |
291 |
|
2689 |
v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>(); |
292 |
|
2689 |
v8::Isolate* isolate = env->isolate(); |
293 |
|
10756 |
ctx_obj->Set(context, |
294 |
|
|
env->errno_string(), |
295 |
|
|
v8::Integer::New(isolate, err)).Check(); |
296 |
|
10756 |
ctx_obj->Set(context, |
297 |
|
|
env->syscall_string(), |
298 |
|
|
OneByteString(isolate, syscall)).Check(); |
299 |
|
|
} |
300 |
|
708691 |
return err; |
301 |
|
|
} |
302 |
|
|
|
303 |
|
|
} // namespace fs |
304 |
|
|
} // namespace node |
305 |
|
|
|
306 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
307 |
|
|
|
308 |
|
|
#endif // SRC_NODE_FILE_INL_H_ |