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