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 |
|
6905 |
FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb) |
13 |
|
6905 |
: done_cb_(done_cb), req_(req), mode_(mode) { |
14 |
|
6905 |
} |
15 |
|
|
|
16 |
|
966 |
void FSContinuationData::PushPath(std::string&& path) { |
17 |
|
966 |
paths_.emplace_back(std::move(path)); |
18 |
|
966 |
} |
19 |
|
|
|
20 |
|
6541 |
void FSContinuationData::PushPath(const std::string& path) { |
21 |
|
6541 |
paths_.push_back(path); |
22 |
|
6541 |
} |
23 |
|
|
|
24 |
|
713 |
void FSContinuationData::MaybeSetFirstPath(const std::string& path) { |
25 |
✓✓ |
713 |
if (first_path_.empty()) { |
26 |
|
531 |
first_path_ = path; |
27 |
|
|
} |
28 |
|
713 |
} |
29 |
|
|
|
30 |
|
7507 |
std::string FSContinuationData::PopPath() { |
31 |
✗✓ |
7507 |
CHECK(!paths_.empty()); |
32 |
|
7507 |
std::string path = std::move(paths_.back()); |
33 |
|
7507 |
paths_.pop_back(); |
34 |
|
7507 |
return path; |
35 |
|
|
} |
36 |
|
|
|
37 |
|
364 |
void FSContinuationData::Done(int result) { |
38 |
|
364 |
req_->result = result; |
39 |
|
364 |
done_cb_(req_); |
40 |
|
364 |
} |
41 |
|
|
|
42 |
|
57450 |
FSReqBase::FSReqBase(BindingData* binding_data, |
43 |
|
|
v8::Local<v8::Object> req, |
44 |
|
|
AsyncWrap::ProviderType type, |
45 |
|
57450 |
bool use_bigint) |
46 |
|
|
: ReqWrap(binding_data->env(), req, type), |
47 |
|
|
use_bigint_(use_bigint), |
48 |
|
57450 |
binding_data_(binding_data) { |
49 |
|
57450 |
} |
50 |
|
|
|
51 |
|
57372 |
void FSReqBase::Init(const char* syscall, |
52 |
|
|
const char* data, |
53 |
|
|
size_t len, |
54 |
|
|
enum encoding encoding) { |
55 |
|
57372 |
syscall_ = syscall; |
56 |
|
57372 |
encoding_ = encoding; |
57 |
|
|
|
58 |
✓✓ |
57372 |
if (data != nullptr) { |
59 |
✗✓ |
236 |
CHECK(!has_data_); |
60 |
|
236 |
buffer_.AllocateSufficientStorage(len + 1); |
61 |
|
236 |
buffer_.SetLengthAndZeroTerminate(len); |
62 |
|
236 |
memcpy(*buffer_, data, len); |
63 |
|
236 |
has_data_ = true; |
64 |
|
|
} |
65 |
|
57372 |
} |
66 |
|
|
|
67 |
|
|
FSReqBase::FSReqBuffer& |
68 |
|
78 |
FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) { |
69 |
|
78 |
syscall_ = syscall; |
70 |
|
78 |
encoding_ = encoding; |
71 |
|
|
|
72 |
|
78 |
buffer_.AllocateSufficientStorage(len + 1); |
73 |
|
78 |
has_data_ = false; // so that the data does not show up in error messages |
74 |
|
78 |
return buffer_; |
75 |
|
|
} |
76 |
|
|
|
77 |
|
52107 |
FSReqCallback::FSReqCallback(BindingData* binding_data, |
78 |
|
|
v8::Local<v8::Object> req, |
79 |
|
52107 |
bool use_bigint) |
80 |
|
|
: FSReqBase(binding_data, |
81 |
|
|
req, |
82 |
|
|
AsyncWrap::PROVIDER_FSREQCALLBACK, |
83 |
|
52107 |
use_bigint) {} |
84 |
|
|
|
85 |
|
|
template <typename NativeT, typename V8T> |
86 |
|
384198 |
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 |
|
192099 |
SET_FIELD_WITH_STAT(kDev, s->st_dev); |
107 |
|
192099 |
SET_FIELD_WITH_STAT(kMode, s->st_mode); |
108 |
|
192099 |
SET_FIELD_WITH_STAT(kNlink, s->st_nlink); |
109 |
|
192099 |
SET_FIELD_WITH_STAT(kUid, s->st_uid); |
110 |
|
192099 |
SET_FIELD_WITH_STAT(kGid, s->st_gid); |
111 |
|
192099 |
SET_FIELD_WITH_STAT(kRdev, s->st_rdev); |
112 |
|
192099 |
SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize); |
113 |
|
192099 |
SET_FIELD_WITH_STAT(kIno, s->st_ino); |
114 |
|
192099 |
SET_FIELD_WITH_STAT(kSize, s->st_size); |
115 |
|
192099 |
SET_FIELD_WITH_STAT(kBlocks, s->st_blocks); |
116 |
|
|
|
117 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec); |
118 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec); |
119 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec); |
120 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec); |
121 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec); |
122 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec); |
123 |
|
192099 |
SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec); |
124 |
|
192099 |
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 |
|
192099 |
} |
129 |
|
|
|
130 |
|
190453 |
v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data, |
131 |
|
|
const bool use_bigint, |
132 |
|
|
const uv_stat_t* s, |
133 |
|
|
const bool second) { |
134 |
|
190453 |
const ptrdiff_t offset = |
135 |
✓✓ |
190453 |
second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0; |
136 |
✓✓ |
190453 |
if (use_bigint) { |
137 |
|
114061 |
auto* const arr = &binding_data->stats_field_bigint_array; |
138 |
|
114061 |
FillStatsArray(arr, s, offset); |
139 |
|
228122 |
return arr->GetJSArray(); |
140 |
|
|
} else { |
141 |
|
76392 |
auto* const arr = &binding_data->stats_field_array; |
142 |
|
76392 |
FillStatsArray(arr, s, offset); |
143 |
|
152784 |
return arr->GetJSArray(); |
144 |
|
|
} |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
template <typename AliasedBufferT> |
148 |
|
|
FSReqPromise<AliasedBufferT>* |
149 |
|
10686 |
FSReqPromise<AliasedBufferT>::New(BindingData* binding_data, |
150 |
|
|
bool use_bigint) { |
151 |
|
10686 |
Environment* env = binding_data->env(); |
152 |
|
|
v8::Local<v8::Object> obj; |
153 |
|
10686 |
if (!env->fsreqpromise_constructor_template() |
154 |
|
10686 |
->NewInstance(env->context()) |
155 |
✗✓ |
10686 |
.ToLocal(&obj)) { |
156 |
|
|
return nullptr; |
157 |
|
|
} |
158 |
|
|
v8::Local<v8::Promise::Resolver> resolver; |
159 |
✓✗ |
32058 |
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) || |
160 |
✗✓✗✓
|
42744 |
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) { |
161 |
|
|
return nullptr; |
162 |
|
|
} |
163 |
|
10686 |
return new FSReqPromise(binding_data, obj, use_bigint); |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
template <typename AliasedBufferT> |
167 |
|
21356 |
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 |
✗✓✗✓
|
10678 |
CHECK_IMPLIES(!finished_, !env()->can_call_into_js()); |
172 |
✓✓ |
32034 |
} |
173 |
|
|
|
174 |
|
|
template <typename AliasedBufferT> |
175 |
|
10686 |
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 |
|
10686 |
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {} |
186 |
|
|
|
187 |
|
|
template <typename AliasedBufferT> |
188 |
|
826 |
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) { |
189 |
|
826 |
finished_ = true; |
190 |
|
1652 |
v8::HandleScope scope(env()->isolate()); |
191 |
|
826 |
InternalCallbackScope callback_scope(this); |
192 |
|
|
v8::Local<v8::Value> value = |
193 |
|
2478 |
object()->Get(env()->context(), |
194 |
|
826 |
env()->promise_string()).ToLocalChecked(); |
195 |
|
826 |
v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>(); |
196 |
|
1652 |
USE(resolver->Reject(env()->context(), reject).FromJust()); |
197 |
|
826 |
} |
198 |
|
|
|
199 |
|
|
template <typename AliasedBufferT> |
200 |
|
9566 |
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) { |
201 |
|
9566 |
finished_ = true; |
202 |
|
19132 |
v8::HandleScope scope(env()->isolate()); |
203 |
|
9566 |
InternalCallbackScope callback_scope(this); |
204 |
|
|
v8::Local<v8::Value> val = |
205 |
|
28698 |
object()->Get(env()->context(), |
206 |
|
9566 |
env()->promise_string()).ToLocalChecked(); |
207 |
|
9566 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
208 |
|
19132 |
USE(resolver->Resolve(env()->context(), value).FromJust()); |
209 |
|
9566 |
} |
210 |
|
|
|
211 |
|
|
template <typename AliasedBufferT> |
212 |
|
3292 |
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) { |
213 |
|
3292 |
FillStatsArray(&stats_field_array_, stat); |
214 |
|
6584 |
Resolve(stats_field_array_.GetJSArray()); |
215 |
|
3292 |
} |
216 |
|
|
|
217 |
|
|
template <typename AliasedBufferT> |
218 |
|
10686 |
void FSReqPromise<AliasedBufferT>::SetReturnValue( |
219 |
|
|
const v8::FunctionCallbackInfo<v8::Value>& args) { |
220 |
|
|
v8::Local<v8::Value> val = |
221 |
|
32058 |
object()->Get(env()->context(), |
222 |
|
10686 |
env()->promise_string()).ToLocalChecked(); |
223 |
|
10686 |
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>(); |
224 |
|
10686 |
args.GetReturnValue().Set(resolver->GetPromise()); |
225 |
|
10686 |
} |
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 |
✓✗ |
801922 |
FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args, |
234 |
|
|
int index, |
235 |
|
|
bool use_bigint) { |
236 |
|
801922 |
v8::Local<v8::Value> value = args[index]; |
237 |
✓✓ |
801922 |
if (value->IsObject()) { |
238 |
|
52107 |
return Unwrap<FSReqBase>(value.As<v8::Object>()); |
239 |
|
|
} |
240 |
|
|
|
241 |
|
749815 |
BindingData* binding_data = Environment::GetBindingData<BindingData>(args); |
242 |
|
749815 |
Environment* env = binding_data->env(); |
243 |
✓✓ |
1499630 |
if (value->StrictEquals(env->fs_use_promises_symbol())) { |
244 |
✓✓ |
5343 |
if (use_bigint) { |
245 |
|
428 |
return FSReqPromise<AliasedBigInt64Array>::New(binding_data, use_bigint); |
246 |
|
|
} else { |
247 |
|
4915 |
return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint); |
248 |
|
|
} |
249 |
|
|
} |
250 |
|
744472 |
return nullptr; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
// Returns nullptr if the operation fails from the start. |
254 |
|
|
template <typename Func, typename... Args> |
255 |
|
114744 |
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 |
✗✓ |
114744 |
CHECK_NOT_NULL(req_wrap); |
261 |
|
114744 |
req_wrap->Init(syscall, dest, len, enc); |
262 |
|
114744 |
int err = req_wrap->Dispatch(fn, fn_args..., after); |
263 |
✗✓ |
114744 |
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 |
|
114744 |
req_wrap->SetReturnValue(args); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
114744 |
return req_wrap; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
// Returns nullptr if the operation fails from the start. |
277 |
|
|
template <typename Func, typename... Args> |
278 |
|
114272 |
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 |
|
114272 |
return AsyncDestCall(env, req_wrap, args, |
284 |
|
|
syscall, nullptr, 0, enc, |
285 |
|
114272 |
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 |
|
744189 |
int SyncCall(Environment* env, v8::Local<v8::Value> ctx, |
294 |
|
|
FSReqWrapSync* req_wrap, const char* syscall, |
295 |
|
|
Func fn, Args... args) { |
296 |
|
744189 |
env->PrintSyncTrace(); |
297 |
|
744189 |
int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr); |
298 |
|
744189 |
if (err < 0) { |
299 |
|
2735 |
v8::Local<v8::Context> context = env->context(); |
300 |
|
2735 |
v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>(); |
301 |
|
2735 |
v8::Isolate* isolate = env->isolate(); |
302 |
|
10940 |
ctx_obj->Set(context, |
303 |
|
|
env->errno_string(), |
304 |
|
|
v8::Integer::New(isolate, err)).Check(); |
305 |
|
10940 |
ctx_obj->Set(context, |
306 |
|
|
env->syscall_string(), |
307 |
|
|
OneByteString(isolate, syscall)).Check(); |
308 |
|
|
} |
309 |
|
744189 |
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_ |