• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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