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