xref: /third_party/node/src/node_file.cc (revision 1cb0ef41)
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
50namespace node {
51
52namespace fs {
53
54using v8::Array;
55using v8::BigInt;
56using v8::Boolean;
57using v8::Context;
58using v8::EscapableHandleScope;
59using v8::Function;
60using v8::FunctionCallbackInfo;
61using v8::FunctionTemplate;
62using v8::HandleScope;
63using v8::Int32;
64using v8::Integer;
65using v8::Isolate;
66using v8::Local;
67using v8::MaybeLocal;
68using v8::Number;
69using v8::Object;
70using v8::ObjectTemplate;
71using v8::Promise;
72using v8::String;
73using v8::Undefined;
74using v8::Value;
75
76#ifndef S_ISDIR
77# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
78#endif
79
80#ifdef __POSIX__
81constexpr char kPathSeparator = '/';
82#else
83const char* const kPathSeparator = "\\/";
84#endif
85
86std::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
109inline int64_t GetOffset(Local<Value> value) {
110  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
111}
112
113static 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.
215typedef void(*uv_fs_callback_t)(uv_fs_t*);
216
217
218void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
219  tracker->TrackField("paths", paths_);
220}
221
222FileHandleReadWrap::~FileHandleReadWrap() = default;
223
224FSReqBase::~FSReqBase() = default;
225
226void 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.)
233FileHandle::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
243FileHandle* 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
254void 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
269FileHandle::~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
275int 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
282void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
283  tracker->TrackField("current_read", current_read_);
284}
285
286FileHandle::TransferMode FileHandle::GetTransferMode() const {
287  return reading_ || closing_ || closed_ ?
288      TransferMode::kUntransferable : TransferMode::kTransferable;
289}
290
291std::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
298FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
299
300FileHandle::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
311BaseObjectPtr<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.
327inline 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
380void 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
390void 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
400FileHandle* 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
408FileHandle::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
417FileHandle::CloseReq::~CloseReq() {
418  uv_fs_req_cleanup(req());
419  promise_.Reset();
420  ref_.Reset();
421}
422
423void 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.
435MaybeLocal<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
493void 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
502void 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
510void FileHandle::AfterClose() {
511  closing_ = false;
512  closed_ = true;
513  fd_ = -1;
514  if (reading_ && !persistent().IsEmpty())
515    EmitRead(UV_EOF);
516}
517
518void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
519  tracker->TrackField("buffer", buffer_);
520  tracker->TrackField("file_handle", this->file_handle_);
521}
522
523FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
524  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
525    file_handle_(handle) {}
526
527int 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
645int FileHandle::ReadStop() {
646  reading_ = false;
647  return 0;
648}
649
650typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
651
652ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
653  return new FileHandleCloseWrap(this, object);
654}
655
656int 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
682void FSReqCallback::Reject(Local<Value> reject) {
683  MakeCallback(env()->oncomplete_string(), 1, &reject);
684}
685
686void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
687  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
688}
689
690void FSReqCallback::ResolveStatFs(const uv_statfs_t* stat) {
691  Resolve(FillGlobalStatFsArray(binding_data(), use_bigint(), stat));
692}
693
694void 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
704void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
705  args.GetReturnValue().SetUndefined();
706}
707
708void 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
714FSReqAfterScope::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
722FSReqAfterScope::~FSReqAfterScope() {
723  Clear();
724}
725
726void 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.
743void 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
755bool 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
767void 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
776void 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
786void 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
796void 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
809void 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.
824void 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
835void 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
856void 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
876void 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
896void 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
945void 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
975void 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]
1001static 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.
1098static 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
1115static 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
1148static 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
1182static 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
1214static 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
1256static 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
1291static 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
1324static 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
1369static 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
1402static 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
1429static 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
1452static 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
1475static 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
1499static 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
1524int 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
1592int 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
1687int 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
1706static 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
1757static 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
1803static 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
1895static 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
1929static 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
1968static 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
2015static 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
2070static 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
2117static 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 */
2220static 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
2276static 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 */
2319static 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 */
2351static 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 */
2382static 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 */
2417static 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
2448static 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
2480static 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
2511static 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
2541static 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
2572static 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
2611void 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
2620BindingData::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
2649void 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
2660bool 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
2674InternalFieldInfoBase* BindingData::Serialize(int index) {
2675  DCHECK_EQ(index, BaseObject::kEmbedderType);
2676  InternalFieldInfo* info =
2677      InternalFieldInfoBase::New<InternalFieldInfo>(type());
2678  return info;
2679}
2680
2681void 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
2798BindingData* FSReqBase::binding_data() {
2799  return binding_data_.get();
2800}
2801
2802void 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
2858NODE_BINDING_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2859NODE_BINDING_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)
2860