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