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