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