• 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(Environment * env,v8::Local<v8::Object> req,AsyncWrap::ProviderType type,bool use_bigint)42 FSReqBase::FSReqBase(Environment* env,
43           v8::Local<v8::Object> req,
44           AsyncWrap::ProviderType type,
45           bool use_bigint)
46   : ReqWrap(env, req, type), use_bigint_(use_bigint) {
47 }
48 
Init(const char * syscall,const char * data,size_t len,enum encoding encoding)49 void FSReqBase::Init(const char* syscall,
50                      const char* data,
51                      size_t len,
52                      enum encoding encoding) {
53   syscall_ = syscall;
54   encoding_ = encoding;
55 
56   if (data != nullptr) {
57     CHECK(!has_data_);
58     buffer_.AllocateSufficientStorage(len + 1);
59     buffer_.SetLengthAndZeroTerminate(len);
60     memcpy(*buffer_, data, len);
61     has_data_ = true;
62   }
63 }
64 
65 FSReqBase::FSReqBuffer&
Init(const char * syscall,size_t len,enum encoding encoding)66 FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) {
67   syscall_ = syscall;
68   encoding_ = encoding;
69 
70   buffer_.AllocateSufficientStorage(len + 1);
71   has_data_ = false;  // so that the data does not show up in error messages
72   return buffer_;
73 }
74 
FSReqCallback(Environment * env,v8::Local<v8::Object> req,bool use_bigint)75 FSReqCallback::FSReqCallback(Environment* env,
76                              v8::Local<v8::Object> req, bool use_bigint)
77   : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) {}
78 
79 template <typename NativeT, typename V8T>
FillStatsArray(AliasedBufferBase<NativeT,V8T> * fields,const uv_stat_t * s,const size_t offset)80 void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
81                     const uv_stat_t* s,
82                     const size_t offset) {
83 #define SET_FIELD_WITH_STAT(stat_offset, stat)                               \
84   fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \
85                    static_cast<NativeT>(stat))
86 
87 #define SET_FIELD_WITH_TIME_STAT(stat_offset, stat)                          \
88   /* NOLINTNEXTLINE(runtime/int) */                                          \
89   SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat))
90 
91   SET_FIELD_WITH_STAT(kDev, s->st_dev);
92   SET_FIELD_WITH_STAT(kMode, s->st_mode);
93   SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
94   SET_FIELD_WITH_STAT(kUid, s->st_uid);
95   SET_FIELD_WITH_STAT(kGid, s->st_gid);
96   SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
97   SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
98   SET_FIELD_WITH_STAT(kIno, s->st_ino);
99   SET_FIELD_WITH_STAT(kSize, s->st_size);
100   SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);
101 
102   SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
103   SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
104   SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
105   SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
106   SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
107   SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
108   SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
109   SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec);
110 
111 #undef SET_FIELD_WITH_TIME_STAT
112 #undef SET_FIELD_WITH_STAT
113 }
114 
FillGlobalStatsArray(Environment * env,const bool use_bigint,const uv_stat_t * s,const bool second)115 v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
116                                           const bool use_bigint,
117                                           const uv_stat_t* s,
118                                           const bool second) {
119   const ptrdiff_t offset =
120       second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0;
121   if (use_bigint) {
122     auto* const arr = env->fs_stats_field_bigint_array();
123     FillStatsArray(arr, s, offset);
124     return arr->GetJSArray();
125   } else {
126     auto* const arr = env->fs_stats_field_array();
127     FillStatsArray(arr, s, offset);
128     return arr->GetJSArray();
129   }
130 }
131 
132 template <typename AliasedBufferT>
133 FSReqPromise<AliasedBufferT>*
New(Environment * env,bool use_bigint)134 FSReqPromise<AliasedBufferT>::New(Environment* env, bool use_bigint) {
135   v8::Local<v8::Object> obj;
136   if (!env->fsreqpromise_constructor_template()
137            ->NewInstance(env->context())
138            .ToLocal(&obj)) {
139     return nullptr;
140   }
141   v8::Local<v8::Promise::Resolver> resolver;
142   if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
143       obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
144     return nullptr;
145   }
146   return new FSReqPromise(env, obj, use_bigint);
147 }
148 
149 template <typename AliasedBufferT>
~FSReqPromise()150 FSReqPromise<AliasedBufferT>::~FSReqPromise() {
151   // Validate that the promise was explicitly resolved or rejected.
152   CHECK(finished_);
153 }
154 
155 template <typename AliasedBufferT>
FSReqPromise(Environment * env,v8::Local<v8::Object> obj,bool use_bigint)156 FSReqPromise<AliasedBufferT>::FSReqPromise(
157     Environment* env,
158     v8::Local<v8::Object> obj,
159     bool use_bigint)
160   : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
161     stats_field_array_(
162         env->isolate(),
163         static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}
164 
165 template <typename AliasedBufferT>
Reject(v8::Local<v8::Value> reject)166 void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
167   finished_ = true;
168   v8::HandleScope scope(env()->isolate());
169   InternalCallbackScope callback_scope(this);
170   v8::Local<v8::Value> value =
171       object()->Get(env()->context(),
172                     env()->promise_string()).ToLocalChecked();
173   v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
174   USE(resolver->Reject(env()->context(), reject).FromJust());
175 }
176 
177 template <typename AliasedBufferT>
Resolve(v8::Local<v8::Value> value)178 void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) {
179   finished_ = true;
180   v8::HandleScope scope(env()->isolate());
181   InternalCallbackScope callback_scope(this);
182   v8::Local<v8::Value> val =
183       object()->Get(env()->context(),
184                     env()->promise_string()).ToLocalChecked();
185   v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
186   USE(resolver->Resolve(env()->context(), value).FromJust());
187 }
188 
189 template <typename AliasedBufferT>
ResolveStat(const uv_stat_t * stat)190 void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) {
191   FillStatsArray(&stats_field_array_, stat);
192   Resolve(stats_field_array_.GetJSArray());
193 }
194 
195 template <typename AliasedBufferT>
SetReturnValue(const v8::FunctionCallbackInfo<v8::Value> & args)196 void FSReqPromise<AliasedBufferT>::SetReturnValue(
197     const v8::FunctionCallbackInfo<v8::Value>& args) {
198   v8::Local<v8::Value> val =
199       object()->Get(env()->context(),
200                     env()->promise_string()).ToLocalChecked();
201   v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
202   args.GetReturnValue().Set(resolver->GetPromise());
203 }
204 
205 template <typename AliasedBufferT>
MemoryInfo(MemoryTracker * tracker)206 void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const {
207   FSReqBase::MemoryInfo(tracker);
208   tracker->TrackField("stats_field_array", stats_field_array_);
209 }
210 
GetReqWrap(Environment * env,v8::Local<v8::Value> value,bool use_bigint)211 FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
212                       bool use_bigint) {
213   if (value->IsObject()) {
214     return Unwrap<FSReqBase>(value.As<v8::Object>());
215   } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
216     if (use_bigint) {
217       return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
218     } else {
219       return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
220     }
221   }
222   return nullptr;
223 }
224 
225 // Returns nullptr if the operation fails from the start.
226 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)227 FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
228                          const v8::FunctionCallbackInfo<v8::Value>& args,
229                          const char* syscall, const char* dest,
230                          size_t len, enum encoding enc, uv_fs_cb after,
231                          Func fn, Args... fn_args) {
232   CHECK_NOT_NULL(req_wrap);
233   req_wrap->Init(syscall, dest, len, enc);
234   int err = req_wrap->Dispatch(fn, fn_args..., after);
235   if (err < 0) {
236     uv_fs_t* uv_req = req_wrap->req();
237     uv_req->result = err;
238     uv_req->path = nullptr;
239     after(uv_req);  // after may delete req_wrap if there is an error
240     req_wrap = nullptr;
241   } else {
242     req_wrap->SetReturnValue(args);
243   }
244 
245   return req_wrap;
246 }
247 
248 // Returns nullptr if the operation fails from the start.
249 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)250 FSReqBase* AsyncCall(Environment* env,
251                      FSReqBase* req_wrap,
252                      const v8::FunctionCallbackInfo<v8::Value>& args,
253                      const char* syscall, enum encoding enc,
254                      uv_fs_cb after, Func fn, Args... fn_args) {
255   return AsyncDestCall(env, req_wrap, args,
256                        syscall, nullptr, 0, enc,
257                        after, fn, fn_args...);
258 }
259 
260 // Template counterpart of SYNC_CALL, except that it only puts
261 // the error number and the syscall in the context instead of
262 // creating an error in the C++ land.
263 // ctx must be checked using value->IsObject() before being passed.
264 template <typename Func, typename... Args>
SyncCall(Environment * env,v8::Local<v8::Value> ctx,FSReqWrapSync * req_wrap,const char * syscall,Func fn,Args...args)265 int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
266              FSReqWrapSync* req_wrap, const char* syscall,
267              Func fn, Args... args) {
268   env->PrintSyncTrace();
269   int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
270   if (err < 0) {
271     v8::Local<v8::Context> context = env->context();
272     v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>();
273     v8::Isolate* isolate = env->isolate();
274     ctx_obj->Set(context,
275                  env->errno_string(),
276                  v8::Integer::New(isolate, err)).Check();
277     ctx_obj->Set(context,
278                  env->syscall_string(),
279                  OneByteString(isolate, syscall)).Check();
280   }
281   return err;
282 }
283 
284 }  // namespace fs
285 }  // namespace node
286 
287 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
288 
289 #endif  // SRC_NODE_FILE_INL_H_
290