• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 #include "node_file.h"  // NOLINT(build/include_inline)
22 #include "node_file-inl.h"
23 #include "aliased_buffer.h"
24 #include "memory_tracker-inl.h"
25 #include "node_buffer.h"
26 #include "node_process-inl.h"
27 #include "node_stat_watcher.h"
28 #include "util-inl.h"
29 
30 #include "tracing/trace_event.h"
31 
32 #include "req_wrap-inl.h"
33 #include "stream_base-inl.h"
34 #include "string_bytes.h"
35 
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <cstring>
40 #include <cerrno>
41 #include <climits>
42 
43 #if defined(__MINGW32__) || defined(_MSC_VER)
44 # include <io.h>
45 #endif
46 
47 #include <memory>
48 
49 namespace node {
50 
51 namespace fs {
52 
53 using v8::Array;
54 using v8::BigInt;
55 using v8::Boolean;
56 using v8::Context;
57 using v8::EscapableHandleScope;
58 using v8::Function;
59 using v8::FunctionCallbackInfo;
60 using v8::FunctionTemplate;
61 using v8::HandleScope;
62 using v8::Int32;
63 using v8::Integer;
64 using v8::Isolate;
65 using v8::Local;
66 using v8::MaybeLocal;
67 using v8::Number;
68 using v8::Object;
69 using v8::ObjectTemplate;
70 using v8::Promise;
71 using v8::String;
72 using v8::Symbol;
73 using v8::Undefined;
74 using v8::Value;
75 
76 #ifndef S_ISDIR
77 # define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
78 #endif
79 
80 #ifdef __POSIX__
81 constexpr char kPathSeparator = '/';
82 #else
83 const char* const kPathSeparator = "\\/";
84 #endif
85 
Basename(const std::string & str,const std::string & extension)86 std::string Basename(const std::string& str, const std::string& extension) {
87   // Remove everything leading up to and including the final path separator.
88   std::string::size_type pos = str.find_last_of(kPathSeparator);
89 
90   // Starting index for the resulting string
91   std::size_t start_pos = 0;
92   // String size to return
93   std::size_t str_size = str.size();
94   if (pos != std::string::npos) {
95     start_pos = pos + 1;
96     str_size -= start_pos;
97   }
98 
99   // Strip away the extension, if any.
100   if (str_size >= extension.size() &&
101       str.compare(str.size() - extension.size(),
102         extension.size(), extension) == 0) {
103     str_size -= extension.size();
104   }
105 
106   return str.substr(start_pos, str_size);
107 }
108 
GetOffset(Local<Value> value)109 inline int64_t GetOffset(Local<Value> value) {
110   return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
111 }
112 
113 #define TRACE_NAME(name) "fs.sync." #name
114 #define GET_TRACE_ENABLED                                                  \
115   (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
116   (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
117 #define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
118   if (GET_TRACE_ENABLED)                                                   \
119   TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
120   ##__VA_ARGS__);
121 #define FS_SYNC_TRACE_END(syscall, ...)                                    \
122   if (GET_TRACE_ENABLED)                                                   \
123   TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
124   ##__VA_ARGS__);
125 
126 // We sometimes need to convert a C++ lambda function to a raw C-style function.
127 // This is helpful, because ReqWrap::Dispatch() does not recognize lambda
128 // functions, and thus does not wrap them properly.
129 typedef void(*uv_fs_callback_t)(uv_fs_t*);
130 
131 
MemoryInfo(MemoryTracker * tracker) const132 void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
133   tracker->TrackField("paths", paths_);
134 }
135 
136 FileHandleReadWrap::~FileHandleReadWrap() = default;
137 
138 FSReqBase::~FSReqBase() = default;
139 
MemoryInfo(MemoryTracker * tracker) const140 void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
141   tracker->TrackField("continuation_data", continuation_data_);
142 }
143 
144 // The FileHandle object wraps a file descriptor and will close it on garbage
145 // collection if necessary. If that happens, a process warning will be
146 // emitted (or a fatal exception will occur if the fd cannot be closed.)
FileHandle(BindingData * binding_data,Local<Object> obj,int fd)147 FileHandle::FileHandle(BindingData* binding_data,
148                        Local<Object> obj, int fd)
149     : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
150       StreamBase(env()),
151       fd_(fd),
152       binding_data_(binding_data) {
153   MakeWeak();
154   StreamBase::AttachToObject(GetObject());
155 }
156 
New(BindingData * binding_data,int fd,Local<Object> obj)157 FileHandle* FileHandle::New(BindingData* binding_data,
158                             int fd, Local<Object> obj) {
159   Environment* env = binding_data->env();
160   if (obj.IsEmpty() && !env->fd_constructor_template()
161                             ->NewInstance(env->context())
162                             .ToLocal(&obj)) {
163     return nullptr;
164   }
165   return new FileHandle(binding_data, obj, fd);
166 }
167 
New(const FunctionCallbackInfo<Value> & args)168 void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
169   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
170   Environment* env = binding_data->env();
171   CHECK(args.IsConstructCall());
172   CHECK(args[0]->IsInt32());
173 
174   FileHandle* handle =
175       FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
176   if (handle == nullptr) return;
177   if (args[1]->IsNumber())
178     handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
179   if (args[2]->IsNumber())
180     handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
181 }
182 
~FileHandle()183 FileHandle::~FileHandle() {
184   CHECK(!closing_);  // We should not be deleting while explicitly closing!
185   Close();           // Close synchronously and emit warning
186   CHECK(closed_);    // We have to be closed at the point
187 }
188 
DoWrite(WriteWrap * w,uv_buf_t * bufs,size_t count,uv_stream_t * send_handle)189 int FileHandle::DoWrite(WriteWrap* w,
190                         uv_buf_t* bufs,
191                         size_t count,
192                         uv_stream_t* send_handle) {
193   return UV_ENOSYS;  // Not implemented (yet).
194 }
195 
MemoryInfo(MemoryTracker * tracker) const196 void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
197   tracker->TrackField("current_read", current_read_);
198 }
199 
GetTransferMode() const200 FileHandle::TransferMode FileHandle::GetTransferMode() const {
201   return reading_ || closing_ || closed_ ?
202       TransferMode::kUntransferable : TransferMode::kTransferable;
203 }
204 
TransferForMessaging()205 std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
206   CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
207   auto ret = std::make_unique<TransferData>(fd_);
208   closed_ = true;
209   return ret;
210 }
211 
TransferData(int fd)212 FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
213 
~TransferData()214 FileHandle::TransferData::~TransferData() {
215   if (fd_ > 0) {
216     uv_fs_t close_req;
217     CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
218     uv_fs_req_cleanup(&close_req);
219   }
220 }
221 
Deserialize(Environment * env,v8::Local<v8::Context> context,std::unique_ptr<worker::TransferData> self)222 BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
223     Environment* env,
224     v8::Local<v8::Context> context,
225     std::unique_ptr<worker::TransferData> self) {
226   BindingData* bd = Environment::GetBindingData<BindingData>(context);
227   if (bd == nullptr) return {};
228 
229   int fd = fd_;
230   fd_ = -1;
231   return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
232 }
233 
234 // Close the file descriptor if it hasn't already been closed. A process
235 // warning will be emitted using a SetImmediate to avoid calling back to
236 // JS during GC. If closing the fd fails at this point, a fatal exception
237 // will crash the process immediately.
Close()238 inline void FileHandle::Close() {
239   if (closed_) return;
240   uv_fs_t req;
241   int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
242   uv_fs_req_cleanup(&req);
243 
244   struct err_detail { int ret; int fd; };
245 
246   err_detail detail { ret, fd_ };
247 
248   AfterClose();
249 
250   if (ret < 0) {
251     // Do not unref this
252     env()->SetImmediate([detail](Environment* env) {
253       char msg[70];
254       snprintf(msg, arraysize(msg),
255               "Closing file descriptor %d on garbage collection failed",
256               detail.fd);
257       // This exception will end up being fatal for the process because
258       // it is being thrown from within the SetImmediate handler and
259       // there is no JS stack to bubble it to. In other words, tearing
260       // down the process is the only reasonable thing we can do here.
261       HandleScope handle_scope(env->isolate());
262       env->ThrowUVException(detail.ret, "close", msg);
263     });
264     return;
265   }
266 
267   // If the close was successful, we still want to emit a process warning
268   // to notify that the file descriptor was gc'd. We want to be noisy about
269   // this because not explicitly closing the FileHandle is a bug.
270 
271   env()->SetImmediate([detail](Environment* env) {
272     ProcessEmitWarning(env,
273                        "Closing file descriptor %d on garbage collection",
274                        detail.fd);
275     if (env->filehandle_close_warning()) {
276       env->set_filehandle_close_warning(false);
277       ProcessEmitDeprecationWarning(
278           env,
279           "Closing a FileHandle object on garbage collection is deprecated. "
280           "Please close FileHandle objects explicitly using "
281           "FileHandle.prototype.close(). In the future, an error will be "
282           "thrown if a file descriptor is closed during garbage collection.",
283           "DEP0137").IsNothing();
284     }
285   }, CallbackFlags::kUnrefed);
286 }
287 
Resolve()288 void FileHandle::CloseReq::Resolve() {
289   Isolate* isolate = env()->isolate();
290   HandleScope scope(isolate);
291   Context::Scope context_scope(env()->context());
292   InternalCallbackScope callback_scope(this);
293   Local<Promise> promise = promise_.Get(isolate);
294   Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
295   resolver->Resolve(env()->context(), Undefined(isolate)).Check();
296 }
297 
Reject(Local<Value> reason)298 void FileHandle::CloseReq::Reject(Local<Value> reason) {
299   Isolate* isolate = env()->isolate();
300   HandleScope scope(isolate);
301   Context::Scope context_scope(env()->context());
302   InternalCallbackScope callback_scope(this);
303   Local<Promise> promise = promise_.Get(isolate);
304   Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
305   resolver->Reject(env()->context(), reason).Check();
306 }
307 
file_handle()308 FileHandle* FileHandle::CloseReq::file_handle() {
309   Isolate* isolate = env()->isolate();
310   HandleScope scope(isolate);
311   Local<Value> val = ref_.Get(isolate);
312   Local<Object> obj = val.As<Object>();
313   return Unwrap<FileHandle>(obj);
314 }
315 
CloseReq(Environment * env,Local<Object> obj,Local<Promise> promise,Local<Value> ref)316 FileHandle::CloseReq::CloseReq(Environment* env,
317                                Local<Object> obj,
318                                Local<Promise> promise,
319                                Local<Value> ref)
320   : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
321   promise_.Reset(env->isolate(), promise);
322   ref_.Reset(env->isolate(), ref);
323 }
324 
~CloseReq()325 FileHandle::CloseReq::~CloseReq() {
326   uv_fs_req_cleanup(req());
327   promise_.Reset();
328   ref_.Reset();
329 }
330 
MemoryInfo(MemoryTracker * tracker) const331 void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
332   tracker->TrackField("promise", promise_);
333   tracker->TrackField("ref", ref_);
334 }
335 
336 
337 
338 // Closes this FileHandle asynchronously and returns a Promise that will be
339 // resolved when the callback is invoked, or rejects with a UVException if
340 // there was a problem closing the fd. This is the preferred mechanism for
341 // closing the FD object even tho the object will attempt to close
342 // automatically on gc.
ClosePromise()343 MaybeLocal<Promise> FileHandle::ClosePromise() {
344   Isolate* isolate = env()->isolate();
345   EscapableHandleScope scope(isolate);
346   Local<Context> context = env()->context();
347   auto maybe_resolver = Promise::Resolver::New(context);
348   CHECK(!maybe_resolver.IsEmpty());
349   Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
350   Local<Promise> promise = resolver.As<Promise>();
351   CHECK(!reading_);
352   if (!closed_ && !closing_) {
353     closing_ = true;
354     Local<Object> close_req_obj;
355     if (!env()
356              ->fdclose_constructor_template()
357              ->NewInstance(env()->context())
358              .ToLocal(&close_req_obj)) {
359       return MaybeLocal<Promise>();
360     }
361     CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
362     auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
363       std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
364       CHECK_NOT_NULL(close);
365       close->file_handle()->AfterClose();
366       Isolate* isolate = close->env()->isolate();
367       if (req->result < 0) {
368         HandleScope handle_scope(isolate);
369         close->Reject(UVException(isolate, req->result, "close"));
370       } else {
371         close->Resolve();
372       }
373     }};
374     int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
375     if (ret < 0) {
376       req->Reject(UVException(isolate, ret, "close"));
377       delete req;
378     }
379   } else {
380     // Already closed. Just reject the promise immediately
381     resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
382         .Check();
383   }
384   return scope.Escape(promise);
385 }
386 
Close(const FunctionCallbackInfo<Value> & args)387 void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
388   FileHandle* fd;
389   ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
390   Local<Promise> ret;
391   if (!fd->ClosePromise().ToLocal(&ret)) return;
392   args.GetReturnValue().Set(ret);
393 }
394 
395 
ReleaseFD(const FunctionCallbackInfo<Value> & args)396 void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
397   FileHandle* fd;
398   ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
399   // Just act as if this FileHandle has been closed.
400   fd->AfterClose();
401 }
402 
403 
AfterClose()404 void FileHandle::AfterClose() {
405   closing_ = false;
406   closed_ = true;
407   fd_ = -1;
408   if (reading_ && !persistent().IsEmpty())
409     EmitRead(UV_EOF);
410 }
411 
MemoryInfo(MemoryTracker * tracker) const412 void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
413   tracker->TrackField("buffer", buffer_);
414   tracker->TrackField("file_handle", this->file_handle_);
415 }
416 
FileHandleReadWrap(FileHandle * handle,Local<Object> obj)417 FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
418   : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
419     file_handle_(handle) {}
420 
ReadStart()421 int FileHandle::ReadStart() {
422   if (!IsAlive() || IsClosing())
423     return UV_EOF;
424 
425   reading_ = true;
426 
427   if (current_read_)
428     return 0;
429 
430   BaseObjectPtr<FileHandleReadWrap> read_wrap;
431 
432   if (read_length_ == 0) {
433     EmitRead(UV_EOF);
434     return 0;
435   }
436 
437   {
438     // Create a new FileHandleReadWrap or re-use one.
439     // Either way, we need these two scopes for AsyncReset() or otherwise
440     // for creating the new instance.
441     HandleScope handle_scope(env()->isolate());
442     AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
443 
444     auto& freelist = binding_data_->file_handle_read_wrap_freelist;
445     if (freelist.size() > 0) {
446       read_wrap = std::move(freelist.back());
447       freelist.pop_back();
448       // Use a fresh async resource.
449       // Lifetime is ensured via AsyncWrap::resource_.
450       Local<Object> resource = Object::New(env()->isolate());
451       USE(resource->Set(
452           env()->context(), env()->handle_string(), read_wrap->object()));
453       read_wrap->AsyncReset(resource);
454       read_wrap->file_handle_ = this;
455     } else {
456       Local<Object> wrap_obj;
457       if (!env()
458                ->filehandlereadwrap_template()
459                ->NewInstance(env()->context())
460                .ToLocal(&wrap_obj)) {
461         return UV_EBUSY;
462       }
463       read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
464     }
465   }
466   int64_t recommended_read = 65536;
467   if (read_length_ >= 0 && read_length_ <= recommended_read)
468     recommended_read = read_length_;
469 
470   read_wrap->buffer_ = EmitAlloc(recommended_read);
471 
472   current_read_ = std::move(read_wrap);
473 
474   current_read_->Dispatch(uv_fs_read,
475                           fd_,
476                           &current_read_->buffer_,
477                           1,
478                           read_offset_,
479                           uv_fs_callback_t{[](uv_fs_t* req) {
480     FileHandle* handle;
481     {
482       FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
483       handle = req_wrap->file_handle_;
484       CHECK_EQ(handle->current_read_.get(), req_wrap);
485     }
486 
487     // ReadStart() checks whether current_read_ is set to determine whether
488     // a read is in progress. Moving it into a local variable makes sure that
489     // the ReadStart() call below doesn't think we're still actively reading.
490     BaseObjectPtr<FileHandleReadWrap> read_wrap =
491         std::move(handle->current_read_);
492 
493     int result = req->result;
494     uv_buf_t buffer = read_wrap->buffer_;
495 
496     uv_fs_req_cleanup(req);
497 
498     // Push the read wrap back to the freelist, or let it be destroyed
499     // once we’re exiting the current scope.
500     constexpr size_t kWantedFreelistFill = 100;
501     auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
502     if (freelist.size() < kWantedFreelistFill) {
503       read_wrap->Reset();
504       freelist.emplace_back(std::move(read_wrap));
505     }
506 
507     if (result >= 0) {
508       // Read at most as many bytes as we originally planned to.
509       if (handle->read_length_ >= 0 && handle->read_length_ < result)
510         result = handle->read_length_;
511 
512       // If we read data and we have an expected length, decrease it by
513       // how much we have read.
514       if (handle->read_length_ >= 0)
515         handle->read_length_ -= result;
516 
517       // If we have an offset, increase it by how much we have read.
518       if (handle->read_offset_ >= 0)
519         handle->read_offset_ += result;
520     }
521 
522     // Reading 0 bytes from a file always means EOF, or that we reached
523     // the end of the requested range.
524     if (result == 0)
525       result = UV_EOF;
526 
527     handle->EmitRead(result, buffer);
528 
529     // Start over, if EmitRead() didn’t tell us to stop.
530     if (handle->reading_)
531       handle->ReadStart();
532   }});
533 
534   return 0;
535 }
536 
ReadStop()537 int FileHandle::ReadStop() {
538   reading_ = false;
539   return 0;
540 }
541 
542 typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
543 
CreateShutdownWrap(Local<Object> object)544 ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
545   return new FileHandleCloseWrap(this, object);
546 }
547 
DoShutdown(ShutdownWrap * req_wrap)548 int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
549   FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
550   closing_ = true;
551   wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
552     FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
553         FileHandleCloseWrap::from_req(req));
554     FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
555     handle->AfterClose();
556 
557     int result = req->result;
558     uv_fs_req_cleanup(req);
559     wrap->Done(result);
560   }});
561 
562   return 0;
563 }
564 
565 
Reject(Local<Value> reject)566 void FSReqCallback::Reject(Local<Value> reject) {
567   MakeCallback(env()->oncomplete_string(), 1, &reject);
568 }
569 
ResolveStat(const uv_stat_t * stat)570 void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
571   Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
572 }
573 
Resolve(Local<Value> value)574 void FSReqCallback::Resolve(Local<Value> value) {
575   Local<Value> argv[2] {
576     Null(env()->isolate()),
577     value
578   };
579   MakeCallback(env()->oncomplete_string(),
580                value->IsUndefined() ? 1 : arraysize(argv),
581                argv);
582 }
583 
SetReturnValue(const FunctionCallbackInfo<Value> & args)584 void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
585   args.GetReturnValue().SetUndefined();
586 }
587 
NewFSReqCallback(const FunctionCallbackInfo<Value> & args)588 void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
589   CHECK(args.IsConstructCall());
590   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
591   new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
592 }
593 
FSReqAfterScope(FSReqBase * wrap,uv_fs_t * req)594 FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
595     : wrap_(wrap),
596       req_(req),
597       handle_scope_(wrap->env()->isolate()),
598       context_scope_(wrap->env()->context()) {
599   CHECK_EQ(wrap_->req(), req);
600 }
601 
~FSReqAfterScope()602 FSReqAfterScope::~FSReqAfterScope() {
603   Clear();
604 }
605 
Clear()606 void FSReqAfterScope::Clear() {
607   if (!wrap_) return;
608 
609   uv_fs_req_cleanup(wrap_->req());
610   wrap_->Detach();
611   wrap_.reset();
612 }
613 
614 // TODO(joyeecheung): create a normal context object, and
615 // construct the actual errors in the JS land using the context.
616 // The context should include fds for some fs APIs, currently they are
617 // missing in the error messages. The path, dest, syscall, fd, .etc
618 // can be put into the context before the binding is even invoked,
619 // the only information that has to come from the C++ layer is the
620 // error number (and possibly the syscall for abstraction),
621 // which is also why the errors should have been constructed
622 // in JS for more flexibility.
Reject(uv_fs_t * req)623 void FSReqAfterScope::Reject(uv_fs_t* req) {
624   BaseObjectPtr<FSReqBase> wrap { wrap_ };
625   Local<Value> exception =
626       UVException(wrap_->env()->isolate(),
627                   req->result,
628                   wrap_->syscall(),
629                   nullptr,
630                   req->path,
631                   wrap_->data());
632   Clear();
633   wrap->Reject(exception);
634 }
635 
Proceed()636 bool FSReqAfterScope::Proceed() {
637   if (req_->result < 0) {
638     Reject(req_);
639     return false;
640   }
641   return true;
642 }
643 
AfterNoArgs(uv_fs_t * req)644 void AfterNoArgs(uv_fs_t* req) {
645   FSReqBase* req_wrap = FSReqBase::from_req(req);
646   FSReqAfterScope after(req_wrap, req);
647 
648   if (after.Proceed())
649     req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
650 }
651 
AfterStat(uv_fs_t * req)652 void AfterStat(uv_fs_t* req) {
653   FSReqBase* req_wrap = FSReqBase::from_req(req);
654   FSReqAfterScope after(req_wrap, req);
655 
656   if (after.Proceed()) {
657     req_wrap->ResolveStat(&req->statbuf);
658   }
659 }
660 
AfterInteger(uv_fs_t * req)661 void AfterInteger(uv_fs_t* req) {
662   FSReqBase* req_wrap = FSReqBase::from_req(req);
663   FSReqAfterScope after(req_wrap, req);
664 
665   if (req->result >= 0 && req_wrap->is_plain_open())
666     req_wrap->env()->AddUnmanagedFd(req->result);
667 
668   if (after.Proceed())
669     req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
670 }
671 
AfterOpenFileHandle(uv_fs_t * req)672 void AfterOpenFileHandle(uv_fs_t* req) {
673   FSReqBase* req_wrap = FSReqBase::from_req(req);
674   FSReqAfterScope after(req_wrap, req);
675 
676   if (after.Proceed()) {
677     FileHandle* fd = FileHandle::New(req_wrap->binding_data(), req->result);
678     if (fd == nullptr) return;
679     req_wrap->Resolve(fd->object());
680   }
681 }
682 
683 // Reverse the logic applied by path.toNamespacedPath() to create a
684 // namespace-prefixed path.
FromNamespacedPath(std::string * path)685 void FromNamespacedPath(std::string* path) {
686 #ifdef _WIN32
687   if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
688     *path = path->substr(8);
689     path->insert(0, "\\\\");
690   } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
691     *path = path->substr(4);
692   }
693 #endif
694 }
695 
AfterMkdirp(uv_fs_t * req)696 void AfterMkdirp(uv_fs_t* req) {
697   FSReqBase* req_wrap = FSReqBase::from_req(req);
698   FSReqAfterScope after(req_wrap, req);
699 
700   MaybeLocal<Value> path;
701   Local<Value> error;
702 
703   if (after.Proceed()) {
704     if (!req_wrap->continuation_data()->first_path().empty()) {
705       std::string first_path(req_wrap->continuation_data()->first_path());
706       FromNamespacedPath(&first_path);
707       path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
708                                  req_wrap->encoding(),
709                                  &error);
710       if (path.IsEmpty())
711         req_wrap->Reject(error);
712       else
713         req_wrap->Resolve(path.ToLocalChecked());
714     } else {
715       req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
716     }
717   }
718 }
719 
AfterStringPath(uv_fs_t * req)720 void AfterStringPath(uv_fs_t* req) {
721   FSReqBase* req_wrap = FSReqBase::from_req(req);
722   FSReqAfterScope after(req_wrap, req);
723 
724   MaybeLocal<Value> link;
725   Local<Value> error;
726 
727   if (after.Proceed()) {
728     link = StringBytes::Encode(req_wrap->env()->isolate(),
729                                req->path,
730                                req_wrap->encoding(),
731                                &error);
732     if (link.IsEmpty())
733       req_wrap->Reject(error);
734     else
735       req_wrap->Resolve(link.ToLocalChecked());
736   }
737 }
738 
AfterStringPtr(uv_fs_t * req)739 void AfterStringPtr(uv_fs_t* req) {
740   FSReqBase* req_wrap = FSReqBase::from_req(req);
741   FSReqAfterScope after(req_wrap, req);
742 
743   MaybeLocal<Value> link;
744   Local<Value> error;
745 
746   if (after.Proceed()) {
747     link = StringBytes::Encode(req_wrap->env()->isolate(),
748                                static_cast<const char*>(req->ptr),
749                                req_wrap->encoding(),
750                                &error);
751     if (link.IsEmpty())
752       req_wrap->Reject(error);
753     else
754       req_wrap->Resolve(link.ToLocalChecked());
755   }
756 }
757 
AfterScanDir(uv_fs_t * req)758 void AfterScanDir(uv_fs_t* req) {
759   FSReqBase* req_wrap = FSReqBase::from_req(req);
760   FSReqAfterScope after(req_wrap, req);
761 
762   if (!after.Proceed()) {
763     return;
764   }
765   Environment* env = req_wrap->env();
766   Local<Value> error;
767   int r;
768   std::vector<Local<Value>> name_v;
769 
770   for (;;) {
771     uv_dirent_t ent;
772 
773     r = uv_fs_scandir_next(req, &ent);
774     if (r == UV_EOF)
775       break;
776     if (r != 0) {
777       return req_wrap->Reject(UVException(
778           env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
779     }
780 
781     MaybeLocal<Value> filename =
782       StringBytes::Encode(env->isolate(),
783           ent.name,
784           req_wrap->encoding(),
785           &error);
786     if (filename.IsEmpty())
787       return req_wrap->Reject(error);
788 
789     name_v.push_back(filename.ToLocalChecked());
790   }
791 
792   req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
793 }
794 
AfterScanDirWithTypes(uv_fs_t * req)795 void AfterScanDirWithTypes(uv_fs_t* req) {
796   FSReqBase* req_wrap = FSReqBase::from_req(req);
797   FSReqAfterScope after(req_wrap, req);
798 
799   if (!after.Proceed()) {
800     return;
801   }
802 
803   Environment* env = req_wrap->env();
804   Isolate* isolate = env->isolate();
805   Local<Value> error;
806   int r;
807 
808   std::vector<Local<Value>> name_v;
809   std::vector<Local<Value>> type_v;
810 
811   for (;;) {
812     uv_dirent_t ent;
813 
814     r = uv_fs_scandir_next(req, &ent);
815     if (r == UV_EOF)
816       break;
817     if (r != 0) {
818       return req_wrap->Reject(
819           UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
820     }
821 
822     MaybeLocal<Value> filename =
823       StringBytes::Encode(isolate,
824           ent.name,
825           req_wrap->encoding(),
826           &error);
827     if (filename.IsEmpty())
828       return req_wrap->Reject(error);
829 
830     name_v.push_back(filename.ToLocalChecked());
831     type_v.emplace_back(Integer::New(isolate, ent.type));
832   }
833 
834   Local<Value> result[] = {
835     Array::New(isolate, name_v.data(), name_v.size()),
836     Array::New(isolate, type_v.data(), type_v.size())
837   };
838   req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
839 }
840 
Access(const FunctionCallbackInfo<Value> & args)841 void Access(const FunctionCallbackInfo<Value>& args) {
842   Environment* env = Environment::GetCurrent(args);
843   Isolate* isolate = env->isolate();
844   HandleScope scope(isolate);
845 
846   const int argc = args.Length();
847   CHECK_GE(argc, 2);
848 
849   CHECK(args[1]->IsInt32());
850   int mode = args[1].As<Int32>()->Value();
851 
852   BufferValue path(isolate, args[0]);
853   CHECK_NOT_NULL(*path);
854 
855   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
856   if (req_wrap_async != nullptr) {  // access(path, mode, req)
857     AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
858               uv_fs_access, *path, mode);
859   } else {  // access(path, mode, undefined, ctx)
860     CHECK_EQ(argc, 4);
861     FSReqWrapSync req_wrap_sync;
862     FS_SYNC_TRACE_BEGIN(access);
863     SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
864     FS_SYNC_TRACE_END(access);
865   }
866 }
867 
868 
Close(const FunctionCallbackInfo<Value> & args)869 void Close(const FunctionCallbackInfo<Value>& args) {
870   Environment* env = Environment::GetCurrent(args);
871 
872   const int argc = args.Length();
873   CHECK_GE(argc, 2);
874 
875   CHECK(args[0]->IsInt32());
876   int fd = args[0].As<Int32>()->Value();
877   env->RemoveUnmanagedFd(fd);
878 
879   FSReqBase* req_wrap_async = GetReqWrap(args, 1);
880   if (req_wrap_async != nullptr) {  // close(fd, req)
881     AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
882               uv_fs_close, fd);
883   } else {  // close(fd, undefined, ctx)
884     CHECK_EQ(argc, 3);
885     FSReqWrapSync req_wrap_sync;
886     FS_SYNC_TRACE_BEGIN(close);
887     SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
888     FS_SYNC_TRACE_END(close);
889   }
890 }
891 
892 
893 // Used to speed up module loading. Returns an array [string, boolean]
InternalModuleReadJSON(const FunctionCallbackInfo<Value> & args)894 static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
895   Environment* env = Environment::GetCurrent(args);
896   Isolate* isolate = env->isolate();
897   uv_loop_t* loop = env->event_loop();
898 
899   CHECK(args[0]->IsString());
900   node::Utf8Value path(isolate, args[0]);
901 
902   if (strlen(*path) != path.length()) {
903     args.GetReturnValue().Set(Array::New(isolate));
904     return;  // Contains a nul byte.
905   }
906   uv_fs_t open_req;
907   const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
908   uv_fs_req_cleanup(&open_req);
909 
910   if (fd < 0) {
911     args.GetReturnValue().Set(Array::New(isolate));
912     return;
913   }
914 
915   auto defer_close = OnScopeLeave([fd, loop]() {
916     uv_fs_t close_req;
917     CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
918     uv_fs_req_cleanup(&close_req);
919   });
920 
921   const size_t kBlockSize = 32 << 10;
922   std::vector<char> chars;
923   int64_t offset = 0;
924   ssize_t numchars;
925   do {
926     const size_t start = chars.size();
927     chars.resize(start + kBlockSize);
928 
929     uv_buf_t buf;
930     buf.base = &chars[start];
931     buf.len = kBlockSize;
932 
933     uv_fs_t read_req;
934     numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
935     uv_fs_req_cleanup(&read_req);
936 
937     if (numchars < 0) {
938       args.GetReturnValue().Set(Array::New(isolate));
939       return;
940     }
941     offset += numchars;
942   } while (static_cast<size_t>(numchars) == kBlockSize);
943 
944   size_t start = 0;
945   if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
946     start = 3;  // Skip UTF-8 BOM.
947   }
948 
949   const size_t size = offset - start;
950   char* p = &chars[start];
951   char* pe = &chars[size];
952   char* pos[2];
953   char** ppos = &pos[0];
954 
955   while (p < pe) {
956     char c = *p++;
957     if (c == '\\' && p < pe && *p == '"') p++;
958     if (c != '"') continue;
959     *ppos++ = p;
960     if (ppos < &pos[2]) continue;
961     ppos = &pos[0];
962 
963     char* s = &pos[0][0];
964     char* se = &pos[1][-1];  // Exclude quote.
965     size_t n = se - s;
966 
967     if (n == 4) {
968       if (0 == memcmp(s, "main", 4)) break;
969       if (0 == memcmp(s, "name", 4)) break;
970       if (0 == memcmp(s, "type", 4)) break;
971     } else if (n == 7) {
972       if (0 == memcmp(s, "exports", 7)) break;
973       if (0 == memcmp(s, "imports", 7)) break;
974     }
975   }
976 
977 
978   Local<Value> return_value[] = {
979     String::NewFromUtf8(isolate,
980                         &chars[start],
981                         v8::NewStringType::kNormal,
982                         size).ToLocalChecked(),
983     Boolean::New(isolate, p < pe ? true : false)
984   };
985   args.GetReturnValue().Set(
986     Array::New(isolate, return_value, arraysize(return_value)));
987 }
988 
989 // Used to speed up module loading.  Returns 0 if the path refers to
990 // a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
991 // The speedup comes from not creating thousands of Stat and Error objects.
InternalModuleStat(const FunctionCallbackInfo<Value> & args)992 static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
993   Environment* env = Environment::GetCurrent(args);
994 
995   CHECK(args[0]->IsString());
996   node::Utf8Value path(env->isolate(), args[0]);
997 
998   uv_fs_t req;
999   int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1000   if (rc == 0) {
1001     const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1002     rc = !!(s->st_mode & S_IFDIR);
1003   }
1004   uv_fs_req_cleanup(&req);
1005 
1006   args.GetReturnValue().Set(rc);
1007 }
1008 
Stat(const FunctionCallbackInfo<Value> & args)1009 static void Stat(const FunctionCallbackInfo<Value>& args) {
1010   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1011   Environment* env = binding_data->env();
1012 
1013   const int argc = args.Length();
1014   CHECK_GE(argc, 2);
1015 
1016   BufferValue path(env->isolate(), args[0]);
1017   CHECK_NOT_NULL(*path);
1018 
1019   bool use_bigint = args[1]->IsTrue();
1020   FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1021   if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1022     AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1023               uv_fs_stat, *path);
1024   } else {  // stat(path, use_bigint, undefined, ctx)
1025     CHECK_EQ(argc, 4);
1026     FSReqWrapSync req_wrap_sync;
1027     FS_SYNC_TRACE_BEGIN(stat);
1028     int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1029     FS_SYNC_TRACE_END(stat);
1030     if (err != 0) {
1031       return;  // error info is in ctx
1032     }
1033 
1034     Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1035         static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1036     args.GetReturnValue().Set(arr);
1037   }
1038 }
1039 
LStat(const FunctionCallbackInfo<Value> & args)1040 static void LStat(const FunctionCallbackInfo<Value>& args) {
1041   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1042   Environment* env = binding_data->env();
1043 
1044   const int argc = args.Length();
1045   CHECK_GE(argc, 3);
1046 
1047   BufferValue path(env->isolate(), args[0]);
1048   CHECK_NOT_NULL(*path);
1049 
1050   bool use_bigint = args[1]->IsTrue();
1051   FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1052   if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1053     AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1054               uv_fs_lstat, *path);
1055   } else {  // lstat(path, use_bigint, undefined, ctx)
1056     CHECK_EQ(argc, 4);
1057     FSReqWrapSync req_wrap_sync;
1058     FS_SYNC_TRACE_BEGIN(lstat);
1059     int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1060                        *path);
1061     FS_SYNC_TRACE_END(lstat);
1062     if (err != 0) {
1063       return;  // error info is in ctx
1064     }
1065 
1066     Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1067         static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1068     args.GetReturnValue().Set(arr);
1069   }
1070 }
1071 
FStat(const FunctionCallbackInfo<Value> & args)1072 static void FStat(const FunctionCallbackInfo<Value>& args) {
1073   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1074   Environment* env = binding_data->env();
1075 
1076   const int argc = args.Length();
1077   CHECK_GE(argc, 2);
1078 
1079   CHECK(args[0]->IsInt32());
1080   int fd = args[0].As<Int32>()->Value();
1081 
1082   bool use_bigint = args[1]->IsTrue();
1083   FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1084   if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1085     AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1086               uv_fs_fstat, fd);
1087   } else {  // fstat(fd, use_bigint, undefined, ctx)
1088     CHECK_EQ(argc, 4);
1089     FSReqWrapSync req_wrap_sync;
1090     FS_SYNC_TRACE_BEGIN(fstat);
1091     int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1092     FS_SYNC_TRACE_END(fstat);
1093     if (err != 0) {
1094       return;  // error info is in ctx
1095     }
1096 
1097     Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1098         static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1099     args.GetReturnValue().Set(arr);
1100   }
1101 }
1102 
Symlink(const FunctionCallbackInfo<Value> & args)1103 static void Symlink(const FunctionCallbackInfo<Value>& args) {
1104   Environment* env = Environment::GetCurrent(args);
1105   Isolate* isolate = env->isolate();
1106 
1107   const int argc = args.Length();
1108   CHECK_GE(argc, 4);
1109 
1110   BufferValue target(isolate, args[0]);
1111   CHECK_NOT_NULL(*target);
1112   BufferValue path(isolate, args[1]);
1113   CHECK_NOT_NULL(*path);
1114 
1115   CHECK(args[2]->IsInt32());
1116   int flags = args[2].As<Int32>()->Value();
1117 
1118   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1119   if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1120     AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1121                   UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1122   } else {  // symlink(target, path, flags, undefinec, ctx)
1123     CHECK_EQ(argc, 5);
1124     FSReqWrapSync req_wrap_sync;
1125     FS_SYNC_TRACE_BEGIN(symlink);
1126     SyncCall(env, args[4], &req_wrap_sync, "symlink",
1127              uv_fs_symlink, *target, *path, flags);
1128     FS_SYNC_TRACE_END(symlink);
1129   }
1130 }
1131 
Link(const FunctionCallbackInfo<Value> & args)1132 static void Link(const FunctionCallbackInfo<Value>& args) {
1133   Environment* env = Environment::GetCurrent(args);
1134   Isolate* isolate = env->isolate();
1135 
1136   const int argc = args.Length();
1137   CHECK_GE(argc, 3);
1138 
1139   BufferValue src(isolate, args[0]);
1140   CHECK_NOT_NULL(*src);
1141 
1142   BufferValue dest(isolate, args[1]);
1143   CHECK_NOT_NULL(*dest);
1144 
1145   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1146   if (req_wrap_async != nullptr) {  // link(src, dest, req)
1147     AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1148                   AfterNoArgs, uv_fs_link, *src, *dest);
1149   } else {  // link(src, dest)
1150     CHECK_EQ(argc, 4);
1151     FSReqWrapSync req_wrap_sync;
1152     FS_SYNC_TRACE_BEGIN(link);
1153     SyncCall(env, args[3], &req_wrap_sync, "link",
1154              uv_fs_link, *src, *dest);
1155     FS_SYNC_TRACE_END(link);
1156   }
1157 }
1158 
ReadLink(const FunctionCallbackInfo<Value> & args)1159 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1160   Environment* env = Environment::GetCurrent(args);
1161   Isolate* isolate = env->isolate();
1162 
1163   const int argc = args.Length();
1164   CHECK_GE(argc, 3);
1165 
1166   BufferValue path(isolate, args[0]);
1167   CHECK_NOT_NULL(*path);
1168 
1169   const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1170 
1171   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1172   if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1173     AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1174               uv_fs_readlink, *path);
1175   } else {
1176     CHECK_EQ(argc, 4);
1177     FSReqWrapSync req_wrap_sync;
1178     FS_SYNC_TRACE_BEGIN(readlink);
1179     int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1180                        uv_fs_readlink, *path);
1181     FS_SYNC_TRACE_END(readlink);
1182     if (err < 0) {
1183       return;  // syscall failed, no need to continue, error info is in ctx
1184     }
1185     const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1186 
1187     Local<Value> error;
1188     MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1189                                                link_path,
1190                                                encoding,
1191                                                &error);
1192     if (rc.IsEmpty()) {
1193       Local<Object> ctx = args[3].As<Object>();
1194       ctx->Set(env->context(), env->error_string(), error).Check();
1195       return;
1196     }
1197 
1198     args.GetReturnValue().Set(rc.ToLocalChecked());
1199   }
1200 }
1201 
Rename(const FunctionCallbackInfo<Value> & args)1202 static void Rename(const FunctionCallbackInfo<Value>& args) {
1203   Environment* env = Environment::GetCurrent(args);
1204   Isolate* isolate = env->isolate();
1205 
1206   const int argc = args.Length();
1207   CHECK_GE(argc, 3);
1208 
1209   BufferValue old_path(isolate, args[0]);
1210   CHECK_NOT_NULL(*old_path);
1211   BufferValue new_path(isolate, args[1]);
1212   CHECK_NOT_NULL(*new_path);
1213 
1214   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1215   if (req_wrap_async != nullptr) {
1216     AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1217                   new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1218                   *old_path, *new_path);
1219   } else {
1220     CHECK_EQ(argc, 4);
1221     FSReqWrapSync req_wrap_sync;
1222     FS_SYNC_TRACE_BEGIN(rename);
1223     SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1224              *old_path, *new_path);
1225     FS_SYNC_TRACE_END(rename);
1226   }
1227 }
1228 
FTruncate(const FunctionCallbackInfo<Value> & args)1229 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1230   Environment* env = Environment::GetCurrent(args);
1231 
1232   const int argc = args.Length();
1233   CHECK_GE(argc, 3);
1234 
1235   CHECK(args[0]->IsInt32());
1236   const int fd = args[0].As<Int32>()->Value();
1237 
1238   CHECK(IsSafeJsInt(args[1]));
1239   const int64_t len = args[1].As<Integer>()->Value();
1240 
1241   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1242   if (req_wrap_async != nullptr) {
1243     AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1244               uv_fs_ftruncate, fd, len);
1245   } else {
1246     CHECK_EQ(argc, 4);
1247     FSReqWrapSync req_wrap_sync;
1248     FS_SYNC_TRACE_BEGIN(ftruncate);
1249     SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1250              len);
1251     FS_SYNC_TRACE_END(ftruncate);
1252   }
1253 }
1254 
Fdatasync(const FunctionCallbackInfo<Value> & args)1255 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1256   Environment* env = Environment::GetCurrent(args);
1257 
1258   const int argc = args.Length();
1259   CHECK_GE(argc, 2);
1260 
1261   CHECK(args[0]->IsInt32());
1262   const int fd = args[0].As<Int32>()->Value();
1263 
1264   FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1265   if (req_wrap_async != nullptr) {
1266     AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1267               uv_fs_fdatasync, fd);
1268   } else {
1269     CHECK_EQ(argc, 3);
1270     FSReqWrapSync req_wrap_sync;
1271     FS_SYNC_TRACE_BEGIN(fdatasync);
1272     SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1273     FS_SYNC_TRACE_END(fdatasync);
1274   }
1275 }
1276 
Fsync(const FunctionCallbackInfo<Value> & args)1277 static void Fsync(const FunctionCallbackInfo<Value>& args) {
1278   Environment* env = Environment::GetCurrent(args);
1279 
1280   const int argc = args.Length();
1281   CHECK_GE(argc, 2);
1282 
1283   CHECK(args[0]->IsInt32());
1284   const int fd = args[0].As<Int32>()->Value();
1285 
1286   FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1287   if (req_wrap_async != nullptr) {
1288     AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1289               uv_fs_fsync, fd);
1290   } else {
1291     CHECK_EQ(argc, 3);
1292     FSReqWrapSync req_wrap_sync;
1293     FS_SYNC_TRACE_BEGIN(fsync);
1294     SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1295     FS_SYNC_TRACE_END(fsync);
1296   }
1297 }
1298 
Unlink(const FunctionCallbackInfo<Value> & args)1299 static void Unlink(const FunctionCallbackInfo<Value>& args) {
1300   Environment* env = Environment::GetCurrent(args);
1301 
1302   const int argc = args.Length();
1303   CHECK_GE(argc, 2);
1304 
1305   BufferValue path(env->isolate(), args[0]);
1306   CHECK_NOT_NULL(*path);
1307 
1308   FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1309   if (req_wrap_async != nullptr) {
1310     AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1311               uv_fs_unlink, *path);
1312   } else {
1313     CHECK_EQ(argc, 3);
1314     FSReqWrapSync req_wrap_sync;
1315     FS_SYNC_TRACE_BEGIN(unlink);
1316     SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1317     FS_SYNC_TRACE_END(unlink);
1318   }
1319 }
1320 
RMDir(const FunctionCallbackInfo<Value> & args)1321 static void RMDir(const FunctionCallbackInfo<Value>& args) {
1322   Environment* env = Environment::GetCurrent(args);
1323 
1324   const int argc = args.Length();
1325   CHECK_GE(argc, 2);
1326 
1327   BufferValue path(env->isolate(), args[0]);
1328   CHECK_NOT_NULL(*path);
1329 
1330   FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1331   if (req_wrap_async != nullptr) {
1332     AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1333               uv_fs_rmdir, *path);
1334   } else {  // rmdir(path, undefined, ctx)
1335     CHECK_EQ(argc, 3);
1336     FSReqWrapSync req_wrap_sync;
1337     FS_SYNC_TRACE_BEGIN(rmdir);
1338     SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1339              uv_fs_rmdir, *path);
1340     FS_SYNC_TRACE_END(rmdir);
1341   }
1342 }
1343 
MKDirpSync(uv_loop_t * loop,uv_fs_t * req,const std::string & path,int mode,uv_fs_cb cb)1344 int MKDirpSync(uv_loop_t* loop,
1345                uv_fs_t* req,
1346                const std::string& path,
1347                int mode,
1348                uv_fs_cb cb) {
1349   FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1350 
1351   // on the first iteration of algorithm, stash state information.
1352   if (req_wrap->continuation_data() == nullptr) {
1353     req_wrap->set_continuation_data(
1354         std::make_unique<FSContinuationData>(req, mode, cb));
1355     req_wrap->continuation_data()->PushPath(std::move(path));
1356   }
1357 
1358   while (req_wrap->continuation_data()->paths().size() > 0) {
1359     std::string next_path = req_wrap->continuation_data()->PopPath();
1360     int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1361     while (true) {
1362       switch (err) {
1363         // Note: uv_fs_req_cleanup in terminal paths will be called by
1364         // ~FSReqWrapSync():
1365         case 0:
1366           req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1367           if (req_wrap->continuation_data()->paths().size() == 0) {
1368             return 0;
1369           }
1370           break;
1371         case UV_EACCES:
1372         case UV_ENOTDIR:
1373         case UV_EPERM: {
1374           return err;
1375         }
1376         case UV_ENOENT: {
1377           std::string dirname = next_path.substr(0,
1378                                         next_path.find_last_of(kPathSeparator));
1379           if (dirname != next_path) {
1380             req_wrap->continuation_data()->PushPath(std::move(next_path));
1381             req_wrap->continuation_data()->PushPath(std::move(dirname));
1382           } else if (req_wrap->continuation_data()->paths().size() == 0) {
1383             err = UV_EEXIST;
1384             continue;
1385           }
1386           break;
1387         }
1388         default:
1389           uv_fs_req_cleanup(req);
1390           int orig_err = err;
1391           err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1392           if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1393             uv_fs_req_cleanup(req);
1394             if (orig_err == UV_EEXIST &&
1395               req_wrap->continuation_data()->paths().size() > 0) {
1396               return UV_ENOTDIR;
1397             }
1398             return UV_EEXIST;
1399           }
1400           if (err < 0) return err;
1401           break;
1402       }
1403       break;
1404     }
1405     uv_fs_req_cleanup(req);
1406   }
1407 
1408   return 0;
1409 }
1410 
MKDirpAsync(uv_loop_t * loop,uv_fs_t * req,const char * path,int mode,uv_fs_cb cb)1411 int MKDirpAsync(uv_loop_t* loop,
1412                 uv_fs_t* req,
1413                 const char* path,
1414                 int mode,
1415                 uv_fs_cb cb) {
1416   FSReqBase* req_wrap = FSReqBase::from_req(req);
1417   // on the first iteration of algorithm, stash state information.
1418   if (req_wrap->continuation_data() == nullptr) {
1419     req_wrap->set_continuation_data(
1420         std::make_unique<FSContinuationData>(req, mode, cb));
1421     req_wrap->continuation_data()->PushPath(std::move(path));
1422   }
1423 
1424   // on each iteration of algorithm, mkdir directory on top of stack.
1425   std::string next_path = req_wrap->continuation_data()->PopPath();
1426   int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1427                         uv_fs_callback_t{[](uv_fs_t* req) {
1428     FSReqBase* req_wrap = FSReqBase::from_req(req);
1429     Environment* env = req_wrap->env();
1430     uv_loop_t* loop = env->event_loop();
1431     std::string path = req->path;
1432     int err = req->result;
1433 
1434     while (true) {
1435       switch (err) {
1436         // Note: uv_fs_req_cleanup in terminal paths will be called by
1437         // FSReqAfterScope::~FSReqAfterScope()
1438         case 0: {
1439           if (req_wrap->continuation_data()->paths().size() == 0) {
1440             req_wrap->continuation_data()->MaybeSetFirstPath(path);
1441             req_wrap->continuation_data()->Done(0);
1442           } else {
1443             req_wrap->continuation_data()->MaybeSetFirstPath(path);
1444             uv_fs_req_cleanup(req);
1445             MKDirpAsync(loop, req, path.c_str(),
1446                         req_wrap->continuation_data()->mode(), nullptr);
1447           }
1448           break;
1449         }
1450         case UV_EACCES:
1451         case UV_ENOTDIR:
1452         case UV_EPERM: {
1453           req_wrap->continuation_data()->Done(err);
1454           break;
1455         }
1456         case UV_ENOENT: {
1457           std::string dirname = path.substr(0,
1458                                             path.find_last_of(kPathSeparator));
1459           if (dirname != path) {
1460             req_wrap->continuation_data()->PushPath(std::move(path));
1461             req_wrap->continuation_data()->PushPath(std::move(dirname));
1462           } else if (req_wrap->continuation_data()->paths().size() == 0) {
1463             err = UV_EEXIST;
1464             continue;
1465           }
1466           uv_fs_req_cleanup(req);
1467           MKDirpAsync(loop, req, path.c_str(),
1468                       req_wrap->continuation_data()->mode(), nullptr);
1469           break;
1470         }
1471         default:
1472           uv_fs_req_cleanup(req);
1473           // Stash err for use in the callback.
1474           req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1475           int err = uv_fs_stat(loop, req, path.c_str(),
1476                                uv_fs_callback_t{[](uv_fs_t* req) {
1477             FSReqBase* req_wrap = FSReqBase::from_req(req);
1478             int err = req->result;
1479             if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1480                   req_wrap->continuation_data()->paths().size() > 0) {
1481               if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1482                 Environment* env = req_wrap->env();
1483                 uv_loop_t* loop = env->event_loop();
1484                 std::string path = req->path;
1485                 uv_fs_req_cleanup(req);
1486                 MKDirpAsync(loop, req, path.c_str(),
1487                             req_wrap->continuation_data()->mode(), nullptr);
1488                 return;
1489               }
1490               err = UV_ENOTDIR;
1491             }
1492             // verify that the path pointed to is actually a directory.
1493             if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1494             req_wrap->continuation_data()->Done(err);
1495           }});
1496           if (err < 0) req_wrap->continuation_data()->Done(err);
1497           break;
1498       }
1499       break;
1500     }
1501   }});
1502 
1503   return err;
1504 }
1505 
CallMKDirpSync(Environment * env,const FunctionCallbackInfo<Value> & args,FSReqWrapSync * req_wrap,const char * path,int mode)1506 int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1507                    FSReqWrapSync* req_wrap, const char* path, int mode) {
1508   env->PrintSyncTrace();
1509   int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1510                        nullptr);
1511   if (err < 0) {
1512     v8::Local<v8::Context> context = env->context();
1513     v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1514     v8::Isolate* isolate = env->isolate();
1515     ctx_obj->Set(context,
1516                  env->errno_string(),
1517                  v8::Integer::New(isolate, err)).Check();
1518     ctx_obj->Set(context,
1519                  env->syscall_string(),
1520                  OneByteString(isolate, "mkdir")).Check();
1521   }
1522   return err;
1523 }
1524 
MKDir(const FunctionCallbackInfo<Value> & args)1525 static void MKDir(const FunctionCallbackInfo<Value>& args) {
1526   Environment* env = Environment::GetCurrent(args);
1527 
1528   const int argc = args.Length();
1529   CHECK_GE(argc, 4);
1530 
1531   BufferValue path(env->isolate(), args[0]);
1532   CHECK_NOT_NULL(*path);
1533 
1534   CHECK(args[1]->IsInt32());
1535   const int mode = args[1].As<Int32>()->Value();
1536 
1537   CHECK(args[2]->IsBoolean());
1538   bool mkdirp = args[2]->IsTrue();
1539 
1540   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1541   if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1542     AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1543               mkdirp ? AfterMkdirp : AfterNoArgs,
1544               mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1545   } else {  // mkdir(path, mode, undefined, ctx)
1546     CHECK_EQ(argc, 5);
1547     FSReqWrapSync req_wrap_sync;
1548     FS_SYNC_TRACE_BEGIN(mkdir);
1549     if (mkdirp) {
1550       int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1551       if (err == 0 &&
1552           !req_wrap_sync.continuation_data()->first_path().empty()) {
1553         Local<Value> error;
1554         std::string first_path(req_wrap_sync.continuation_data()->first_path());
1555         FromNamespacedPath(&first_path);
1556         MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1557                                                      first_path.c_str(),
1558                                                      UTF8, &error);
1559         if (path.IsEmpty()) {
1560           Local<Object> ctx = args[4].As<Object>();
1561           ctx->Set(env->context(), env->error_string(), error).Check();
1562           return;
1563         }
1564         args.GetReturnValue().Set(path.ToLocalChecked());
1565       }
1566     } else {
1567       SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1568                uv_fs_mkdir, *path, mode);
1569     }
1570     FS_SYNC_TRACE_END(mkdir);
1571   }
1572 }
1573 
RealPath(const FunctionCallbackInfo<Value> & args)1574 static void RealPath(const FunctionCallbackInfo<Value>& args) {
1575   Environment* env = Environment::GetCurrent(args);
1576   Isolate* isolate = env->isolate();
1577 
1578   const int argc = args.Length();
1579   CHECK_GE(argc, 3);
1580 
1581   BufferValue path(isolate, args[0]);
1582   CHECK_NOT_NULL(*path);
1583 
1584   const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1585 
1586   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1587   if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1588     AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1589               uv_fs_realpath, *path);
1590   } else {  // realpath(path, encoding, undefined, ctx)
1591     CHECK_EQ(argc, 4);
1592     FSReqWrapSync req_wrap_sync;
1593     FS_SYNC_TRACE_BEGIN(realpath);
1594     int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1595                        uv_fs_realpath, *path);
1596     FS_SYNC_TRACE_END(realpath);
1597     if (err < 0) {
1598       return;  // syscall failed, no need to continue, error info is in ctx
1599     }
1600 
1601     const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1602 
1603     Local<Value> error;
1604     MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1605                                                link_path,
1606                                                encoding,
1607                                                &error);
1608     if (rc.IsEmpty()) {
1609       Local<Object> ctx = args[3].As<Object>();
1610       ctx->Set(env->context(), env->error_string(), error).Check();
1611       return;
1612     }
1613 
1614     args.GetReturnValue().Set(rc.ToLocalChecked());
1615   }
1616 }
1617 
ReadDir(const FunctionCallbackInfo<Value> & args)1618 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1619   Environment* env = Environment::GetCurrent(args);
1620   Isolate* isolate = env->isolate();
1621 
1622   const int argc = args.Length();
1623   CHECK_GE(argc, 3);
1624 
1625   BufferValue path(isolate, args[0]);
1626   CHECK_NOT_NULL(*path);
1627 
1628   const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1629 
1630   bool with_types = args[2]->IsTrue();
1631 
1632   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1633   if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1634     if (with_types) {
1635       AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1636                 AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1637     } else {
1638       AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1639                 AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1640     }
1641   } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1642     CHECK_EQ(argc, 5);
1643     FSReqWrapSync req_wrap_sync;
1644     FS_SYNC_TRACE_BEGIN(readdir);
1645     int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1646                        uv_fs_scandir, *path, 0 /*flags*/);
1647     FS_SYNC_TRACE_END(readdir);
1648     if (err < 0) {
1649       return;  // syscall failed, no need to continue, error info is in ctx
1650     }
1651 
1652     CHECK_GE(req_wrap_sync.req.result, 0);
1653     int r;
1654     std::vector<Local<Value>> name_v;
1655     std::vector<Local<Value>> type_v;
1656 
1657     for (;;) {
1658       uv_dirent_t ent;
1659 
1660       r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1661       if (r == UV_EOF)
1662         break;
1663       if (r != 0) {
1664         Local<Object> ctx = args[4].As<Object>();
1665         ctx->Set(env->context(), env->errno_string(),
1666                  Integer::New(isolate, r)).Check();
1667         ctx->Set(env->context(), env->syscall_string(),
1668                  OneByteString(isolate, "readdir")).Check();
1669         return;
1670       }
1671 
1672       Local<Value> error;
1673       MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1674                                                        ent.name,
1675                                                        encoding,
1676                                                        &error);
1677 
1678       if (filename.IsEmpty()) {
1679         Local<Object> ctx = args[4].As<Object>();
1680         ctx->Set(env->context(), env->error_string(), error).Check();
1681         return;
1682       }
1683 
1684       name_v.push_back(filename.ToLocalChecked());
1685 
1686       if (with_types) {
1687         type_v.emplace_back(Integer::New(isolate, ent.type));
1688       }
1689     }
1690 
1691 
1692     Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1693     if (with_types) {
1694       Local<Value> result[] = {
1695         names,
1696         Array::New(isolate, type_v.data(), type_v.size())
1697       };
1698       args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1699     } else {
1700       args.GetReturnValue().Set(names);
1701     }
1702   }
1703 }
1704 
Open(const FunctionCallbackInfo<Value> & args)1705 static void Open(const FunctionCallbackInfo<Value>& args) {
1706   Environment* env = Environment::GetCurrent(args);
1707 
1708   const int argc = args.Length();
1709   CHECK_GE(argc, 3);
1710 
1711   BufferValue path(env->isolate(), args[0]);
1712   CHECK_NOT_NULL(*path);
1713 
1714   CHECK(args[1]->IsInt32());
1715   const int flags = args[1].As<Int32>()->Value();
1716 
1717   CHECK(args[2]->IsInt32());
1718   const int mode = args[2].As<Int32>()->Value();
1719 
1720   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1721   if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1722     req_wrap_async->set_is_plain_open(true);
1723     AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1724               uv_fs_open, *path, flags, mode);
1725   } else {  // open(path, flags, mode, undefined, ctx)
1726     CHECK_EQ(argc, 5);
1727     FSReqWrapSync req_wrap_sync;
1728     FS_SYNC_TRACE_BEGIN(open);
1729     int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1730                           uv_fs_open, *path, flags, mode);
1731     FS_SYNC_TRACE_END(open);
1732     if (result >= 0) env->AddUnmanagedFd(result);
1733     args.GetReturnValue().Set(result);
1734   }
1735 }
1736 
OpenFileHandle(const FunctionCallbackInfo<Value> & args)1737 static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1738   BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1739   Environment* env = binding_data->env();
1740   Isolate* isolate = env->isolate();
1741 
1742   const int argc = args.Length();
1743   CHECK_GE(argc, 3);
1744 
1745   BufferValue path(isolate, args[0]);
1746   CHECK_NOT_NULL(*path);
1747 
1748   CHECK(args[1]->IsInt32());
1749   const int flags = args[1].As<Int32>()->Value();
1750 
1751   CHECK(args[2]->IsInt32());
1752   const int mode = args[2].As<Int32>()->Value();
1753 
1754   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1755   if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1756     AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1757               uv_fs_open, *path, flags, mode);
1758   } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1759     CHECK_EQ(argc, 5);
1760     FSReqWrapSync req_wrap_sync;
1761     FS_SYNC_TRACE_BEGIN(open);
1762     int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1763                           uv_fs_open, *path, flags, mode);
1764     FS_SYNC_TRACE_END(open);
1765     if (result < 0) {
1766       return;  // syscall failed, no need to continue, error info is in ctx
1767     }
1768     FileHandle* fd = FileHandle::New(binding_data, result);
1769     if (fd == nullptr) return;
1770     args.GetReturnValue().Set(fd->object());
1771   }
1772 }
1773 
CopyFile(const FunctionCallbackInfo<Value> & args)1774 static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1775   Environment* env = Environment::GetCurrent(args);
1776   Isolate* isolate = env->isolate();
1777 
1778   const int argc = args.Length();
1779   CHECK_GE(argc, 3);
1780 
1781   BufferValue src(isolate, args[0]);
1782   CHECK_NOT_NULL(*src);
1783 
1784   BufferValue dest(isolate, args[1]);
1785   CHECK_NOT_NULL(*dest);
1786 
1787   CHECK(args[2]->IsInt32());
1788   const int flags = args[2].As<Int32>()->Value();
1789 
1790   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1791   if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1792     AsyncDestCall(env, req_wrap_async, args, "copyfile",
1793                   *dest, dest.length(), UTF8, AfterNoArgs,
1794                   uv_fs_copyfile, *src, *dest, flags);
1795   } else {  // copyFile(src, dest, flags, undefined, ctx)
1796     CHECK_EQ(argc, 5);
1797     FSReqWrapSync req_wrap_sync;
1798     FS_SYNC_TRACE_BEGIN(copyfile);
1799     SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1800              uv_fs_copyfile, *src, *dest, flags);
1801     FS_SYNC_TRACE_END(copyfile);
1802   }
1803 }
1804 
1805 
1806 // Wrapper for write(2).
1807 //
1808 // bytesWritten = write(fd, buffer, offset, length, position, callback)
1809 // 0 fd        integer. file descriptor
1810 // 1 buffer    the data to write
1811 // 2 offset    where in the buffer to start from
1812 // 3 length    how much to write
1813 // 4 position  if integer, position to write at in the file.
1814 //             if null, write from the current position
WriteBuffer(const FunctionCallbackInfo<Value> & args)1815 static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1816   Environment* env = Environment::GetCurrent(args);
1817 
1818   const int argc = args.Length();
1819   CHECK_GE(argc, 4);
1820 
1821   CHECK(args[0]->IsInt32());
1822   const int fd = args[0].As<Int32>()->Value();
1823 
1824   CHECK(Buffer::HasInstance(args[1]));
1825   Local<Object> buffer_obj = args[1].As<Object>();
1826   char* buffer_data = Buffer::Data(buffer_obj);
1827   size_t buffer_length = Buffer::Length(buffer_obj);
1828 
1829   CHECK(IsSafeJsInt(args[2]));
1830   const int64_t off_64 = args[2].As<Integer>()->Value();
1831   CHECK_GE(off_64, 0);
1832   CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1833   const size_t off = static_cast<size_t>(off_64);
1834 
1835   CHECK(args[3]->IsInt32());
1836   const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1837   CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1838   CHECK_LE(len, buffer_length);
1839   CHECK_GE(off + len, off);
1840 
1841   const int64_t pos = GetOffset(args[4]);
1842 
1843   char* buf = buffer_data + off;
1844   uv_buf_t uvbuf = uv_buf_init(buf, len);
1845 
1846   FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1847   if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1848     AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1849               uv_fs_write, fd, &uvbuf, 1, pos);
1850   } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1851     CHECK_EQ(argc, 7);
1852     FSReqWrapSync req_wrap_sync;
1853     FS_SYNC_TRACE_BEGIN(write);
1854     int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1855                                 uv_fs_write, fd, &uvbuf, 1, pos);
1856     FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1857     args.GetReturnValue().Set(bytesWritten);
1858   }
1859 }
1860 
1861 
1862 // Wrapper for writev(2).
1863 //
1864 // bytesWritten = writev(fd, chunks, position, callback)
1865 // 0 fd        integer. file descriptor
1866 // 1 chunks    array of buffers to write
1867 // 2 position  if integer, position to write at in the file.
1868 //             if null, write from the current position
WriteBuffers(const FunctionCallbackInfo<Value> & args)1869 static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1870   Environment* env = Environment::GetCurrent(args);
1871 
1872   const int argc = args.Length();
1873   CHECK_GE(argc, 3);
1874 
1875   CHECK(args[0]->IsInt32());
1876   const int fd = args[0].As<Int32>()->Value();
1877 
1878   CHECK(args[1]->IsArray());
1879   Local<Array> chunks = args[1].As<Array>();
1880 
1881   int64_t pos = GetOffset(args[2]);
1882 
1883   MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1884 
1885   for (uint32_t i = 0; i < iovs.length(); i++) {
1886     Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1887     CHECK(Buffer::HasInstance(chunk));
1888     iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1889   }
1890 
1891   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1892   if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1893     AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1894               uv_fs_write, fd, *iovs, iovs.length(), pos);
1895   } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1896     CHECK_EQ(argc, 5);
1897     FSReqWrapSync req_wrap_sync;
1898     FS_SYNC_TRACE_BEGIN(write);
1899     int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1900                                 uv_fs_write, fd, *iovs, iovs.length(), pos);
1901     FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1902     args.GetReturnValue().Set(bytesWritten);
1903   }
1904 }
1905 
1906 
1907 // Wrapper for write(2).
1908 //
1909 // bytesWritten = write(fd, string, position, enc, callback)
1910 // 0 fd        integer. file descriptor
1911 // 1 string    non-buffer values are converted to strings
1912 // 2 position  if integer, position to write at in the file.
1913 //             if null, write from the current position
1914 // 3 enc       encoding of string
WriteString(const FunctionCallbackInfo<Value> & args)1915 static void WriteString(const FunctionCallbackInfo<Value>& args) {
1916   Environment* env = Environment::GetCurrent(args);
1917   Isolate* isolate = env->isolate();
1918 
1919   const int argc = args.Length();
1920   CHECK_GE(argc, 4);
1921 
1922   CHECK(args[0]->IsInt32());
1923   const int fd = args[0].As<Int32>()->Value();
1924 
1925   const int64_t pos = GetOffset(args[2]);
1926 
1927   const auto enc = ParseEncoding(isolate, args[3], UTF8);
1928 
1929   Local<Value> value = args[1];
1930   char* buf = nullptr;
1931   size_t len;
1932 
1933   FSReqBase* req_wrap_async = GetReqWrap(args, 4);
1934   const bool is_async = req_wrap_async != nullptr;
1935 
1936   // Avoid copying the string when it is externalized but only when:
1937   // 1. The target encoding is compatible with the string's encoding, and
1938   // 2. The write is synchronous, otherwise the string might get neutered
1939   //    while the request is in flight, and
1940   // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1941   //    need to call StringBytes::Write() to ensure proper byte swapping.
1942   // The const_casts are conceptually sound: memory is read but not written.
1943   if (!is_async && value->IsString()) {
1944     auto string = value.As<String>();
1945     if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1946       auto ext = string->GetExternalOneByteStringResource();
1947       buf = const_cast<char*>(ext->data());
1948       len = ext->length();
1949     } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1950       auto ext = string->GetExternalStringResource();
1951       buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1952       len = ext->length() * sizeof(*ext->data());
1953     }
1954   }
1955 
1956   if (is_async) {  // write(fd, string, pos, enc, req)
1957     CHECK_NOT_NULL(req_wrap_async);
1958     if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1959     FSReqBase::FSReqBuffer& stack_buffer =
1960         req_wrap_async->Init("write", len, enc);
1961     // StorageSize may return too large a char, so correct the actual length
1962     // by the write size
1963     len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1964     stack_buffer.SetLengthAndZeroTerminate(len);
1965     uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1966     int err = req_wrap_async->Dispatch(uv_fs_write,
1967                                        fd,
1968                                        &uvbuf,
1969                                        1,
1970                                        pos,
1971                                        AfterInteger);
1972     if (err < 0) {
1973       uv_fs_t* uv_req = req_wrap_async->req();
1974       uv_req->result = err;
1975       uv_req->path = nullptr;
1976       AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1977                              // an error
1978     } else {
1979       req_wrap_async->SetReturnValue(args);
1980     }
1981   } else {  // write(fd, string, pos, enc, undefined, ctx)
1982     CHECK_EQ(argc, 6);
1983     FSReqWrapSync req_wrap_sync;
1984     FSReqBase::FSReqBuffer stack_buffer;
1985     if (buf == nullptr) {
1986       if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1987         return;
1988       stack_buffer.AllocateSufficientStorage(len + 1);
1989       // StorageSize may return too large a char, so correct the actual length
1990       // by the write size
1991       len = StringBytes::Write(isolate, *stack_buffer,
1992                                len, args[1], enc);
1993       stack_buffer.SetLengthAndZeroTerminate(len);
1994       buf = *stack_buffer;
1995     }
1996     uv_buf_t uvbuf = uv_buf_init(buf, len);
1997     FS_SYNC_TRACE_BEGIN(write);
1998     int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1999                                 uv_fs_write, fd, &uvbuf, 1, pos);
2000     FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2001     args.GetReturnValue().Set(bytesWritten);
2002   }
2003 }
2004 
2005 
2006 /*
2007  * Wrapper for read(2).
2008  *
2009  * bytesRead = fs.read(fd, buffer, offset, length, position)
2010  *
2011  * 0 fd        int32. file descriptor
2012  * 1 buffer    instance of Buffer
2013  * 2 offset    int64. offset to start reading into inside buffer
2014  * 3 length    int32. length to read
2015  * 4 position  int64. file position - -1 for current position
2016  */
Read(const FunctionCallbackInfo<Value> & args)2017 static void Read(const FunctionCallbackInfo<Value>& args) {
2018   Environment* env = Environment::GetCurrent(args);
2019 
2020   const int argc = args.Length();
2021   CHECK_GE(argc, 5);
2022 
2023   CHECK(args[0]->IsInt32());
2024   const int fd = args[0].As<Int32>()->Value();
2025 
2026   CHECK(Buffer::HasInstance(args[1]));
2027   Local<Object> buffer_obj = args[1].As<Object>();
2028   char* buffer_data = Buffer::Data(buffer_obj);
2029   size_t buffer_length = Buffer::Length(buffer_obj);
2030 
2031   CHECK(IsSafeJsInt(args[2]));
2032   const int64_t off_64 = args[2].As<Integer>()->Value();
2033   CHECK_GE(off_64, 0);
2034   CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2035   const size_t off = static_cast<size_t>(off_64);
2036 
2037   CHECK(args[3]->IsInt32());
2038   const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2039   CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2040 
2041   CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2042   const int64_t pos = args[4]->IsNumber() ?
2043                       args[4].As<Integer>()->Value() :
2044                       args[4].As<BigInt>()->Int64Value();
2045 
2046   char* buf = buffer_data + off;
2047   uv_buf_t uvbuf = uv_buf_init(buf, len);
2048 
2049   FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2050   if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2051     AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2052               uv_fs_read, fd, &uvbuf, 1, pos);
2053   } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2054     CHECK_EQ(argc, 7);
2055     FSReqWrapSync req_wrap_sync;
2056     FS_SYNC_TRACE_BEGIN(read);
2057     const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2058                                    uv_fs_read, fd, &uvbuf, 1, pos);
2059     FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2060     args.GetReturnValue().Set(bytesRead);
2061   }
2062 }
2063 
2064 
2065 // Wrapper for readv(2).
2066 //
2067 // bytesRead = fs.readv(fd, buffers[, position], callback)
2068 // 0 fd        integer. file descriptor
2069 // 1 buffers   array of buffers to read
2070 // 2 position  if integer, position to read at in the file.
2071 //             if null, read from the current position
ReadBuffers(const FunctionCallbackInfo<Value> & args)2072 static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2073   Environment* env = Environment::GetCurrent(args);
2074 
2075   const int argc = args.Length();
2076   CHECK_GE(argc, 3);
2077 
2078   CHECK(args[0]->IsInt32());
2079   const int fd = args[0].As<Int32>()->Value();
2080 
2081   CHECK(args[1]->IsArray());
2082   Local<Array> buffers = args[1].As<Array>();
2083 
2084   int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2085 
2086   MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2087 
2088   // Init uv buffers from ArrayBufferViews
2089   for (uint32_t i = 0; i < iovs.length(); i++) {
2090     Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2091     CHECK(Buffer::HasInstance(buffer));
2092     iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2093   }
2094 
2095   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2096   if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2097     AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2098               uv_fs_read, fd, *iovs, iovs.length(), pos);
2099   } else {  // readBuffers(fd, buffers, undefined, ctx)
2100     CHECK_EQ(argc, 5);
2101     FSReqWrapSync req_wrap_sync;
2102     FS_SYNC_TRACE_BEGIN(read);
2103     int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2104                              uv_fs_read, fd, *iovs, iovs.length(), pos);
2105     FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2106     args.GetReturnValue().Set(bytesRead);
2107   }
2108 }
2109 
2110 
2111 /* fs.chmod(path, mode);
2112  * Wrapper for chmod(1) / EIO_CHMOD
2113  */
Chmod(const FunctionCallbackInfo<Value> & args)2114 static void Chmod(const FunctionCallbackInfo<Value>& args) {
2115   Environment* env = Environment::GetCurrent(args);
2116 
2117   const int argc = args.Length();
2118   CHECK_GE(argc, 2);
2119 
2120   BufferValue path(env->isolate(), args[0]);
2121   CHECK_NOT_NULL(*path);
2122 
2123   CHECK(args[1]->IsInt32());
2124   int mode = args[1].As<Int32>()->Value();
2125 
2126   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2127   if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2128     AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2129               uv_fs_chmod, *path, mode);
2130   } else {  // chmod(path, mode, undefined, ctx)
2131     CHECK_EQ(argc, 4);
2132     FSReqWrapSync req_wrap_sync;
2133     FS_SYNC_TRACE_BEGIN(chmod);
2134     SyncCall(env, args[3], &req_wrap_sync, "chmod",
2135              uv_fs_chmod, *path, mode);
2136     FS_SYNC_TRACE_END(chmod);
2137   }
2138 }
2139 
2140 
2141 /* fs.fchmod(fd, mode);
2142  * Wrapper for fchmod(1) / EIO_FCHMOD
2143  */
FChmod(const FunctionCallbackInfo<Value> & args)2144 static void FChmod(const FunctionCallbackInfo<Value>& args) {
2145   Environment* env = Environment::GetCurrent(args);
2146 
2147   const int argc = args.Length();
2148   CHECK_GE(argc, 2);
2149 
2150   CHECK(args[0]->IsInt32());
2151   const int fd = args[0].As<Int32>()->Value();
2152 
2153   CHECK(args[1]->IsInt32());
2154   const int mode = args[1].As<Int32>()->Value();
2155 
2156   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2157   if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2158     AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2159               uv_fs_fchmod, fd, mode);
2160   } else {  // fchmod(fd, mode, undefined, ctx)
2161     CHECK_EQ(argc, 4);
2162     FSReqWrapSync req_wrap_sync;
2163     FS_SYNC_TRACE_BEGIN(fchmod);
2164     SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2165              uv_fs_fchmod, fd, mode);
2166     FS_SYNC_TRACE_END(fchmod);
2167   }
2168 }
2169 
2170 
2171 /* fs.chown(path, uid, gid);
2172  * Wrapper for chown(1) / EIO_CHOWN
2173  */
Chown(const FunctionCallbackInfo<Value> & args)2174 static void Chown(const FunctionCallbackInfo<Value>& args) {
2175   Environment* env = Environment::GetCurrent(args);
2176 
2177   const int argc = args.Length();
2178   CHECK_GE(argc, 3);
2179 
2180   BufferValue path(env->isolate(), args[0]);
2181   CHECK_NOT_NULL(*path);
2182 
2183   CHECK(IsSafeJsInt(args[1]));
2184   const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2185 
2186   CHECK(IsSafeJsInt(args[2]));
2187   const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2188 
2189   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2190   if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2191     AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2192               uv_fs_chown, *path, uid, gid);
2193   } else {  // chown(path, uid, gid, undefined, ctx)
2194     CHECK_EQ(argc, 5);
2195     FSReqWrapSync req_wrap_sync;
2196     FS_SYNC_TRACE_BEGIN(chown);
2197     SyncCall(env, args[4], &req_wrap_sync, "chown",
2198              uv_fs_chown, *path, uid, gid);
2199     FS_SYNC_TRACE_END(chown);
2200   }
2201 }
2202 
2203 
2204 /* fs.fchown(fd, uid, gid);
2205  * Wrapper for fchown(1) / EIO_FCHOWN
2206  */
FChown(const FunctionCallbackInfo<Value> & args)2207 static void FChown(const FunctionCallbackInfo<Value>& args) {
2208   Environment* env = Environment::GetCurrent(args);
2209 
2210   const int argc = args.Length();
2211   CHECK_GE(argc, 3);
2212 
2213   CHECK(args[0]->IsInt32());
2214   const int fd = args[0].As<Int32>()->Value();
2215 
2216   CHECK(IsSafeJsInt(args[1]));
2217   const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2218 
2219   CHECK(IsSafeJsInt(args[2]));
2220   const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2221 
2222   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2223   if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2224     AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2225               uv_fs_fchown, fd, uid, gid);
2226   } else {  // fchown(fd, uid, gid, undefined, ctx)
2227     CHECK_EQ(argc, 5);
2228     FSReqWrapSync req_wrap_sync;
2229     FS_SYNC_TRACE_BEGIN(fchown);
2230     SyncCall(env, args[4], &req_wrap_sync, "fchown",
2231              uv_fs_fchown, fd, uid, gid);
2232     FS_SYNC_TRACE_END(fchown);
2233   }
2234 }
2235 
2236 
LChown(const FunctionCallbackInfo<Value> & args)2237 static void LChown(const FunctionCallbackInfo<Value>& args) {
2238   Environment* env = Environment::GetCurrent(args);
2239 
2240   const int argc = args.Length();
2241   CHECK_GE(argc, 3);
2242 
2243   BufferValue path(env->isolate(), args[0]);
2244   CHECK_NOT_NULL(*path);
2245 
2246   CHECK(IsSafeJsInt(args[1]));
2247   const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2248 
2249   CHECK(IsSafeJsInt(args[2]));
2250   const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2251 
2252   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2253   if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2254     AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2255               uv_fs_lchown, *path, uid, gid);
2256   } else {  // lchown(path, uid, gid, undefined, ctx)
2257     CHECK_EQ(argc, 5);
2258     FSReqWrapSync req_wrap_sync;
2259     FS_SYNC_TRACE_BEGIN(lchown);
2260     SyncCall(env, args[4], &req_wrap_sync, "lchown",
2261              uv_fs_lchown, *path, uid, gid);
2262     FS_SYNC_TRACE_END(lchown);
2263   }
2264 }
2265 
2266 
UTimes(const FunctionCallbackInfo<Value> & args)2267 static void UTimes(const FunctionCallbackInfo<Value>& args) {
2268   Environment* env = Environment::GetCurrent(args);
2269 
2270   const int argc = args.Length();
2271   CHECK_GE(argc, 3);
2272 
2273   BufferValue path(env->isolate(), args[0]);
2274   CHECK_NOT_NULL(*path);
2275 
2276   CHECK(args[1]->IsNumber());
2277   const double atime = args[1].As<Number>()->Value();
2278 
2279   CHECK(args[2]->IsNumber());
2280   const double mtime = args[2].As<Number>()->Value();
2281 
2282   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2283   if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2284     AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2285               uv_fs_utime, *path, atime, mtime);
2286   } else {  // utimes(path, atime, mtime, undefined, ctx)
2287     CHECK_EQ(argc, 5);
2288     FSReqWrapSync req_wrap_sync;
2289     FS_SYNC_TRACE_BEGIN(utimes);
2290     SyncCall(env, args[4], &req_wrap_sync, "utime",
2291              uv_fs_utime, *path, atime, mtime);
2292     FS_SYNC_TRACE_END(utimes);
2293   }
2294 }
2295 
FUTimes(const FunctionCallbackInfo<Value> & args)2296 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2297   Environment* env = Environment::GetCurrent(args);
2298 
2299   const int argc = args.Length();
2300   CHECK_GE(argc, 3);
2301 
2302   CHECK(args[0]->IsInt32());
2303   const int fd = args[0].As<Int32>()->Value();
2304 
2305   CHECK(args[1]->IsNumber());
2306   const double atime = args[1].As<Number>()->Value();
2307 
2308   CHECK(args[2]->IsNumber());
2309   const double mtime = args[2].As<Number>()->Value();
2310 
2311   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2312   if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2313     AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2314               uv_fs_futime, fd, atime, mtime);
2315   } else {  // futimes(fd, atime, mtime, undefined, ctx)
2316     CHECK_EQ(argc, 5);
2317     FSReqWrapSync req_wrap_sync;
2318     FS_SYNC_TRACE_BEGIN(futimes);
2319     SyncCall(env, args[4], &req_wrap_sync, "futime",
2320              uv_fs_futime, fd, atime, mtime);
2321     FS_SYNC_TRACE_END(futimes);
2322   }
2323 }
2324 
LUTimes(const FunctionCallbackInfo<Value> & args)2325 static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2326   Environment* env = Environment::GetCurrent(args);
2327 
2328   const int argc = args.Length();
2329   CHECK_GE(argc, 3);
2330 
2331   BufferValue path(env->isolate(), args[0]);
2332   CHECK_NOT_NULL(*path);
2333 
2334   CHECK(args[1]->IsNumber());
2335   const double atime = args[1].As<Number>()->Value();
2336 
2337   CHECK(args[2]->IsNumber());
2338   const double mtime = args[2].As<Number>()->Value();
2339 
2340   FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2341   if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2342     AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2343               uv_fs_lutime, *path, atime, mtime);
2344   } else {  // lutimes(path, atime, mtime, undefined, ctx)
2345     CHECK_EQ(argc, 5);
2346     FSReqWrapSync req_wrap_sync;
2347     FS_SYNC_TRACE_BEGIN(lutimes);
2348     SyncCall(env, args[4], &req_wrap_sync, "lutime",
2349              uv_fs_lutime, *path, atime, mtime);
2350     FS_SYNC_TRACE_END(lutimes);
2351   }
2352 }
2353 
Mkdtemp(const FunctionCallbackInfo<Value> & args)2354 static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2355   Environment* env = Environment::GetCurrent(args);
2356   Isolate* isolate = env->isolate();
2357 
2358   const int argc = args.Length();
2359   CHECK_GE(argc, 2);
2360 
2361   BufferValue tmpl(isolate, args[0]);
2362   CHECK_NOT_NULL(*tmpl);
2363 
2364   const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2365 
2366   FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2367   if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2368     AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2369               uv_fs_mkdtemp, *tmpl);
2370   } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2371     CHECK_EQ(argc, 4);
2372     FSReqWrapSync req_wrap_sync;
2373     FS_SYNC_TRACE_BEGIN(mkdtemp);
2374     SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2375              uv_fs_mkdtemp, *tmpl);
2376     FS_SYNC_TRACE_END(mkdtemp);
2377     const char* path = req_wrap_sync.req.path;
2378 
2379     Local<Value> error;
2380     MaybeLocal<Value> rc =
2381         StringBytes::Encode(isolate, path, encoding, &error);
2382     if (rc.IsEmpty()) {
2383       Local<Object> ctx = args[3].As<Object>();
2384       ctx->Set(env->context(), env->error_string(), error).Check();
2385       return;
2386     }
2387     args.GetReturnValue().Set(rc.ToLocalChecked());
2388   }
2389 }
2390 
MemoryInfo(MemoryTracker * tracker) const2391 void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2392   tracker->TrackField("stats_field_array", stats_field_array);
2393   tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2394   tracker->TrackField("file_handle_read_wrap_freelist",
2395                       file_handle_read_wrap_freelist);
2396 }
2397 
2398 // TODO(addaleax): Remove once we're on C++17.
2399 constexpr FastStringKey BindingData::type_name;
2400 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)2401 void Initialize(Local<Object> target,
2402                 Local<Value> unused,
2403                 Local<Context> context,
2404                 void* priv) {
2405   Environment* env = Environment::GetCurrent(context);
2406   Isolate* isolate = env->isolate();
2407   BindingData* const binding_data =
2408       env->AddBindingData<BindingData>(context, target);
2409   if (binding_data == nullptr) return;
2410 
2411   env->SetMethod(target, "access", Access);
2412   env->SetMethod(target, "close", Close);
2413   env->SetMethod(target, "open", Open);
2414   env->SetMethod(target, "openFileHandle", OpenFileHandle);
2415   env->SetMethod(target, "read", Read);
2416   env->SetMethod(target, "readBuffers", ReadBuffers);
2417   env->SetMethod(target, "fdatasync", Fdatasync);
2418   env->SetMethod(target, "fsync", Fsync);
2419   env->SetMethod(target, "rename", Rename);
2420   env->SetMethod(target, "ftruncate", FTruncate);
2421   env->SetMethod(target, "rmdir", RMDir);
2422   env->SetMethod(target, "mkdir", MKDir);
2423   env->SetMethod(target, "readdir", ReadDir);
2424   env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2425   env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2426   env->SetMethod(target, "stat", Stat);
2427   env->SetMethod(target, "lstat", LStat);
2428   env->SetMethod(target, "fstat", FStat);
2429   env->SetMethod(target, "link", Link);
2430   env->SetMethod(target, "symlink", Symlink);
2431   env->SetMethod(target, "readlink", ReadLink);
2432   env->SetMethod(target, "unlink", Unlink);
2433   env->SetMethod(target, "writeBuffer", WriteBuffer);
2434   env->SetMethod(target, "writeBuffers", WriteBuffers);
2435   env->SetMethod(target, "writeString", WriteString);
2436   env->SetMethod(target, "realpath", RealPath);
2437   env->SetMethod(target, "copyFile", CopyFile);
2438 
2439   env->SetMethod(target, "chmod", Chmod);
2440   env->SetMethod(target, "fchmod", FChmod);
2441 
2442   env->SetMethod(target, "chown", Chown);
2443   env->SetMethod(target, "fchown", FChown);
2444   env->SetMethod(target, "lchown", LChown);
2445 
2446   env->SetMethod(target, "utimes", UTimes);
2447   env->SetMethod(target, "futimes", FUTimes);
2448   env->SetMethod(target, "lutimes", LUTimes);
2449 
2450   env->SetMethod(target, "mkdtemp", Mkdtemp);
2451 
2452   target
2453       ->Set(context,
2454             FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2455             Integer::New(
2456                 isolate,
2457                 static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2458       .Check();
2459 
2460   target->Set(context,
2461               FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2462               binding_data->stats_field_array.GetJSArray()).Check();
2463 
2464   target->Set(context,
2465               FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2466               binding_data->stats_field_bigint_array.GetJSArray()).Check();
2467 
2468   StatWatcher::Initialize(env, target);
2469 
2470   // Create FunctionTemplate for FSReqCallback
2471   Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2472   fst->InstanceTemplate()->SetInternalFieldCount(
2473       FSReqBase::kInternalFieldCount);
2474   fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2475   env->SetConstructorFunction(target, "FSReqCallback", fst);
2476 
2477   // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2478   // to do anything in the constructor, so we only store the instance template.
2479   Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2480   fh_rw->InstanceTemplate()->SetInternalFieldCount(
2481       FSReqBase::kInternalFieldCount);
2482   fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2483   Local<String> fhWrapString =
2484       FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2485   fh_rw->SetClassName(fhWrapString);
2486   env->set_filehandlereadwrap_template(
2487       fst->InstanceTemplate());
2488 
2489   // Create Function Template for FSReqPromise
2490   Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2491   fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2492   Local<String> promiseString =
2493       FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2494   fpt->SetClassName(promiseString);
2495   Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2496   fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2497   env->set_fsreqpromise_constructor_template(fpo);
2498 
2499   // Create FunctionTemplate for FileHandle
2500   Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2501   fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2502   env->SetProtoMethod(fd, "close", FileHandle::Close);
2503   env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2504   Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2505   fdt->SetInternalFieldCount(StreamBase::kInternalFieldCount);
2506   StreamBase::AddMethods(env, fd);
2507   env->SetConstructorFunction(target, "FileHandle", fd);
2508   env->set_fd_constructor_template(fdt);
2509 
2510   // Create FunctionTemplate for FileHandle::CloseReq
2511   Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2512   fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2513                         "FileHandleCloseReq"));
2514   fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2515   Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2516   fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2517   env->set_fdclose_constructor_template(fdcloset);
2518 
2519   Local<Symbol> use_promises_symbol =
2520     Symbol::New(isolate,
2521                 FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2522   env->set_fs_use_promises_symbol(use_promises_symbol);
2523   target->Set(context,
2524               FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2525               use_promises_symbol).Check();
2526 }
2527 
binding_data()2528 BindingData* FSReqBase::binding_data() {
2529   return binding_data_.get();
2530 }
2531 }  // namespace fs
2532 
2533 }  // end namespace node
2534 
2535 NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2536