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
FSContinuationData(uv_fs_t * req,int mode,uv_fs_cb done_cb)12 FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
13 : done_cb_(done_cb), req_(req), mode_(mode) {
14 }
15
PushPath(std::string && path)16 void FSContinuationData::PushPath(std::string&& path) {
17 paths_.emplace_back(std::move(path));
18 }
19
PushPath(const std::string & path)20 void FSContinuationData::PushPath(const std::string& path) {
21 paths_.push_back(path);
22 }
23
MaybeSetFirstPath(const std::string & path)24 void FSContinuationData::MaybeSetFirstPath(const std::string& path) {
25 if (first_path_.empty()) {
26 first_path_ = path;
27 }
28 }
29
PopPath()30 std::string FSContinuationData::PopPath() {
31 CHECK(!paths_.empty());
32 std::string path = std::move(paths_.back());
33 paths_.pop_back();
34 return path;
35 }
36
Done(int result)37 void FSContinuationData::Done(int result) {
38 req_->result = result;
39 done_cb_(req_);
40 }
41
FSReqBase(BindingData * binding_data,v8::Local<v8::Object> req,AsyncWrap::ProviderType type,bool use_bigint)42 FSReqBase::FSReqBase(BindingData* binding_data,
43 v8::Local<v8::Object> req,
44 AsyncWrap::ProviderType type,
45 bool use_bigint)
46 : ReqWrap(binding_data->env(), req, type),
47 use_bigint_(use_bigint),
48 binding_data_(binding_data) {
49 }
50
Init(const char * syscall,const char * data,size_t len,enum encoding encoding)51 void FSReqBase::Init(const char* syscall,
52 const char* data,
53 size_t len,
54 enum encoding encoding) {
55 syscall_ = syscall;
56 encoding_ = encoding;
57
58 if (data != nullptr) {
59 CHECK(!has_data_);
60 buffer_.AllocateSufficientStorage(len + 1);
61 buffer_.SetLengthAndZeroTerminate(len);
62 memcpy(*buffer_, data, len);
63 has_data_ = true;
64 }
65 }
66
67 FSReqBase::FSReqBuffer&
Init(const char * syscall,size_t len,enum encoding encoding)68 FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) {
69 syscall_ = syscall;
70 encoding_ = encoding;
71
72 buffer_.AllocateSufficientStorage(len + 1);
73 has_data_ = false; // so that the data does not show up in error messages
74 return buffer_;
75 }
76
FSReqCallback(BindingData * binding_data,v8::Local<v8::Object> req,bool use_bigint)77 FSReqCallback::FSReqCallback(BindingData* binding_data,
78 v8::Local<v8::Object> req,
79 bool use_bigint)
80 : FSReqBase(binding_data,
81 req,
82 AsyncWrap::PROVIDER_FSREQCALLBACK,
83 use_bigint) {}
84
85 template <typename NativeT, typename V8T>
FillStatsArray(AliasedBufferBase<NativeT,V8T> * fields,const uv_stat_t * s,const size_t offset)86 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 SET_FIELD_WITH_STAT(kDev, s->st_dev);
98 SET_FIELD_WITH_STAT(kMode, s->st_mode);
99 SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
100 SET_FIELD_WITH_STAT(kUid, s->st_uid);
101 SET_FIELD_WITH_STAT(kGid, s->st_gid);
102 SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
103 SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
104 SET_FIELD_WITH_STAT(kIno, s->st_ino);
105 SET_FIELD_WITH_STAT(kSize, s->st_size);
106 SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);
107
108 SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
109 SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
110 SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
111 SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
112 SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
113 SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
114 SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
115 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 }
120
FillGlobalStatsArray(BindingData * binding_data,const bool use_bigint,const uv_stat_t * s,const bool second)121 v8::Local<v8::Value> FillGlobalStatsArray(BindingData* binding_data,
122 const bool use_bigint,
123 const uv_stat_t* s,
124 const bool second) {
125 const ptrdiff_t offset =
126 second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
127 if (use_bigint) {
128 auto* const arr = &binding_data->stats_field_bigint_array;
129 FillStatsArray(arr, s, offset);
130 return arr->GetJSArray();
131 } else {
132 auto* const arr = &binding_data->stats_field_array;
133 FillStatsArray(arr, s, offset);
134 return arr->GetJSArray();
135 }
136 }
137
138 template <typename AliasedBufferT>
139 FSReqPromise<AliasedBufferT>*
New(BindingData * binding_data,bool use_bigint)140 FSReqPromise<AliasedBufferT>::New(BindingData* binding_data,
141 bool use_bigint) {
142 Environment* env = binding_data->env();
143 v8::Local<v8::Object> obj;
144 if (!env->fsreqpromise_constructor_template()
145 ->NewInstance(env->context())
146 .ToLocal(&obj)) {
147 return nullptr;
148 }
149 v8::Local<v8::Promise::Resolver> resolver;
150 if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
151 obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
152 return nullptr;
153 }
154 return new FSReqPromise(binding_data, obj, use_bigint);
155 }
156
157 template <typename AliasedBufferT>
~FSReqPromise()158 FSReqPromise<AliasedBufferT>::~FSReqPromise() {
159 // Validate that the promise was explicitly resolved or rejected.
160 CHECK(finished_);
161 }
162
163 template <typename AliasedBufferT>
FSReqPromise(BindingData * binding_data,v8::Local<v8::Object> obj,bool use_bigint)164 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 static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
175
176 template <typename AliasedBufferT>
Reject(v8::Local<v8::Value> reject)177 void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
178 finished_ = true;
179 v8::HandleScope scope(env()->isolate());
180 InternalCallbackScope callback_scope(this);
181 v8::Local<v8::Value> value =
182 object()->Get(env()->context(),
183 env()->promise_string()).ToLocalChecked();
184 v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
185 USE(resolver->Reject(env()->context(), reject).FromJust());
186 }
187
188 template <typename AliasedBufferT>
Resolve(v8::Local<v8::Value> value)189 void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) {
190 finished_ = true;
191 v8::HandleScope scope(env()->isolate());
192 InternalCallbackScope callback_scope(this);
193 v8::Local<v8::Value> val =
194 object()->Get(env()->context(),
195 env()->promise_string()).ToLocalChecked();
196 v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
197 USE(resolver->Resolve(env()->context(), value).FromJust());
198 }
199
200 template <typename AliasedBufferT>
ResolveStat(const uv_stat_t * stat)201 void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) {
202 FillStatsArray(&stats_field_array_, stat);
203 Resolve(stats_field_array_.GetJSArray());
204 }
205
206 template <typename AliasedBufferT>
SetReturnValue(const v8::FunctionCallbackInfo<v8::Value> & args)207 void FSReqPromise<AliasedBufferT>::SetReturnValue(
208 const v8::FunctionCallbackInfo<v8::Value>& args) {
209 v8::Local<v8::Value> val =
210 object()->Get(env()->context(),
211 env()->promise_string()).ToLocalChecked();
212 v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
213 args.GetReturnValue().Set(resolver->GetPromise());
214 }
215
216 template <typename AliasedBufferT>
MemoryInfo(MemoryTracker * tracker)217 void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const {
218 FSReqBase::MemoryInfo(tracker);
219 tracker->TrackField("stats_field_array", stats_field_array_);
220 }
221
GetReqWrap(const v8::FunctionCallbackInfo<v8::Value> & args,int index,bool use_bigint)222 FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo<v8::Value>& args,
223 int index,
224 bool use_bigint) {
225 v8::Local<v8::Value> value = args[index];
226 if (value->IsObject()) {
227 return Unwrap<FSReqBase>(value.As<v8::Object>());
228 }
229
230 BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
231 Environment* env = binding_data->env();
232 if (value->StrictEquals(env->fs_use_promises_symbol())) {
233 if (use_bigint) {
234 return FSReqPromise<AliasedBigUint64Array>::New(binding_data, use_bigint);
235 } else {
236 return FSReqPromise<AliasedFloat64Array>::New(binding_data, use_bigint);
237 }
238 }
239 return nullptr;
240 }
241
242 // Returns nullptr if the operation fails from the start.
243 template <typename Func, typename... Args>
AsyncDestCall(Environment * env,FSReqBase * req_wrap,const v8::FunctionCallbackInfo<v8::Value> & args,const char * syscall,const char * dest,size_t len,enum encoding enc,uv_fs_cb after,Func fn,Args...fn_args)244 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 CHECK_NOT_NULL(req_wrap);
250 req_wrap->Init(syscall, dest, len, enc);
251 int err = req_wrap->Dispatch(fn, fn_args..., after);
252 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 req_wrap->SetReturnValue(args);
260 }
261
262 return req_wrap;
263 }
264
265 // Returns nullptr if the operation fails from the start.
266 template <typename Func, typename... Args>
AsyncCall(Environment * env,FSReqBase * req_wrap,const v8::FunctionCallbackInfo<v8::Value> & args,const char * syscall,enum encoding enc,uv_fs_cb after,Func fn,Args...fn_args)267 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 return AsyncDestCall(env, req_wrap, args,
273 syscall, nullptr, 0, enc,
274 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>
SyncCall(Environment * env,v8::Local<v8::Value> ctx,FSReqWrapSync * req_wrap,const char * syscall,Func fn,Args...args)282 int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
283 FSReqWrapSync* req_wrap, const char* syscall,
284 Func fn, Args... args) {
285 env->PrintSyncTrace();
286 int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
287 if (err < 0) {
288 v8::Local<v8::Context> context = env->context();
289 v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>();
290 v8::Isolate* isolate = env->isolate();
291 ctx_obj->Set(context,
292 env->errno_string(),
293 v8::Integer::New(isolate, err)).Check();
294 ctx_obj->Set(context,
295 env->syscall_string(),
296 OneByteString(isolate, syscall)).Check();
297 }
298 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_
307