GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_file.cc Lines: 1586 1674 94.7 %
Date: 2021-06-07 04:11:51 Branches: 806 1230 65.5 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
#include "node_file.h"  // NOLINT(build/include_inline)
22
#include "node_file-inl.h"
23
#include "aliased_buffer.h"
24
#include "memory_tracker-inl.h"
25
#include "node_buffer.h"
26
#include "node_external_reference.h"
27
#include "node_process-inl.h"
28
#include "node_stat_watcher.h"
29
#include "util-inl.h"
30
31
#include "tracing/trace_event.h"
32
33
#include "req_wrap-inl.h"
34
#include "stream_base-inl.h"
35
#include "string_bytes.h"
36
37
#include <fcntl.h>
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
#include <cstring>
41
#include <cerrno>
42
#include <climits>
43
44
#if defined(__MINGW32__) || defined(_MSC_VER)
45
# include <io.h>
46
#endif
47
48
#include <memory>
49
50
namespace node {
51
52
namespace fs {
53
54
using v8::Array;
55
using v8::BigInt;
56
using v8::Boolean;
57
using v8::Context;
58
using v8::EscapableHandleScope;
59
using v8::Function;
60
using v8::FunctionCallbackInfo;
61
using v8::FunctionTemplate;
62
using v8::HandleScope;
63
using v8::Int32;
64
using v8::Integer;
65
using v8::Isolate;
66
using v8::Local;
67
using v8::MaybeLocal;
68
using v8::Number;
69
using v8::Object;
70
using v8::ObjectTemplate;
71
using v8::Promise;
72
using v8::String;
73
using v8::Symbol;
74
using v8::Undefined;
75
using v8::Value;
76
77
#ifndef S_ISDIR
78
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
79
#endif
80
81
#ifdef __POSIX__
82
constexpr char kPathSeparator = '/';
83
#else
84
const char* const kPathSeparator = "\\/";
85
#endif
86
87
10
std::string Basename(const std::string& str, const std::string& extension) {
88
  // Remove everything leading up to and including the final path separator.
89
10
  std::string::size_type pos = str.find_last_of(kPathSeparator);
90
91
  // Starting index for the resulting string
92
10
  std::size_t start_pos = 0;
93
  // String size to return
94
10
  std::size_t str_size = str.size();
95
10
  if (pos != std::string::npos) {
96
10
    start_pos = pos + 1;
97
10
    str_size -= start_pos;
98
  }
99
100
  // Strip away the extension, if any.
101

20
  if (str_size >= extension.size() &&
102
10
      str.compare(str.size() - extension.size(),
103
        extension.size(), extension) == 0) {
104
    str_size -= extension.size();
105
  }
106
107
10
  return str.substr(start_pos, str_size);
108
}
109
110
144378
inline int64_t GetOffset(Local<Value> value) {
111
146554
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
112
}
113
114
#define TRACE_NAME(name) "fs.sync." #name
115
#define GET_TRACE_ENABLED                                                  \
116
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
117
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
118
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
119
  if (GET_TRACE_ENABLED)                                                   \
120
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
121
  ##__VA_ARGS__);
122
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
123
  if (GET_TRACE_ENABLED)                                                   \
124
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
125
  ##__VA_ARGS__);
126
127
// We sometimes need to convert a C++ lambda function to a raw C-style function.
128
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
129
// functions, and thus does not wrap them properly.
130
typedef void(*uv_fs_callback_t)(uv_fs_t*);
131
132
133
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
134
  tracker->TrackField("paths", paths_);
135
}
136
137
FileHandleReadWrap::~FileHandleReadWrap() = default;
138
139
FSReqBase::~FSReqBase() = default;
140
141
2
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
142
2
  tracker->TrackField("continuation_data", continuation_data_);
143
2
}
144
145
// The FileHandle object wraps a file descriptor and will close it on garbage
146
// collection if necessary. If that happens, a process warning will be
147
// emitted (or a fatal exception will occur if the fd cannot be closed.)
148
731
FileHandle::FileHandle(BindingData* binding_data,
149
731
                       Local<Object> obj, int fd)
150
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
151
      StreamBase(env()),
152
      fd_(fd),
153
731
      binding_data_(binding_data) {
154
731
  MakeWeak();
155
731
  StreamBase::AttachToObject(GetObject());
156
731
}
157
158
731
FileHandle* FileHandle::New(BindingData* binding_data,
159
                            int fd, Local<Object> obj) {
160
731
  Environment* env = binding_data->env();
161

2894
  if (obj.IsEmpty() && !env->fd_constructor_template()
162
2163
                            ->NewInstance(env->context())
163
716
                            .ToLocal(&obj)) {
164
    return nullptr;
165
  }
166
731
  return new FileHandle(binding_data, obj, fd);
167
}
168
169
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
170
15
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
171
15
  Environment* env = binding_data->env();
172
15
  CHECK(args.IsConstructCall());
173
30
  CHECK(args[0]->IsInt32());
174
175
  FileHandle* handle =
176
45
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
177
15
  if (handle == nullptr) return;
178
30
  if (args[1]->IsNumber())
179
60
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
180
30
  if (args[2]->IsNumber())
181
60
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
182
}
183
184
2091
FileHandle::~FileHandle() {
185
697
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
186
697
  Close();           // Close synchronously and emit warning
187
697
  CHECK(closed_);    // We have to be closed at the point
188
1394
}
189
190
int FileHandle::DoWrite(WriteWrap* w,
191
                        uv_buf_t* bufs,
192
                        size_t count,
193
                        uv_stream_t* send_handle) {
194
  return UV_ENOSYS;  // Not implemented (yet).
195
}
196
197
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
198
  tracker->TrackField("current_read", current_read_);
199
}
200
201
10
FileHandle::TransferMode FileHandle::GetTransferMode() const {
202

10
  return reading_ || closing_ || closed_ ?
203
10
      TransferMode::kUntransferable : TransferMode::kTransferable;
204
}
205
206
6
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
207
6
  CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
208
12
  auto ret = std::make_unique<TransferData>(fd_);
209
6
  closed_ = true;
210
12
  return ret;
211
}
212
213
6
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
214
215
18
FileHandle::TransferData::~TransferData() {
216
6
  if (fd_ > 0) {
217
    uv_fs_t close_req;
218
4
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
219
4
    uv_fs_req_cleanup(&close_req);
220
  }
221
12
}
222
223
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
224
    Environment* env,
225
    v8::Local<v8::Context> context,
226
    std::unique_ptr<worker::TransferData> self) {
227
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
228
2
  if (bd == nullptr) return {};
229
230
2
  int fd = fd_;
231
2
  fd_ = -1;
232
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
233
}
234
235
// Close the file descriptor if it hasn't already been closed. A process
236
// warning will be emitted using a SetImmediate to avoid calling back to
237
// JS during GC. If closing the fd fails at this point, a fatal exception
238
// will crash the process immediately.
239
697
inline void FileHandle::Close() {
240
1383
  if (closed_) return;
241
  uv_fs_t req;
242
11
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
243
11
  uv_fs_req_cleanup(&req);
244
245
  struct err_detail { int ret; int fd; };
246
247
11
  err_detail detail { ret, fd_ };
248
249
11
  AfterClose();
250
251
11
  if (ret < 0) {
252
    // Do not unref this
253
    env()->SetImmediate([detail](Environment* env) {
254
      char msg[70];
255
      snprintf(msg, arraysize(msg),
256
              "Closing file descriptor %d on garbage collection failed",
257
              detail.fd);
258
      // This exception will end up being fatal for the process because
259
      // it is being thrown from within the SetImmediate handler and
260
      // there is no JS stack to bubble it to. In other words, tearing
261
      // down the process is the only reasonable thing we can do here.
262
      HandleScope handle_scope(env->isolate());
263
      env->ThrowUVException(detail.ret, "close", msg);
264
    });
265
    return;
266
  }
267
268
  // If the close was successful, we still want to emit a process warning
269
  // to notify that the file descriptor was gc'd. We want to be noisy about
270
  // this because not explicitly closing the FileHandle is a bug.
271
272
24
  env()->SetImmediate([detail](Environment* env) {
273
    ProcessEmitWarning(env,
274
                       "Closing file descriptor %d on garbage collection",
275
2
                       detail.fd);
276
2
    if (env->filehandle_close_warning()) {
277
2
      env->set_filehandle_close_warning(false);
278
4
      ProcessEmitDeprecationWarning(
279
          env,
280
          "Closing a FileHandle object on garbage collection is deprecated. "
281
          "Please close FileHandle objects explicitly using "
282
          "FileHandle.prototype.close(). In the future, an error will be "
283
          "thrown if a file descriptor is closed during garbage collection.",
284
          "DEP0137").IsNothing();
285
    }
286
13
  }, CallbackFlags::kUnrefed);
287
}
288
289
703
void FileHandle::CloseReq::Resolve() {
290
703
  Isolate* isolate = env()->isolate();
291
1389
  HandleScope scope(isolate);
292
703
  Context::Scope context_scope(env()->context());
293
1406
  InternalCallbackScope callback_scope(this);
294
1406
  Local<Promise> promise = promise_.Get(isolate);
295
703
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
296
2109
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
297
686
}
298
299
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
300
1
  Isolate* isolate = env()->isolate();
301
2
  HandleScope scope(isolate);
302
1
  Context::Scope context_scope(env()->context());
303
2
  InternalCallbackScope callback_scope(this);
304
2
  Local<Promise> promise = promise_.Get(isolate);
305
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
306
3
  resolver->Reject(env()->context(), reason).Check();
307
1
}
308
309
704
FileHandle* FileHandle::CloseReq::file_handle() {
310
704
  Isolate* isolate = env()->isolate();
311
1408
  HandleScope scope(isolate);
312
1408
  Local<Value> val = ref_.Get(isolate);
313
704
  Local<Object> obj = val.As<Object>();
314
1408
  return Unwrap<FileHandle>(obj);
315
}
316
317
704
FileHandle::CloseReq::CloseReq(Environment* env,
318
                               Local<Object> obj,
319
                               Local<Promise> promise,
320
704
                               Local<Value> ref)
321
1408
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
322
704
  promise_.Reset(env->isolate(), promise);
323
704
  ref_.Reset(env->isolate(), ref);
324
704
}
325
326
3435
FileHandle::CloseReq::~CloseReq() {
327
687
  uv_fs_req_cleanup(req());
328
687
  promise_.Reset();
329
687
  ref_.Reset();
330
1374
}
331
332
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
333
  tracker->TrackField("promise", promise_);
334
  tracker->TrackField("ref", ref_);
335
}
336
337
338
339
// Closes this FileHandle asynchronously and returns a Promise that will be
340
// resolved when the callback is invoked, or rejects with a UVException if
341
// there was a problem closing the fd. This is the preferred mechanism for
342
// closing the FD object even tho the object will attempt to close
343
// automatically on gc.
344
704
MaybeLocal<Promise> FileHandle::ClosePromise() {
345
704
  Isolate* isolate = env()->isolate();
346
704
  EscapableHandleScope scope(isolate);
347
704
  Local<Context> context = env()->context();
348
704
  auto maybe_resolver = Promise::Resolver::New(context);
349
704
  CHECK(!maybe_resolver.IsEmpty());
350
704
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
351
704
  Local<Promise> promise = resolver.As<Promise>();
352
704
  CHECK(!reading_);
353

704
  if (!closed_ && !closing_) {
354
704
    closing_ = true;
355
    Local<Object> close_req_obj;
356
1408
    if (!env()
357
1408
             ->fdclose_constructor_template()
358
2112
             ->NewInstance(env()->context())
359
704
             .ToLocal(&close_req_obj)) {
360
      return MaybeLocal<Promise>();
361
    }
362
1408
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
363
2112
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
364
1391
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
365
704
      CHECK_NOT_NULL(close);
366
704
      close->file_handle()->AfterClose();
367
704
      Isolate* isolate = close->env()->isolate();
368
704
      if (req->result < 0) {
369
2
        HandleScope handle_scope(isolate);
370
1
        close->Reject(
371
2
            UVException(isolate, static_cast<int>(req->result), "close"));
372
      } else {
373
703
        close->Resolve();
374
      }
375
2799
    }};
376
704
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
377
704
    if (ret < 0) {
378
      req->Reject(UVException(isolate, ret, "close"));
379
      delete req;
380
704
    }
381
  } else {
382
    // Already closed. Just reject the promise immediately
383
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
384
        .Check();
385
  }
386
704
  return scope.Escape(promise);
387
}
388
389
704
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
390
  FileHandle* fd;
391
704
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
392
  Local<Promise> ret;
393
1408
  if (!fd->ClosePromise().ToLocal(&ret)) return;
394
1408
  args.GetReturnValue().Set(ret);
395
}
396
397
398
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
399
  FileHandle* fd;
400
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
401
  // Just act as if this FileHandle has been closed.
402
8
  fd->AfterClose();
403
}
404
405
406
723
void FileHandle::AfterClose() {
407
723
  closing_ = false;
408
723
  closed_ = true;
409
723
  fd_ = -1;
410

723
  if (reading_ && !persistent().IsEmpty())
411
    EmitRead(UV_EOF);
412
723
}
413
414
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
415
  tracker->TrackField("buffer", buffer_);
416
  tracker->TrackField("file_handle", this->file_handle_);
417
}
418
419
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
420
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
421
15
    file_handle_(handle) {}
422
423
212
int FileHandle::ReadStart() {
424

212
  if (!IsAlive() || IsClosing())
425
    return UV_EOF;
426
427
212
  reading_ = true;
428
429
212
  if (current_read_)
430
    return 0;
431
432
424
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
433
434
212
  if (read_length_ == 0) {
435
5
    EmitRead(UV_EOF);
436
5
    return 0;
437
  }
438
439
  {
440
    // Create a new FileHandleReadWrap or re-use one.
441
    // Either way, we need these two scopes for AsyncReset() or otherwise
442
    // for creating the new instance.
443
414
    HandleScope handle_scope(env()->isolate());
444
414
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
445
446
207
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
447
207
    if (freelist.size() > 0) {
448
192
      read_wrap = std::move(freelist.back());
449
192
      freelist.pop_back();
450
      // Use a fresh async resource.
451
      // Lifetime is ensured via AsyncWrap::resource_.
452
192
      Local<Object> resource = Object::New(env()->isolate());
453
384
      USE(resource->Set(
454
1152
          env()->context(), env()->handle_string(), read_wrap->object()));
455
192
      read_wrap->AsyncReset(resource);
456
192
      read_wrap->file_handle_ = this;
457
    } else {
458
      Local<Object> wrap_obj;
459
30
      if (!env()
460
30
               ->filehandlereadwrap_template()
461
45
               ->NewInstance(env()->context())
462
15
               .ToLocal(&wrap_obj)) {
463
        return UV_EBUSY;
464
      }
465
15
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
466
    }
467
  }
468
207
  int64_t recommended_read = 65536;
469

207
  if (read_length_ >= 0 && read_length_ <= recommended_read)
470
7
    recommended_read = read_length_;
471
472
207
  read_wrap->buffer_ = EmitAlloc(recommended_read);
473
474
207
  current_read_ = std::move(read_wrap);
475
476
414
  current_read_->Dispatch(uv_fs_read,
477
                          fd_,
478
207
                          &current_read_->buffer_,
479
                          1,
480
                          read_offset_,
481
621
                          uv_fs_callback_t{[](uv_fs_t* req) {
482
    FileHandle* handle;
483
    {
484
207
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
485
207
      handle = req_wrap->file_handle_;
486
207
      CHECK_EQ(handle->current_read_.get(), req_wrap);
487
    }
488
489
    // ReadStart() checks whether current_read_ is set to determine whether
490
    // a read is in progress. Moving it into a local variable makes sure that
491
    // the ReadStart() call below doesn't think we're still actively reading.
492
    BaseObjectPtr<FileHandleReadWrap> read_wrap =
493
414
        std::move(handle->current_read_);
494
495
207
    ssize_t result = req->result;
496
207
    uv_buf_t buffer = read_wrap->buffer_;
497
498
207
    uv_fs_req_cleanup(req);
499
500
    // Push the read wrap back to the freelist, or let it be destroyed
501
    // once we’re exiting the current scope.
502
207
    constexpr size_t kWantedFreelistFill = 100;
503
207
    auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
504
207
    if (freelist.size() < kWantedFreelistFill) {
505
207
      read_wrap->Reset();
506
207
      freelist.emplace_back(std::move(read_wrap));
507
    }
508
509
207
    if (result >= 0) {
510
      // Read at most as many bytes as we originally planned to.
511

206
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
512
        result = handle->read_length_;
513
514
      // If we read data and we have an expected length, decrease it by
515
      // how much we have read.
516
206
      if (handle->read_length_ >= 0)
517
9
        handle->read_length_ -= result;
518
519
      // If we have an offset, increase it by how much we have read.
520
206
      if (handle->read_offset_ >= 0)
521
204
        handle->read_offset_ += result;
522
    }
523
524
    // Reading 0 bytes from a file always means EOF, or that we reached
525
    // the end of the requested range.
526
207
    if (result == 0)
527
7
      result = UV_EOF;
528
529
207
    handle->EmitRead(result, buffer);
530
531
    // Start over, if EmitRead() didn’t tell us to stop.
532
207
    if (handle->reading_)
533
      handle->ReadStart();
534
828
  }});
535
536
207
  return 0;
537
}
538
539
227
int FileHandle::ReadStop() {
540
227
  reading_ = false;
541
227
  return 0;
542
}
543
544
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
545
546
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
547
  return new FileHandleCloseWrap(this, object);
548
}
549
550
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
551
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
552
  closing_ = true;
553
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
554
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
555
        FileHandleCloseWrap::from_req(req));
556
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
557
    handle->AfterClose();
558
559
    int result = static_cast<int>(req->result);
560
    uv_fs_req_cleanup(req);
561
    wrap->Done(result);
562
  }});
563
564
  return 0;
565
}
566
567
568
3896
void FSReqCallback::Reject(Local<Value> reject) {
569
3896
  MakeCallback(env()->oncomplete_string(), 1, &reject);
570
3896
}
571
572
3089
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
573
3089
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
574
3089
}
575
576
47097
void FSReqCallback::Resolve(Local<Value> value) {
577
  Local<Value> argv[2] {
578
    Null(env()->isolate()),
579
    value
580
94194
  };
581
  MakeCallback(env()->oncomplete_string(),
582
132551
               value->IsUndefined() ? 1 : arraysize(argv),
583
85454
               argv);
584
47092
}
585
586
50993
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
587
101986
  args.GetReturnValue().SetUndefined();
588
50993
}
589
590
50993
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
591
50993
  CHECK(args.IsConstructCall());
592
50993
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
593
152979
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
594
50993
}
595
596
53395
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
597
    : wrap_(wrap),
598
      req_(req),
599
      handle_scope_(wrap->env()->isolate()),
600
53395
      context_scope_(wrap->env()->context()) {
601
53395
  CHECK_EQ(wrap_->req(), req);
602
53395
}
603
604
160170
FSReqAfterScope::~FSReqAfterScope() {
605
53390
  Clear();
606
53390
}
607
608
57502
void FSReqAfterScope::Clear() {
609
57502
  if (!wrap_) return;
610
611
53390
  uv_fs_req_cleanup(wrap_->req());
612
53390
  wrap_->Detach();
613
53390
  wrap_.reset();
614
}
615
616
// TODO(joyeecheung): create a normal context object, and
617
// construct the actual errors in the JS land using the context.
618
// The context should include fds for some fs APIs, currently they are
619
// missing in the error messages. The path, dest, syscall, fd, .etc
620
// can be put into the context before the binding is even invoked,
621
// the only information that has to come from the C++ layer is the
622
// error number (and possibly the syscall for abstraction),
623
// which is also why the errors should have been constructed
624
// in JS for more flexibility.
625
4101
void FSReqAfterScope::Reject(uv_fs_t* req) {
626
8202
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
627
4101
  Local<Value> exception = UVException(wrap_->env()->isolate(),
628
4101
                                       static_cast<int>(req->result),
629
                                       wrap_->syscall(),
630
                                       nullptr,
631
                                       req->path,
632
12303
                                       wrap_->data());
633
4101
  Clear();
634
4101
  wrap->Reject(exception);
635
4101
}
636
637
53395
bool FSReqAfterScope::Proceed() {
638
53395
  if (req_->result < 0) {
639
4101
    Reject(req_);
640
4101
    return false;
641
  }
642
49294
  return true;
643
}
644
645
8698
void AfterNoArgs(uv_fs_t* req) {
646
8698
  FSReqBase* req_wrap = FSReqBase::from_req(req);
647
17392
  FSReqAfterScope after(req_wrap, req);
648
649
8698
  if (after.Proceed())
650
16934
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
651
8694
}
652
653
7399
void AfterStat(uv_fs_t* req) {
654
7399
  FSReqBase* req_wrap = FSReqBase::from_req(req);
655
14798
  FSReqAfterScope after(req_wrap, req);
656
657
7399
  if (after.Proceed()) {
658
3797
    req_wrap->ResolveStat(&req->statbuf);
659
  }
660
7399
}
661
662
35630
void AfterInteger(uv_fs_t* req) {
663
35630
  FSReqBase* req_wrap = FSReqBase::from_req(req);
664
71260
  FSReqAfterScope after(req_wrap, req);
665
666
35630
  int result = static_cast<int>(req->result);
667

35630
  if (result >= 0 && req_wrap->is_plain_open())
668
5139
    req_wrap->env()->AddUnmanagedFd(result);
669
670
35630
  if (after.Proceed())
671
70828
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
672
35630
}
673
674
742
void AfterOpenFileHandle(uv_fs_t* req) {
675
742
  FSReqBase* req_wrap = FSReqBase::from_req(req);
676
1484
  FSReqAfterScope after(req_wrap, req);
677
678
742
  if (after.Proceed()) {
679
1426
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
680
1426
                                     static_cast<int>(req->result));
681
713
    if (fd == nullptr) return;
682
1426
    req_wrap->Resolve(fd->object());
683
  }
684
}
685
686
// Reverse the logic applied by path.toNamespacedPath() to create a
687
// namespace-prefixed path.
688
480
void FromNamespacedPath(std::string* path) {
689
#ifdef _WIN32
690
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
691
    *path = path->substr(8);
692
    path->insert(0, "\\\\");
693
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
694
    *path = path->substr(4);
695
  }
696
#endif
697
480
}
698
699
591
void AfterMkdirp(uv_fs_t* req) {
700
591
  FSReqBase* req_wrap = FSReqBase::from_req(req);
701
1182
  FSReqAfterScope after(req_wrap, req);
702
703
  MaybeLocal<Value> path;
704
  Local<Value> error;
705
706
591
  if (after.Proceed()) {
707
585
    if (!req_wrap->continuation_data()->first_path().empty()) {
708
502
      std::string first_path(req_wrap->continuation_data()->first_path());
709
251
      FromNamespacedPath(&first_path);
710
      path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
711
                                 req_wrap->encoding(),
712
251
                                 &error);
713
251
      if (path.IsEmpty())
714
        req_wrap->Reject(error);
715
      else
716
502
        req_wrap->Resolve(path.ToLocalChecked());
717
    } else {
718
668
      req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
719
    }
720
  }
721
591
}
722
723
6
void AfterStringPath(uv_fs_t* req) {
724
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
725
12
  FSReqAfterScope after(req_wrap, req);
726
727
  MaybeLocal<Value> link;
728
  Local<Value> error;
729
730
6
  if (after.Proceed()) {
731
    link = StringBytes::Encode(req_wrap->env()->isolate(),
732
                               req->path,
733
                               req_wrap->encoding(),
734
5
                               &error);
735
5
    if (link.IsEmpty())
736
      req_wrap->Reject(error);
737
    else
738
10
      req_wrap->Resolve(link.ToLocalChecked());
739
  }
740
6
}
741
742
56
void AfterStringPtr(uv_fs_t* req) {
743
56
  FSReqBase* req_wrap = FSReqBase::from_req(req);
744
111
  FSReqAfterScope after(req_wrap, req);
745
746
  MaybeLocal<Value> link;
747
  Local<Value> error;
748
749
56
  if (after.Proceed()) {
750
    link = StringBytes::Encode(req_wrap->env()->isolate(),
751
51
                               static_cast<const char*>(req->ptr),
752
                               req_wrap->encoding(),
753
102
                               &error);
754
51
    if (link.IsEmpty())
755
      req_wrap->Reject(error);
756
    else
757
102
      req_wrap->Resolve(link.ToLocalChecked());
758
  }
759
55
}
760
761
89
void AfterScanDir(uv_fs_t* req) {
762
89
  FSReqBase* req_wrap = FSReqBase::from_req(req);
763
169
  FSReqAfterScope after(req_wrap, req);
764
765
89
  if (!after.Proceed()) {
766
9
    return;
767
  }
768
80
  Environment* env = req_wrap->env();
769
  Local<Value> error;
770
  int r;
771
160
  std::vector<Local<Value>> name_v;
772
773
  for (;;) {
774
    uv_dirent_t ent;
775
776
7221
    r = uv_fs_scandir_next(req, &ent);
777
7221
    if (r == UV_EOF)
778
80
      break;
779
7141
    if (r != 0) {
780
      return req_wrap->Reject(UVException(
781
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
782
    }
783
784
    MaybeLocal<Value> filename =
785
      StringBytes::Encode(env->isolate(),
786
          ent.name,
787
          req_wrap->encoding(),
788
7141
          &error);
789
7141
    if (filename.IsEmpty())
790
      return req_wrap->Reject(error);
791
792
7141
    name_v.push_back(filename.ToLocalChecked());
793
7141
  }
794
795
160
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
796
}
797
798
152
void AfterScanDirWithTypes(uv_fs_t* req) {
799
152
  FSReqBase* req_wrap = FSReqBase::from_req(req);
800
303
  FSReqAfterScope after(req_wrap, req);
801
802
152
  if (!after.Proceed()) {
803
1
    return;
804
  }
805
806
151
  Environment* env = req_wrap->env();
807
151
  Isolate* isolate = env->isolate();
808
  Local<Value> error;
809
  int r;
810
811
302
  std::vector<Local<Value>> name_v;
812
302
  std::vector<Local<Value>> type_v;
813
814
  for (;;) {
815
    uv_dirent_t ent;
816
817
166
    r = uv_fs_scandir_next(req, &ent);
818
166
    if (r == UV_EOF)
819
151
      break;
820
15
    if (r != 0) {
821
      return req_wrap->Reject(
822
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
823
    }
824
825
    MaybeLocal<Value> filename =
826
      StringBytes::Encode(isolate,
827
          ent.name,
828
          req_wrap->encoding(),
829
15
          &error);
830
15
    if (filename.IsEmpty())
831
      return req_wrap->Reject(error);
832
833
15
    name_v.push_back(filename.ToLocalChecked());
834
15
    type_v.emplace_back(Integer::New(isolate, ent.type));
835
15
  }
836
837
  Local<Value> result[] = {
838
    Array::New(isolate, name_v.data(), name_v.size()),
839
    Array::New(isolate, type_v.data(), type_v.size())
840
453
  };
841
302
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
842
}
843
844
269
void Access(const FunctionCallbackInfo<Value>& args) {
845
269
  Environment* env = Environment::GetCurrent(args);
846
269
  Isolate* isolate = env->isolate();
847
538
  HandleScope scope(isolate);
848
849
269
  const int argc = args.Length();
850
269
  CHECK_GE(argc, 2);
851
852
538
  CHECK(args[1]->IsInt32());
853
807
  int mode = args[1].As<Int32>()->Value();
854
855
538
  BufferValue path(isolate, args[0]);
856
269
  CHECK_NOT_NULL(*path);
857
858
269
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
859
269
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
860
44
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
861
44
              uv_fs_access, *path, mode);
862
  } else {  // access(path, mode, undefined, ctx)
863
225
    CHECK_EQ(argc, 4);
864
450
    FSReqWrapSync req_wrap_sync;
865
225
    FS_SYNC_TRACE_BEGIN(access);
866
450
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
867
226
    FS_SYNC_TRACE_END(access);
868
1
  }
869
271
}
870

3
871
2
872
54697
void Close(const FunctionCallbackInfo<Value>& args) {
873
54697
  Environment* env = Environment::GetCurrent(args);
874
875
54696
  const int argc = args.Length();
876
54695
  CHECK_GE(argc, 2);
877
878
109390
  CHECK(args[0]->IsInt32());
879
164085
  int fd = args[0].As<Int32>()->Value();
880
54695
  env->RemoveUnmanagedFd(fd);
881
882
54695
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
883
54695
  if (req_wrap_async != nullptr) {  // close(fd, req)
884
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
885
5069
              uv_fs_close, fd);
886
  } else {  // close(fd, undefined, ctx)
887
49626
    CHECK_EQ(argc, 3);
888
99252
    FSReqWrapSync req_wrap_sync;
889
49626
    FS_SYNC_TRACE_BEGIN(close);
890
49626
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
891
49656
    FS_SYNC_TRACE_END(close);
892
30
  }
893
54751
}
894

90
895
56
896
60
// Used to speed up module loading. Returns an array [string, boolean]
897
57821
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
898
57761
  Environment* env = Environment::GetCurrent(args);
899
57782
  Isolate* isolate = env->isolate();
900
57752
  uv_loop_t* loop = env->event_loop();
901
902
173280
  CHECK(args[0]->IsString());
903
63788
  node::Utf8Value path(isolate, args[0]);
904
905
57761
  if (strlen(*path) != path.length()) {
906
9
    args.GetReturnValue().Set(Array::New(isolate));
907
3
    return;  // Contains a nul byte.
908
  }
909
  uv_fs_t open_req;
910
57757
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
911
57758
  uv_fs_req_cleanup(&open_req);
912
913
57755
  if (fd < 0) {
914
155172
    args.GetReturnValue().Set(Array::New(isolate));
915
51723
    return;
916
  }
917
918
6029
  auto defer_close = OnScopeLeave([fd, loop]() {
919
    uv_fs_t close_req;
920
6029
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
921
6029
    uv_fs_req_cleanup(&close_req);
922
18086
  });
923
924
6029
  const size_t kBlockSize = 32 << 10;
925
12057
  std::vector<char> chars;
926
6029
  int64_t offset = 0;
927
  ssize_t numchars;
928
  do {
929
6029
    const size_t start = chars.size();
930
6029
    chars.resize(start + kBlockSize);
931
932
    uv_buf_t buf;
933
6029
    buf.base = &chars[start];
934
6029
    buf.len = kBlockSize;
935
936
    uv_fs_t read_req;
937
6029
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
938
6029
    uv_fs_req_cleanup(&read_req);
939
940
6029
    if (numchars < 0) {
941
3
      args.GetReturnValue().Set(Array::New(isolate));
942
1
      return;
943
    }
944
6028
    offset += numchars;
945
6028
  } while (static_cast<size_t>(numchars) == kBlockSize);
946
947
6028
  size_t start = 0;
948

6028
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
949
1
    start = 3;  // Skip UTF-8 BOM.
950
  }
951
952
6028
  const size_t size = offset - start;
953
6028
  char* p = &chars[start];
954
6028
  char* pe = &chars[size];
955
  char* pos[2];
956
6028
  char** ppos = &pos[0];
957
958
170078
  while (p < pe) {
959
88041
    char c = *p++;
960

88041
    if (c == '\\' && p < pe && *p == '"') p++;
961
88041
    if (c != '"') continue;
962
13730
    *ppos++ = p;
963
13730
    if (ppos < &pos[2]) continue;
964
6865
    ppos = &pos[0];
965
966
6865
    char* s = &pos[0][0];
967
6865
    char* se = &pos[1][-1];  // Exclude quote.
968
6865
    size_t n = se - s;
969
970
6865
    if (n == 4) {
971
6008
      if (0 == memcmp(s, "main", 4)) break;
972
5968
      if (0 == memcmp(s, "name", 4)) break;
973
27
      if (0 == memcmp(s, "type", 4)) break;
974
857
    } else if (n == 7) {
975
14
      if (0 == memcmp(s, "exports", 7)) break;
976
7
      if (0 == memcmp(s, "imports", 7)) break;
977
    }
978
  }
979
980
981
  Local<Value> return_value[] = {
982
12056
    String::NewFromUtf8(isolate,
983
6028
                        &chars[start],
984
                        v8::NewStringType::kNormal,
985
6028
                        size).ToLocalChecked(),
986
    Boolean::New(isolate, p < pe ? true : false)
987
18084
  };
988
18084
  args.GetReturnValue().Set(
989
    Array::New(isolate, return_value, arraysize(return_value)));
990
}
991
992
// Used to speed up module loading.  Returns 0 if the path refers to
993
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
994
// The speedup comes from not creating thousands of Stat and Error objects.
995
138510
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
996
138510
  Environment* env = Environment::GetCurrent(args);
997
998
415530
  CHECK(args[0]->IsString());
999
277020
  node::Utf8Value path(env->isolate(), args[0]);
1000
1001
  uv_fs_t req;
1002
138510
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1003
138510
  if (rc == 0) {
1004
67888
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1005
67888
    rc = !!(s->st_mode & S_IFDIR);
1006
  }
1007
138510
  uv_fs_req_cleanup(&req);
1008
1009
277020
  args.GetReturnValue().Set(rc);
1010
138510
}
1011
1012
15851
static void Stat(const FunctionCallbackInfo<Value>& args) {
1013
15851
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1014
15851
  Environment* env = binding_data->env();
1015
1016
15851
  const int argc = args.Length();
1017
15851
  CHECK_GE(argc, 2);
1018
1019
31453
  BufferValue path(env->isolate(), args[0]);
1020
15851
  CHECK_NOT_NULL(*path);
1021
1022
31702
  bool use_bigint = args[1]->IsTrue();
1023
15851
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1024
15851
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1025
2548
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1026
2548
              uv_fs_stat, *path);
1027
  } else {  // stat(path, use_bigint, undefined, ctx)
1028
13303
    CHECK_EQ(argc, 4);
1029
26357
    FSReqWrapSync req_wrap_sync;
1030
13303
    FS_SYNC_TRACE_BEGIN(stat);
1031
26606
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1032
13304
    FS_SYNC_TRACE_END(stat);
1033

13304
    if (err != 0) {
1034
251
      return;  // error info is in ctx
1035

4
    }
1036
2
1037
3
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1038
13056
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1039
26108
    args.GetReturnValue().Set(arr);
1040
1
  }
1041
}
1042
1043
111678
static void LStat(const FunctionCallbackInfo<Value>& args) {
1044
111678
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1045
111677
  Environment* env = binding_data->env();
1046
1047
111677
  const int argc = args.Length();
1048
111677
  CHECK_GE(argc, 3);
1049
1050
223032
  BufferValue path(env->isolate(), args[0]);
1051
111678
  CHECK_NOT_NULL(*path);
1052
1053
223356
  bool use_bigint = args[1]->IsTrue();
1054
111678
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1055
111678
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1056
3897
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1057
3897
              uv_fs_lstat, *path);
1058
  } else {  // lstat(path, use_bigint, undefined, ctx)
1059
107781
    CHECK_EQ(argc, 4);
1060
215239
    FSReqWrapSync req_wrap_sync;
1061
107781
    FS_SYNC_TRACE_BEGIN(lstat);
1062
107781
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1063
107798
                       *path);
1064

107798
    FS_SYNC_TRACE_END(lstat);
1065
107783
    if (err != 0) {
1066
376
      return;  // error info is in ctx
1067
34
    }
1068
2
1069
53
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1070
107475
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1071
214916
    args.GetReturnValue().Set(arr);
1072
17
  }
1073
}
1074
1075
45242
static void FStat(const FunctionCallbackInfo<Value>& args) {
1076
45242
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1077
45242
  Environment* env = binding_data->env();
1078
1079
45242
  const int argc = args.Length();
1080
45242
  CHECK_GE(argc, 2);
1081
1082
90484
  CHECK(args[0]->IsInt32());
1083
135726
  int fd = args[0].As<Int32>()->Value();
1084
1085
90484
  bool use_bigint = args[1]->IsTrue();
1086
45242
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1087
45242
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1088
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1089
956
              uv_fs_fstat, fd);
1090
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1091
44286
    CHECK_EQ(argc, 4);
1092
88551
    FSReqWrapSync req_wrap_sync;
1093
44286
    FS_SYNC_TRACE_BEGIN(fstat);
1094
44286
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1095
44291
    FS_SYNC_TRACE_END(fstat);
1096

44291
    if (err != 0) {
1097
29
      return;  // error info is in ctx
1098

18
    }
1099
8
1100
13
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1101
44275
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1102
88530
    args.GetReturnValue().Set(arr);
1103
5
  }
1104
}
1105
1106
330
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1107
330
  Environment* env = Environment::GetCurrent(args);
1108
330
  Isolate* isolate = env->isolate();
1109
1110
330
  const int argc = args.Length();
1111
330
  CHECK_GE(argc, 4);
1112
1113
660
  BufferValue target(isolate, args[0]);
1114
330
  CHECK_NOT_NULL(*target);
1115
660
  BufferValue path(isolate, args[1]);
1116
330
  CHECK_NOT_NULL(*path);
1117
1118
660
  CHECK(args[2]->IsInt32());
1119
990
  int flags = args[2].As<Int32>()->Value();
1120
1121
330
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1122
330
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1123
24
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1124
24
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1125
  } else {  // symlink(target, path, flags, undefinec, ctx)
1126
306
    CHECK_EQ(argc, 5);
1127
612
    FSReqWrapSync req_wrap_sync;
1128
306
    FS_SYNC_TRACE_BEGIN(symlink);
1129
306
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1130
308
             uv_fs_symlink, *target, *path, flags);
1131

308
    FS_SYNC_TRACE_END(symlink);
1132
2
  }
1133
338
}
1134
4
1135
70
static void Link(const FunctionCallbackInfo<Value>& args) {
1136
76
  Environment* env = Environment::GetCurrent(args);
1137
70
  Isolate* isolate = env->isolate();
1138
1139
70
  const int argc = args.Length();
1140
68
  CHECK_GE(argc, 3);
1141
1142
136
  BufferValue src(isolate, args[0]);
1143
68
  CHECK_NOT_NULL(*src);
1144
1145
136
  BufferValue dest(isolate, args[1]);
1146
68
  CHECK_NOT_NULL(*dest);
1147
1148
68
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1149
68
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1150
63
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1151
63
                  AfterNoArgs, uv_fs_link, *src, *dest);
1152
  } else {  // link(src, dest)
1153
5
    CHECK_EQ(argc, 4);
1154
10
    FSReqWrapSync req_wrap_sync;
1155
5
    FS_SYNC_TRACE_BEGIN(link);
1156
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1157
8
             uv_fs_link, *src, *dest);
1158

8
    FS_SYNC_TRACE_END(link);
1159
3
  }
1160
80
}
1161
6
1162
85
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1163
94
  Environment* env = Environment::GetCurrent(args);
1164
85
  Isolate* isolate = env->isolate();
1165
1166
85
  const int argc = args.Length();
1167
82
  CHECK_GE(argc, 3);
1168
1169
163
  BufferValue path(isolate, args[0]);
1170
82
  CHECK_NOT_NULL(*path);
1171
1172
82
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1173
1174
82
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1175
82
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1176
34
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1177
34
              uv_fs_readlink, *path);
1178
  } else {
1179
48
    CHECK_EQ(argc, 4);
1180
95
    FSReqWrapSync req_wrap_sync;
1181
48
    FS_SYNC_TRACE_BEGIN(readlink);
1182
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1183
49
                       uv_fs_readlink, *path);
1184

49
    FS_SYNC_TRACE_END(readlink);
1185
49
    if (err < 0) {
1186
5
      return;  // syscall failed, no need to continue, error info is in ctx
1187
2
    }
1188
48
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1189
4
1190
1
    Local<Value> error;
1191
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1192
1
                                               link_path,
1193
                                               encoding,
1194
47
                                               &error);
1195
47
    if (rc.IsEmpty()) {
1196
      Local<Object> ctx = args[3].As<Object>();
1197
      ctx->Set(env->context(), env->error_string(), error).Check();
1198
      return;
1199
    }
1200
1201
94
    args.GetReturnValue().Set(rc.ToLocalChecked());
1202
  }
1203
}
1204
1205
6
static void Rename(const FunctionCallbackInfo<Value>& args) {
1206
6
  Environment* env = Environment::GetCurrent(args);
1207
6
  Isolate* isolate = env->isolate();
1208
1209
6
  const int argc = args.Length();
1210
6
  CHECK_GE(argc, 3);
1211
1212
12
  BufferValue old_path(isolate, args[0]);
1213
6
  CHECK_NOT_NULL(*old_path);
1214
12
  BufferValue new_path(isolate, args[1]);
1215
6
  CHECK_NOT_NULL(*new_path);
1216
1217
6
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1218
6
  if (req_wrap_async != nullptr) {
1219
3
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1220
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1221
3
                  *old_path, *new_path);
1222
  } else {
1223
3
    CHECK_EQ(argc, 4);
1224
6
    FSReqWrapSync req_wrap_sync;
1225
3
    FS_SYNC_TRACE_BEGIN(rename);
1226
3
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1227
4
             *old_path, *new_path);
1228

4
    FS_SYNC_TRACE_END(rename);
1229
1
  }
1230
10
}
1231
2
1232
70
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1233
73
  Environment* env = Environment::GetCurrent(args);
1234
1
1235
69
  const int argc = args.Length();
1236
70
  CHECK_GE(argc, 3);
1237
1238
138
  CHECK(args[0]->IsInt32());
1239
207
  const int fd = args[0].As<Int32>()->Value();
1240
1241
69
  CHECK(IsSafeJsInt(args[1]));
1242
207
  const int64_t len = args[1].As<Integer>()->Value();
1243
1244
69
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1245
69
  if (req_wrap_async != nullptr) {
1246
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1247
54
              uv_fs_ftruncate, fd, len);
1248
  } else {
1249
15
    CHECK_EQ(argc, 4);
1250
30
    FSReqWrapSync req_wrap_sync;
1251
15
    FS_SYNC_TRACE_BEGIN(ftruncate);
1252
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1253
16
             len);
1254

16
    FS_SYNC_TRACE_END(ftruncate);
1255
1
  }
1256
73
}
1257
2
1258
8
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1259
11
  Environment* env = Environment::GetCurrent(args);
1260
1
1261
7
  const int argc = args.Length();
1262
8
  CHECK_GE(argc, 2);
1263
1264
14
  CHECK(args[0]->IsInt32());
1265
21
  const int fd = args[0].As<Int32>()->Value();
1266
1267
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1268
7
  if (req_wrap_async != nullptr) {
1269
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1270
4
              uv_fs_fdatasync, fd);
1271
  } else {
1272
3
    CHECK_EQ(argc, 3);
1273
6
    FSReqWrapSync req_wrap_sync;
1274
3
    FS_SYNC_TRACE_BEGIN(fdatasync);
1275
3
    SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1276
4
    FS_SYNC_TRACE_END(fdatasync);
1277
1
  }
1278
9
}
1279

4
1280
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1281
24
  Environment* env = Environment::GetCurrent(args);
1282
2
1283
21
  const int argc = args.Length();
1284
22
  CHECK_GE(argc, 2);
1285
1286
42
  CHECK(args[0]->IsInt32());
1287
63
  const int fd = args[0].As<Int32>()->Value();
1288
1289
21
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1290
21
  if (req_wrap_async != nullptr) {
1291
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1292
4
              uv_fs_fsync, fd);
1293
  } else {
1294
17
    CHECK_EQ(argc, 3);
1295
34
    FSReqWrapSync req_wrap_sync;
1296
17
    FS_SYNC_TRACE_BEGIN(fsync);
1297
17
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1298
18
    FS_SYNC_TRACE_END(fsync);
1299
1
  }
1300
23
}
1301

4
1302
2271
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1303
2272
  Environment* env = Environment::GetCurrent(args);
1304
2
1305
2269
  const int argc = args.Length();
1306
2270
  CHECK_GE(argc, 2);
1307
1308
4538
  BufferValue path(env->isolate(), args[0]);
1309
2269
  CHECK_NOT_NULL(*path);
1310
1311
2269
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1312
2269
  if (req_wrap_async != nullptr) {
1313
1013
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1314
1013
              uv_fs_unlink, *path);
1315
  } else {
1316
1256
    CHECK_EQ(argc, 3);
1317
2512
    FSReqWrapSync req_wrap_sync;
1318
1256
    FS_SYNC_TRACE_BEGIN(unlink);
1319
2512
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1320
1286
    FS_SYNC_TRACE_END(unlink);
1321
30
  }
1322
2324
}
1323

115
1324
1446
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1325
1476
  Environment* env = Environment::GetCurrent(args);
1326
60
1327
1391
  const int argc = args.Length();
1328
1421
  CHECK_GE(argc, 2);
1329
1330
2782
  BufferValue path(env->isolate(), args[0]);
1331
1391
  CHECK_NOT_NULL(*path);
1332
1333
1391
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1334
1391
  if (req_wrap_async != nullptr) {
1335
217
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1336
217
              uv_fs_rmdir, *path);
1337
  } else {  // rmdir(path, undefined, ctx)
1338
1174
    CHECK_EQ(argc, 3);
1339
2348
    FSReqWrapSync req_wrap_sync;
1340
1174
    FS_SYNC_TRACE_BEGIN(rmdir);
1341
1174
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1342
1177
             uv_fs_rmdir, *path);
1343

1177
    FS_SYNC_TRACE_END(rmdir);
1344
3
  }
1345
1403
}
1346
6
1347
5437
int MKDirpSync(uv_loop_t* loop,
1348
12
               uv_fs_t* req,
1349
3
               const std::string& path,
1350
               int mode,
1351
3
               uv_fs_cb cb) {
1352
5434
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1353
1354
  // on the first iteration of algorithm, stash state information.
1355
5435
  if (req_wrap->continuation_data() == nullptr) {
1356
    req_wrap->set_continuation_data(
1357
5434
        std::make_unique<FSContinuationData>(req, mode, cb));
1358
5435
    req_wrap->continuation_data()->PushPath(std::move(path));
1359
  }
1360
1361
15992
  while (req_wrap->continuation_data()->paths().size() > 0) {
1362
10813
    std::string next_path = req_wrap->continuation_data()->PopPath();
1363
5534
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1364
    while (true) {
1365

5535
      switch (err) {
1366
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1367
        // ~FSReqWrapSync():
1368
        case 0:
1369
300
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1370
300
          if (req_wrap->continuation_data()->paths().size() == 0) {
1371
251
            return 0;
1372
          }
1373
49
          break;
1374
        case UV_EACCES:
1375
        case UV_ENOTDIR:
1376
        case UV_EPERM: {
1377
2
          return err;
1378
        }
1379
        case UV_ENOENT: {
1380
          std::string dirname = next_path.substr(0,
1381
51
                                        next_path.find_last_of(kPathSeparator));
1382
51
          if (dirname != next_path) {
1383
50
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1384
50
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1385
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1386
1
            err = UV_EEXIST;
1387
1
            continue;
1388
          }
1389
50
          break;
1390
        }
1391
        default:
1392
5182
          uv_fs_req_cleanup(req);
1393
5182
          int orig_err = err;
1394
5182
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1395

5182
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1396
1
            uv_fs_req_cleanup(req);
1397

2
            if (orig_err == UV_EEXIST &&
1398
1
              req_wrap->continuation_data()->paths().size() > 0) {
1399
              return UV_ENOTDIR;
1400
            }
1401
1
            return UV_EEXIST;
1402
          }
1403
5181
          if (err < 0) return err;
1404
5180
          break;
1405
      }
1406
5279
      break;
1407
1
    }
1408
5279
    uv_fs_req_cleanup(req);
1409
  }
1410
1411
5180
  return 0;
1412
}
1413
1414
785
int MKDirpAsync(uv_loop_t* loop,
1415
                uv_fs_t* req,
1416
                const char* path,
1417
                int mode,
1418
                uv_fs_cb cb) {
1419
785
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1420
  // on the first iteration of algorithm, stash state information.
1421
785
  if (req_wrap->continuation_data() == nullptr) {
1422
    req_wrap->set_continuation_data(
1423
591
        std::make_unique<FSContinuationData>(req, mode, cb));
1424
591
    req_wrap->continuation_data()->PushPath(std::move(path));
1425
  }
1426
1427
  // on each iteration of algorithm, mkdir directory on top of stack.
1428
1570
  std::string next_path = req_wrap->continuation_data()->PopPath();
1429
785
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1430
2355
                        uv_fs_callback_t{[](uv_fs_t* req) {
1431
785
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1432
785
    Environment* env = req_wrap->env();
1433
785
    uv_loop_t* loop = env->event_loop();
1434
1570
    std::string path = req->path;
1435
785
    int err = static_cast<int>(req->result);
1436
1437
    while (true) {
1438

786
      switch (err) {
1439
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1440
        // FSReqAfterScope::~FSReqAfterScope()
1441
        case 0: {
1442
261
          if (req_wrap->continuation_data()->paths().size() == 0) {
1443
251
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1444
251
            req_wrap->continuation_data()->Done(0);
1445
          } else {
1446
10
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1447
10
            uv_fs_req_cleanup(req);
1448
10
            MKDirpAsync(loop, req, path.c_str(),
1449
10
                        req_wrap->continuation_data()->mode(), nullptr);
1450
          }
1451
261
          break;
1452
        }
1453
        case UV_EACCES:
1454
        case UV_ENOTDIR:
1455
        case UV_EPERM: {
1456
3
          req_wrap->continuation_data()->Done(err);
1457
3
          break;
1458
        }
1459
        case UV_ENOENT: {
1460
          std::string dirname = path.substr(0,
1461
98
                                            path.find_last_of(kPathSeparator));
1462
98
          if (dirname != path) {
1463
97
            req_wrap->continuation_data()->PushPath(std::move(path));
1464
97
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1465
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1466
1
            err = UV_EEXIST;
1467
1
            continue;
1468
          }
1469
97
          uv_fs_req_cleanup(req);
1470
97
          MKDirpAsync(loop, req, path.c_str(),
1471
97
                      req_wrap->continuation_data()->mode(), nullptr);
1472
97
          break;
1473
        }
1474
        default:
1475
424
          uv_fs_req_cleanup(req);
1476
          // Stash err for use in the callback.
1477
424
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1478
424
          int err = uv_fs_stat(loop, req, path.c_str(),
1479
1272
                               uv_fs_callback_t{[](uv_fs_t* req) {
1480
424
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1481
424
            int err = static_cast<int>(req->result);
1482

848
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1483
424
                  req_wrap->continuation_data()->paths().size() > 0) {
1484

87
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1485
87
                Environment* env = req_wrap->env();
1486
87
                uv_loop_t* loop = env->event_loop();
1487
174
                std::string path = req->path;
1488
87
                uv_fs_req_cleanup(req);
1489
87
                MKDirpAsync(loop, req, path.c_str(),
1490
87
                            req_wrap->continuation_data()->mode(), nullptr);
1491
87
                return;
1492
              }
1493
              err = UV_ENOTDIR;
1494
            }
1495
            // verify that the path pointed to is actually a directory.
1496

337
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1497
337
            req_wrap->continuation_data()->Done(err);
1498
1272
          }});
1499
424
          if (err < 0) req_wrap->continuation_data()->Done(err);
1500
424
          break;
1501
      }
1502
785
      break;
1503
1
    }
1504
3140
  }});
1505
1506
1570
  return err;
1507
}
1508
1509
235
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1510
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1511
235
  env->PrintSyncTrace();
1512
470
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1513
235
                       nullptr);
1514
235
  if (err < 0) {
1515
4
    v8::Local<v8::Context> context = env->context();
1516
8
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1517
4
    v8::Isolate* isolate = env->isolate();
1518
8
    ctx_obj->Set(context,
1519
                 env->errno_string(),
1520
16
                 v8::Integer::New(isolate, err)).Check();
1521
8
    ctx_obj->Set(context,
1522
                 env->syscall_string(),
1523
16
                 OneByteString(isolate, "mkdir")).Check();
1524
  }
1525
235
  return err;
1526
}
1527
1528
1812
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1529
1812
  Environment* env = Environment::GetCurrent(args);
1530
1531
1812
  const int argc = args.Length();
1532
1812
  CHECK_GE(argc, 4);
1533
1534
3624
  BufferValue path(env->isolate(), args[0]);
1535
1812
  CHECK_NOT_NULL(*path);
1536
1537
3624
  CHECK(args[1]->IsInt32());
1538
5436
  const int mode = args[1].As<Int32>()->Value();
1539
1540
3624
  CHECK(args[2]->IsBoolean());
1541
3624
  bool mkdirp = args[2]->IsTrue();
1542
1543
1812
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1544
1812
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1545

810
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1546
              mkdirp ? AfterMkdirp : AfterNoArgs,
1547
810
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1548
  } else {  // mkdir(path, mode, undefined, ctx)
1549
1002
    CHECK_EQ(argc, 5);
1550
2004
    FSReqWrapSync req_wrap_sync;
1551
1002
    FS_SYNC_TRACE_BEGIN(mkdir);
1552
1002
    if (mkdirp) {
1553
237
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1554


468
      if (err == 0 &&
1555
233
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1556
6
        Local<Value> error;
1557
460
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1558
229
        FromNamespacedPath(&first_path);
1559
2
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1560
                                                     first_path.c_str(),
1561
229
                                                     UTF8, &error);
1562
229
        if (path.IsEmpty()) {
1563
          Local<Object> ctx = args[4].As<Object>();
1564
          ctx->Set(env->context(), env->error_string(), error).Check();
1565
          return;
1566
        }
1567
458
        args.GetReturnValue().Set(path.ToLocalChecked());
1568
      }
1569
    } else {
1570
767
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1571
767
               uv_fs_mkdir, *path, mode);
1572
    }
1573
1002
    FS_SYNC_TRACE_END(mkdir);
1574
  }
1575
2
}
1576
2
1577
44
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1578
48
  Environment* env = Environment::GetCurrent(args);
1579
44
  Isolate* isolate = env->isolate();
1580
1581
44
  const int argc = args.Length();
1582
42
  CHECK_GE(argc, 3);
1583
1584
82
  BufferValue path(isolate, args[0]);
1585
42
  CHECK_NOT_NULL(*path);
1586
1587
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1588
1589
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1590
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1591
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1592
22
              uv_fs_realpath, *path);
1593
  } else {  // realpath(path, encoding, undefined, ctx)
1594
20
    CHECK_EQ(argc, 4);
1595
38
    FSReqWrapSync req_wrap_sync;
1596
20
    FS_SYNC_TRACE_BEGIN(realpath);
1597
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1598
21
                       uv_fs_realpath, *path);
1599

21
    FS_SYNC_TRACE_END(realpath);
1600
21
    if (err < 0) {
1601
6
      return;  // syscall failed, no need to continue, error info is in ctx
1602
2
    }
1603
1
1604
22
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1605
1
1606
    Local<Value> error;
1607
1
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1608
                                               link_path,
1609
                                               encoding,
1610
18
                                               &error);
1611
18
    if (rc.IsEmpty()) {
1612
      Local<Object> ctx = args[3].As<Object>();
1613
      ctx->Set(env->context(), env->error_string(), error).Check();
1614
      return;
1615
    }
1616
1617
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1618
  }
1619
}
1620
1621
13663
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1622
13663
  Environment* env = Environment::GetCurrent(args);
1623
13663
  Isolate* isolate = env->isolate();
1624
1625
13663
  const int argc = args.Length();
1626
13663
  CHECK_GE(argc, 3);
1627
1628
27165
  BufferValue path(isolate, args[0]);
1629
13663
  CHECK_NOT_NULL(*path);
1630
1631
13663
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1632
1633
27326
  bool with_types = args[2]->IsTrue();
1634
1635
13663
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1636
13663
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1637
241
    if (with_types) {
1638
152
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1639
152
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1640
    } else {
1641
89
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1642
89
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1643
    }
1644
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1645
13422
    CHECK_EQ(argc, 5);
1646
26683
    FSReqWrapSync req_wrap_sync;
1647
13422
    FS_SYNC_TRACE_BEGIN(readdir);
1648
13422
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1649
13423
                       uv_fs_scandir, *path, 0 /*flags*/);
1650

13423
    FS_SYNC_TRACE_END(readdir);
1651
13423
    if (err < 0) {
1652
165
      return;  // syscall failed, no need to continue, error info is in ctx
1653
2
    }
1654
1
1655

13265
    CHECK_GE(req_wrap_sync.req.result, 0);
1656
1
    int r;
1657
26522
    std::vector<Local<Value>> name_v;
1658
26523
    std::vector<Local<Value>> type_v;
1659
1660
    for (;;) {
1661
      uv_dirent_t ent;
1662
1663
741759
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1664
741759
      if (r == UV_EOF)
1665
13261
        break;
1666
728498
      if (r != 0) {
1667
        Local<Object> ctx = args[4].As<Object>();
1668
        ctx->Set(env->context(), env->errno_string(),
1669
                 Integer::New(isolate, r)).Check();
1670
        ctx->Set(env->context(), env->syscall_string(),
1671
                 OneByteString(isolate, "readdir")).Check();
1672
        return;
1673
      }
1674
1675
      Local<Value> error;
1676
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1677
                                                       ent.name,
1678
                                                       encoding,
1679
728498
                                                       &error);
1680
1681
728498
      if (filename.IsEmpty()) {
1682
        Local<Object> ctx = args[4].As<Object>();
1683
        ctx->Set(env->context(), env->error_string(), error).Check();
1684
        return;
1685
      }
1686
1687
728498
      name_v.push_back(filename.ToLocalChecked());
1688
1689
728498
      if (with_types) {
1690
46472
        type_v.emplace_back(Integer::New(isolate, ent.type));
1691
      }
1692
728498
    }
1693
1694
1695
13261
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1696
13261
    if (with_types) {
1697
      Local<Value> result[] = {
1698
        names,
1699
        Array::New(isolate, type_v.data(), type_v.size())
1700
186
      };
1701
186
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1702
    } else {
1703
26398
      args.GetReturnValue().Set(names);
1704
    }
1705
  }
1706
}
1707
1708
55336
static void Open(const FunctionCallbackInfo<Value>& args) {
1709
55336
  Environment* env = Environment::GetCurrent(args);
1710
1711
55336
  const int argc = args.Length();
1712
55336
  CHECK_GE(argc, 3);
1713
1714
110672
  BufferValue path(env->isolate(), args[0]);
1715
55336
  CHECK_NOT_NULL(*path);
1716
1717
110672
  CHECK(args[1]->IsInt32());
1718
166008
  const int flags = args[1].As<Int32>()->Value();
1719
1720
110672
  CHECK(args[2]->IsInt32());
1721
166008
  const int mode = args[2].As<Int32>()->Value();
1722
1723
55336
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1724
55336
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1725
5348
    req_wrap_async->set_is_plain_open(true);
1726
5348
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1727
5348
              uv_fs_open, *path, flags, mode);
1728
  } else {  // open(path, flags, mode, undefined, ctx)
1729
49988
    CHECK_EQ(argc, 5);
1730
99976
    FSReqWrapSync req_wrap_sync;
1731

50024
    FS_SYNC_TRACE_BEGIN(open);
1732
49988
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1733
49988
                          uv_fs_open, *path, flags, mode);
1734
49988
    FS_SYNC_TRACE_END(open);
1735
50014
    if (result >= 0) env->AddUnmanagedFd(result);
1736
100110
    args.GetReturnValue().Set(result);
1737
72
  }
1738
55362
}
1739
134
1740
783
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1741
747
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1742
783
  Environment* env = binding_data->env();
1743
747
  Isolate* isolate = env->isolate();
1744
1745
747
  const int argc = args.Length();
1746
747
  CHECK_GE(argc, 3);
1747
1748
1494
  BufferValue path(isolate, args[0]);
1749
747
  CHECK_NOT_NULL(*path);
1750
1751
1494
  CHECK(args[1]->IsInt32());
1752
2241
  const int flags = args[1].As<Int32>()->Value();
1753
1754
1494
  CHECK(args[2]->IsInt32());
1755
2241
  const int mode = args[2].As<Int32>()->Value();
1756
1757
747
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1758
747
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1759
746
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1760
746
              uv_fs_open, *path, flags, mode);
1761
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1762
1
    CHECK_EQ(argc, 5);
1763
2
    FSReqWrapSync req_wrap_sync;
1764
1
    FS_SYNC_TRACE_BEGIN(open);
1765
1
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1766
1
                          uv_fs_open, *path, flags, mode);
1767

1
    FS_SYNC_TRACE_END(open);
1768
1
    if (result < 0) {
1769
      return;  // syscall failed, no need to continue, error info is in ctx
1770
    }
1771
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1772

1
    if (fd == nullptr) return;
1773
3
    args.GetReturnValue().Set(fd->object());
1774
  }
1775
}
1776
1777
36
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1778
36
  Environment* env = Environment::GetCurrent(args);
1779
36
  Isolate* isolate = env->isolate();
1780
1781
36
  const int argc = args.Length();
1782
36
  CHECK_GE(argc, 3);
1783
1784
72
  BufferValue src(isolate, args[0]);
1785
36
  CHECK_NOT_NULL(*src);
1786
1787
72
  BufferValue dest(isolate, args[1]);
1788
36
  CHECK_NOT_NULL(*dest);
1789
1790
72
  CHECK(args[2]->IsInt32());
1791
108
  const int flags = args[2].As<Int32>()->Value();
1792
1793
36
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1794
36
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1795
17
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1796
17
                  *dest, dest.length(), UTF8, AfterNoArgs,
1797
17
                  uv_fs_copyfile, *src, *dest, flags);
1798
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1799
19
    CHECK_EQ(argc, 5);
1800
38
    FSReqWrapSync req_wrap_sync;
1801
19
    FS_SYNC_TRACE_BEGIN(copyfile);
1802
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1803
20
             uv_fs_copyfile, *src, *dest, flags);
1804

20
    FS_SYNC_TRACE_END(copyfile);
1805
1
  }
1806
40
}
1807
2
1808
1
1809
4
// Wrapper for write(2).
1810
1
//
1811
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1812
1
// 0 fd        integer. file descriptor
1813
// 1 buffer    the data to write
1814
// 2 offset    where in the buffer to start from
1815
// 3 length    how much to write
1816
// 4 position  if integer, position to write at in the file.
1817
//             if null, write from the current position
1818
39072
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1819
39072
  Environment* env = Environment::GetCurrent(args);
1820
1821
39072
  const int argc = args.Length();
1822
39072
  CHECK_GE(argc, 4);
1823
1824
78144
  CHECK(args[0]->IsInt32());
1825
117216
  const int fd = args[0].As<Int32>()->Value();
1826
1827
39072
  CHECK(Buffer::HasInstance(args[1]));
1828
78144
  Local<Object> buffer_obj = args[1].As<Object>();
1829
39072
  char* buffer_data = Buffer::Data(buffer_obj);
1830
39072
  size_t buffer_length = Buffer::Length(buffer_obj);
1831
1832
39072
  CHECK(IsSafeJsInt(args[2]));
1833
117216
  const int64_t off_64 = args[2].As<Integer>()->Value();
1834
39072
  CHECK_GE(off_64, 0);
1835
39072
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1836
39072
  const size_t off = static_cast<size_t>(off_64);
1837
1838
78144
  CHECK(args[3]->IsInt32());
1839
117216
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1840
39072
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1841
39072
  CHECK_LE(len, buffer_length);
1842
39072
  CHECK_GE(off + len, off);
1843
1844
39072
  const int64_t pos = GetOffset(args[4]);
1845
1846
39072
  char* buf = buffer_data + off;
1847
39072
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1848
1849
39072
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1850
39072
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1851
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1852
16492
              uv_fs_write, fd, &uvbuf, 1, pos);
1853
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1854
22580
    CHECK_EQ(argc, 7);
1855
45160
    FSReqWrapSync req_wrap_sync;
1856

22605
    FS_SYNC_TRACE_BEGIN(write);
1857
22580
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1858
22580
                                uv_fs_write, fd, &uvbuf, 1, pos);
1859
22580
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1860
67765
    args.GetReturnValue().Set(bytesWritten);
1861
100
  }
1862
39122
}
1863
25
1864
100
1865
25
// Wrapper for writev(2).
1866
//
1867
25
// bytesWritten = writev(fd, chunks, position, callback)
1868
// 0 fd        integer. file descriptor
1869
// 1 chunks    array of buffers to write
1870
// 2 position  if integer, position to write at in the file.
1871
//             if null, write from the current position
1872
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1873
18
  Environment* env = Environment::GetCurrent(args);
1874
1875
18
  const int argc = args.Length();
1876
18
  CHECK_GE(argc, 3);
1877
1878
36
  CHECK(args[0]->IsInt32());
1879
54
  const int fd = args[0].As<Int32>()->Value();
1880
1881
36
  CHECK(args[1]->IsArray());
1882
36
  Local<Array> chunks = args[1].As<Array>();
1883
1884
18
  int64_t pos = GetOffset(args[2]);
1885
1886
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1887
1888
71
  for (uint32_t i = 0; i < iovs.length(); i++) {
1889
159
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1890
53
    CHECK(Buffer::HasInstance(chunk));
1891
53
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1892
  }
1893
1894
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1895
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1896
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1897
14
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1898
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1899
4
    CHECK_EQ(argc, 5);
1900
8
    FSReqWrapSync req_wrap_sync;
1901
4
    FS_SYNC_TRACE_BEGIN(write);
1902
8
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1903
4
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1904

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1905
12
    args.GetReturnValue().Set(bytesWritten);
1906
  }
1907
18
}
1908
1909
1910
// Wrapper for write(2).
1911
//
1912
// bytesWritten = write(fd, string, position, enc, callback)
1913
// 0 fd        integer. file descriptor
1914
// 1 string    non-buffer values are converted to strings
1915
// 2 position  if integer, position to write at in the file.
1916
//             if null, write from the current position
1917
// 3 enc       encoding of string
1918
105277
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1919
105277
  Environment* env = Environment::GetCurrent(args);
1920
105277
  Isolate* isolate = env->isolate();
1921
1922
105277
  const int argc = args.Length();
1923
105277
  CHECK_GE(argc, 4);
1924
1925
210554
  CHECK(args[0]->IsInt32());
1926
315831
  const int fd = args[0].As<Int32>()->Value();
1927
1928
105277
  const int64_t pos = GetOffset(args[2]);
1929
1930
105277
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1931
1932
105277
  Local<Value> value = args[1];
1933
105277
  char* buf = nullptr;
1934
  size_t len;
1935
1936
105277
  FSReqBase* req_wrap_async = GetReqWrap(args, 4);
1937
105277
  const bool is_async = req_wrap_async != nullptr;
1938
1939
  // Avoid copying the string when it is externalized but only when:
1940
  // 1. The target encoding is compatible with the string's encoding, and
1941
  // 2. The write is synchronous, otherwise the string might get neutered
1942
  //    while the request is in flight, and
1943
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1944
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1945
  // The const_casts are conceptually sound: memory is read but not written.
1946

315679
  if (!is_async && value->IsString()) {
1947
105201
    auto string = value.As<String>();
1948


105202
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1949
1
      auto ext = string->GetExternalOneByteStringResource();
1950
1
      buf = const_cast<char*>(ext->data());
1951
1
      len = ext->length();
1952


105201
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
1953
2
      auto ext = string->GetExternalStringResource();
1954
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1955
1
      len = ext->length() * sizeof(*ext->data());
1956
    }
1957
  }
1958
1959
105277
  if (is_async) {  // write(fd, string, pos, enc, req)
1960
76
    CHECK_NOT_NULL(req_wrap_async);
1961
152
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1962
    FSReqBase::FSReqBuffer& stack_buffer =
1963
76
        req_wrap_async->Init("write", len, enc);
1964
    // StorageSize may return too large a char, so correct the actual length
1965
    // by the write size
1966
76
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1967
76
    stack_buffer.SetLengthAndZeroTerminate(len);
1968
76
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1969
76
    int err = req_wrap_async->Dispatch(uv_fs_write,
1970
                                       fd,
1971
                                       &uvbuf,
1972
                                       1,
1973
                                       pos,
1974
76
                                       AfterInteger);
1975
76
    if (err < 0) {
1976
      uv_fs_t* uv_req = req_wrap_async->req();
1977
      uv_req->result = err;
1978
      uv_req->path = nullptr;
1979
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1980
                             // an error
1981
    } else {
1982
76
      req_wrap_async->SetReturnValue(args);
1983
    }
1984
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1985
105201
    CHECK_EQ(argc, 6);
1986
210402
    FSReqWrapSync req_wrap_sync;
1987
210402
    FSReqBase::FSReqBuffer stack_buffer;
1988
105201
    if (buf == nullptr) {
1989
210398
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1990
        return;
1991
105199
      stack_buffer.AllocateSufficientStorage(len + 1);
1992
      // StorageSize may return too large a char, so correct the actual length
1993
      // by the write size
1994
105199
      len = StringBytes::Write(isolate, *stack_buffer,
1995
                               len, args[1], enc);
1996
105199
      stack_buffer.SetLengthAndZeroTerminate(len);
1997
105199
      buf = *stack_buffer;
1998
    }
1999
105201
    uv_buf_t uvbuf = uv_buf_init(buf, len);
2000
105201
    FS_SYNC_TRACE_BEGIN(write);
2001
105201
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2002
105201
                                uv_fs_write, fd, &uvbuf, 1, pos);
2003

105201
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2004
315603
    args.GetReturnValue().Set(bytesWritten);
2005
  }
2006
}
2007
2008
2009
/*
2010
 * Wrapper for read(2).
2011
 *
2012
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2013
 *
2014
 * 0 fd        int32. file descriptor
2015
 * 1 buffer    instance of Buffer
2016
 * 2 offset    int64. offset to start reading into inside buffer
2017
 * 3 length    int32. length to read
2018
 * 4 position  int64. file position - -1 for current position
2019
 */
2020
61669
static void Read(const FunctionCallbackInfo<Value>& args) {
2021
61669
  Environment* env = Environment::GetCurrent(args);
2022
2023
61669
  const int argc = args.Length();
2024
61669
  CHECK_GE(argc, 5);
2025
2026
123338
  CHECK(args[0]->IsInt32());
2027
185007
  const int fd = args[0].As<Int32>()->Value();
2028
2029
61669
  CHECK(Buffer::HasInstance(args[1]));
2030
123338
  Local<Object> buffer_obj = args[1].As<Object>();
2031
61669
  char* buffer_data = Buffer::Data(buffer_obj);
2032
61669
  size_t buffer_length = Buffer::Length(buffer_obj);
2033
2034
61669
  CHECK(IsSafeJsInt(args[2]));
2035
185007
  const int64_t off_64 = args[2].As<Integer>()->Value();
2036
61669
  CHECK_GE(off_64, 0);
2037
61669
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2038
61669
  const size_t off = static_cast<size_t>(off_64);
2039
2040
123338
  CHECK(args[3]->IsInt32());
2041
185007
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2042
61669
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2043
2044

61677
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2045
246676
  const int64_t pos = args[4]->IsNumber() ?
2046
246664
                      args[4].As<Integer>()->Value() :
2047
61681
                      args[4].As<BigInt>()->Int64Value();
2048
2049
61669
  char* buf = buffer_data + off;
2050
61669
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2051
2052
61669
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2053
61669
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2054
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2055
13693
              uv_fs_read, fd, &uvbuf, 1, pos);
2056
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2057
47976
    CHECK_EQ(argc, 7);
2058
95952
    FSReqWrapSync req_wrap_sync;
2059

47981
    FS_SYNC_TRACE_BEGIN(read);
2060
47976
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2061
47976
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2062
47976
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2063
143931
    args.GetReturnValue().Set(bytesRead);
2064
18
  }
2065
61679
}
2066
3
2067
18
2068
5
// Wrapper for readv(2).
2069
//
2070
5
// bytesRead = fs.readv(fd, buffers[, position], callback)
2071
// 0 fd        integer. file descriptor
2072
// 1 buffers   array of buffers to read
2073
// 2 position  if integer, position to read at in the file.
2074
//             if null, read from the current position
2075
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2076
11
  Environment* env = Environment::GetCurrent(args);
2077
2078
11
  const int argc = args.Length();
2079
11
  CHECK_GE(argc, 3);
2080
2081
22
  CHECK(args[0]->IsInt32());
2082
33
  const int fd = args[0].As<Int32>()->Value();
2083
2084
22
  CHECK(args[1]->IsArray());
2085
22
  Local<Array> buffers = args[1].As<Array>();
2086
2087
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2088
2089
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2090
2091
  // Init uv buffers from ArrayBufferViews
2092
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2093
51
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2094
17
    CHECK(Buffer::HasInstance(buffer));
2095
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2096
  }
2097
2098
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2099
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2100
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2101
7
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2102
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2103
4
    CHECK_EQ(argc, 5);
2104
8
    FSReqWrapSync req_wrap_sync;
2105
4
    FS_SYNC_TRACE_BEGIN(read);
2106
8
    int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2107
4
                             uv_fs_read, fd, *iovs, iovs.length(), pos);
2108

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2109
12
    args.GetReturnValue().Set(bytesRead);
2110
  }
2111
11
}
2112
2113
2114
/* fs.chmod(path, mode);
2115
 * Wrapper for chmod(1) / EIO_CHMOD
2116
 */
2117
89
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2118
89
  Environment* env = Environment::GetCurrent(args);
2119
2120
89
  const int argc = args.Length();
2121
89
  CHECK_GE(argc, 2);
2122
2123
178
  BufferValue path(env->isolate(), args[0]);
2124
89
  CHECK_NOT_NULL(*path);
2125
2126
178
  CHECK(args[1]->IsInt32());
2127
267
  int mode = args[1].As<Int32>()->Value();
2128
2129
89
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2130
89
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2131
70
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2132
70
              uv_fs_chmod, *path, mode);
2133
  } else {  // chmod(path, mode, undefined, ctx)
2134
19
    CHECK_EQ(argc, 4);
2135
38
    FSReqWrapSync req_wrap_sync;
2136
19
    FS_SYNC_TRACE_BEGIN(chmod);
2137
19
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2138
20
             uv_fs_chmod, *path, mode);
2139

20
    FS_SYNC_TRACE_END(chmod);
2140
1
  }
2141
93
}
2142
2
2143
1
2144
4
/* fs.fchmod(fd, mode);
2145
1
 * Wrapper for fchmod(1) / EIO_FCHMOD
2146
 */
2147
13
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2148
12
  Environment* env = Environment::GetCurrent(args);
2149
2150
12
  const int argc = args.Length();
2151
12
  CHECK_GE(argc, 2);
2152
2153
24
  CHECK(args[0]->IsInt32());
2154
36
  const int fd = args[0].As<Int32>()->Value();
2155
2156
24
  CHECK(args[1]->IsInt32());
2157
36
  const int mode = args[1].As<Int32>()->Value();
2158
2159
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2160
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2161
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2162
7
              uv_fs_fchmod, fd, mode);
2163
  } else {  // fchmod(fd, mode, undefined, ctx)
2164
5
    CHECK_EQ(argc, 4);
2165
10
    FSReqWrapSync req_wrap_sync;
2166
5
    FS_SYNC_TRACE_BEGIN(fchmod);
2167
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2168
6
             uv_fs_fchmod, fd, mode);
2169

6
    FS_SYNC_TRACE_END(fchmod);
2170
1
  }
2171
16
}
2172
2
2173
1
2174
4
/* fs.chown(path, uid, gid);
2175
1
 * Wrapper for chown(1) / EIO_CHOWN
2176
 */
2177
5
static void Chown(const FunctionCallbackInfo<Value>& args) {
2178
4
  Environment* env = Environment::GetCurrent(args);
2179
2180
4
  const int argc = args.Length();
2181
4
  CHECK_GE(argc, 3);
2182
2183
8
  BufferValue path(env->isolate(), args[0]);
2184
4
  CHECK_NOT_NULL(*path);
2185
2186
4
  CHECK(IsSafeJsInt(args[1]));
2187
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2188
2189
4
  CHECK(IsSafeJsInt(args[2]));
2190
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2191
2192
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2193
4
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2194
2
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2195
2
              uv_fs_chown, *path, uid, gid);
2196
  } else {  // chown(path, uid, gid, undefined, ctx)
2197
2
    CHECK_EQ(argc, 5);
2198
4
    FSReqWrapSync req_wrap_sync;
2199
2
    FS_SYNC_TRACE_BEGIN(chown);
2200
2
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2201
3
             uv_fs_chown, *path, uid, gid);
2202

3
    FS_SYNC_TRACE_END(chown);
2203
1
  }
2204
8
}
2205
2
2206
1
2207
4
/* fs.fchown(fd, uid, gid);
2208
1
 * Wrapper for fchown(1) / EIO_FCHOWN
2209
 */
2210
5
static void FChown(const FunctionCallbackInfo<Value>& args) {
2211
4
  Environment* env = Environment::GetCurrent(args);
2212
2213
4
  const int argc = args.Length();
2214
4
  CHECK_GE(argc, 3);
2215
2216
8
  CHECK(args[0]->IsInt32());
2217
12
  const int fd = args[0].As<Int32>()->Value();
2218
2219
4
  CHECK(IsSafeJsInt(args[1]));
2220
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2221
2222
4
  CHECK(IsSafeJsInt(args[2]));
2223
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2224
2225
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2226
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2227
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2228
2
              uv_fs_fchown, fd, uid, gid);
2229
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2230
2
    CHECK_EQ(argc, 5);
2231
4
    FSReqWrapSync req_wrap_sync;
2232
2
    FS_SYNC_TRACE_BEGIN(fchown);
2233
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2234
3
             uv_fs_fchown, fd, uid, gid);
2235

3
    FS_SYNC_TRACE_END(fchown);
2236
1
  }
2237
8
}
2238
2
2239
1
2240
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2241
6
  Environment* env = Environment::GetCurrent(args);
2242
2243
6
  const int argc = args.Length();
2244
5
  CHECK_GE(argc, 3);
2245
2246
10
  BufferValue path(env->isolate(), args[0]);
2247
5
  CHECK_NOT_NULL(*path);
2248
2249
5
  CHECK(IsSafeJsInt(args[1]));
2250
15
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2251
2252
5
  CHECK(IsSafeJsInt(args[2]));
2253
15
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2254
2255
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2256
5
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2257
3
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2258
3
              uv_fs_lchown, *path, uid, gid);
2259
  } else {  // lchown(path, uid, gid, undefined, ctx)
2260
2
    CHECK_EQ(argc, 5);
2261
4
    FSReqWrapSync req_wrap_sync;
2262
2
    FS_SYNC_TRACE_BEGIN(lchown);
2263
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2264
3
             uv_fs_lchown, *path, uid, gid);
2265

3
    FS_SYNC_TRACE_END(lchown);
2266
1
  }
2267
9
}
2268
2
2269
1
2270
37
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2271
34
  Environment* env = Environment::GetCurrent(args);
2272
2273
34
  const int argc = args.Length();
2274
33
  CHECK_GE(argc, 3);
2275
2276
66
  BufferValue path(env->isolate(), args[0]);
2277
33
  CHECK_NOT_NULL(*path);
2278
2279
66
  CHECK(args[1]->IsNumber());
2280
99
  const double atime = args[1].As<Number>()->Value();
2281
2282
66
  CHECK(args[2]->IsNumber());
2283
99
  const double mtime = args[2].As<Number>()->Value();
2284
2285
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2286
33
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2287
16
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2288
16
              uv_fs_utime, *path, atime, mtime);
2289
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2290
17
    CHECK_EQ(argc, 5);
2291
34
    FSReqWrapSync req_wrap_sync;
2292
17
    FS_SYNC_TRACE_BEGIN(utimes);
2293
17
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2294
18
             uv_fs_utime, *path, atime, mtime);
2295

18
    FS_SYNC_TRACE_END(utimes);
2296
1
  }
2297
37
}
2298
2
2299
1869
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2300
1872
  Environment* env = Environment::GetCurrent(args);
2301
1
2302
1868
  const int argc = args.Length();
2303
1869
  CHECK_GE(argc, 3);
2304
2305
3736
  CHECK(args[0]->IsInt32());
2306
5604
  const int fd = args[0].As<Int32>()->Value();
2307
2308
3736
  CHECK(args[1]->IsNumber());
2309
5604
  const double atime = args[1].As<Number>()->Value();
2310
2311
3736
  CHECK(args[2]->IsNumber());
2312
5604
  const double mtime = args[2].As<Number>()->Value();
2313
2314
1868
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2315
1868
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2316
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2317
1859
              uv_fs_futime, fd, atime, mtime);
2318
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2319
9
    CHECK_EQ(argc, 5);
2320
18
    FSReqWrapSync req_wrap_sync;
2321
9
    FS_SYNC_TRACE_BEGIN(futimes);
2322
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2323
10
             uv_fs_futime, fd, atime, mtime);
2324

10
    FS_SYNC_TRACE_END(futimes);
2325
1
  }
2326
1872
}
2327
2
2328
16
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2329
19
  Environment* env = Environment::GetCurrent(args);
2330
1
2331
15
  const int argc = args.Length();
2332
16
  CHECK_GE(argc, 3);
2333
2334
30
  BufferValue path(env->isolate(), args[0]);
2335
15
  CHECK_NOT_NULL(*path);
2336
2337
30
  CHECK(args[1]->IsNumber());
2338
45
  const double atime = args[1].As<Number>()->Value();
2339
2340
30
  CHECK(args[2]->IsNumber());
2341
45
  const double mtime = args[2].As<Number>()->Value();
2342
2343
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2344
15
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2345
8
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2346
8
              uv_fs_lutime, *path, atime, mtime);
2347
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2348
7
    CHECK_EQ(argc, 5);
2349
14
    FSReqWrapSync req_wrap_sync;
2350
7
    FS_SYNC_TRACE_BEGIN(lutimes);
2351
7
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2352
7
             uv_fs_lutime, *path, atime, mtime);
2353

7
    FS_SYNC_TRACE_END(lutimes);
2354
  }
2355
15
}
2356
2357
15
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2358
15
  Environment* env = Environment::GetCurrent(args);
2359
15
  Isolate* isolate = env->isolate();
2360
2361
15
  const int argc = args.Length();
2362
15
  CHECK_GE(argc, 2);
2363
2364
30
  BufferValue tmpl(isolate, args[0]);
2365
15
  CHECK_NOT_NULL(*tmpl);
2366
2367
15
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2368
2369
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2370
15
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2371
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2372
6
              uv_fs_mkdtemp, *tmpl);
2373
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2374
9
    CHECK_EQ(argc, 4);
2375
18
    FSReqWrapSync req_wrap_sync;
2376
9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2377
9
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2378
10
             uv_fs_mkdtemp, *tmpl);
2379

10
    FS_SYNC_TRACE_END(mkdtemp);
2380
10
    const char* path = req_wrap_sync.req.path;
2381
4
2382
2
    Local<Value> error;
2383
1
    MaybeLocal<Value> rc =
2384
13
        StringBytes::Encode(isolate, path, encoding, &error);
2385
10
    if (rc.IsEmpty()) {
2386
      Local<Object> ctx = args[3].As<Object>();
2387
1
      ctx->Set(env->context(), env->error_string(), error).Check();
2388
      return;
2389
    }
2390
18
    args.GetReturnValue().Set(rc.ToLocalChecked());
2391
  }
2392
}
2393
2394
22
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2395
22
  tracker->TrackField("stats_field_array", stats_field_array);
2396
22
  tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2397
22
  tracker->TrackField("file_handle_read_wrap_freelist",
2398
22
                      file_handle_read_wrap_freelist);
2399
22
}
2400
2401
5230
BindingData::BindingData(Environment* env, v8::Local<v8::Object> wrap)
2402
    : SnapshotableObject(env, wrap, type_int),
2403
      stats_field_array(env->isolate(), kFsStatsBufferLength),
2404
5230
      stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {
2405
10460
  wrap->Set(env->context(),
2406
            FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"),
2407
26150
            stats_field_array.GetJSArray())
2408
      .Check();
2409
2410
10460
  wrap->Set(env->context(),
2411
            FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"),
2412
26150
            stats_field_bigint_array.GetJSArray())
2413
      .Check();
2414
5230
}
2415
2416
4771
void BindingData::Deserialize(Local<Context> context,
2417
                              Local<Object> holder,
2418
                              int index,
2419
                              InternalFieldInfo* info) {
2420
  DCHECK_EQ(index, BaseObject::kSlot);
2421
9542
  HandleScope scope(context->GetIsolate());
2422
4771
  Environment* env = Environment::GetCurrent(context);
2423
4771
  BindingData* binding = env->AddBindingData<BindingData>(context, holder);
2424
4771
  CHECK_NOT_NULL(binding);
2425
4771
}
2426
2427
8
void BindingData::PrepareForSerialization(Local<Context> context,
2428
                                          v8::SnapshotCreator* creator) {
2429
8
  CHECK(file_handle_read_wrap_freelist.empty());
2430
  // We'll just re-initialize the buffers in the constructor since their
2431
  // contents can be thrown away once consumed in the previous call.
2432
8
  stats_field_array.Release();
2433
8
  stats_field_bigint_array.Release();
2434
8
}
2435
2436
8
InternalFieldInfo* BindingData::Serialize(int index) {
2437
  DCHECK_EQ(index, BaseObject::kSlot);
2438
8
  InternalFieldInfo* info = InternalFieldInfo::New(type());
2439
8
  return info;
2440
}
2441
2442
// TODO(addaleax): Remove once we're on C++17.
2443
constexpr FastStringKey BindingData::type_name;
2444
2445
459
void Initialize(Local<Object> target,
2446
                Local<Value> unused,
2447
                Local<Context> context,
2448
                void* priv) {
2449
459
  Environment* env = Environment::GetCurrent(context);
2450
459
  Isolate* isolate = env->isolate();
2451
  BindingData* const binding_data =
2452
459
      env->AddBindingData<BindingData>(context, target);
2453
459
  if (binding_data == nullptr) return;
2454
2455
459
  env->SetMethod(target, "access", Access);
2456
459
  env->SetMethod(target, "close", Close);
2457
459
  env->SetMethod(target, "open", Open);
2458
459
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2459
459
  env->SetMethod(target, "read", Read);
2460
459
  env->SetMethod(target, "readBuffers", ReadBuffers);
2461
459
  env->SetMethod(target, "fdatasync", Fdatasync);
2462
459
  env->SetMethod(target, "fsync", Fsync);
2463
459
  env->SetMethod(target, "rename", Rename);
2464
459
  env->SetMethod(target, "ftruncate", FTruncate);
2465
459
  env->SetMethod(target, "rmdir", RMDir);
2466
459
  env->SetMethod(target, "mkdir", MKDir);
2467
459
  env->SetMethod(target, "readdir", ReadDir);
2468
459
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2469
459
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2470
459
  env->SetMethod(target, "stat", Stat);
2471
459
  env->SetMethod(target, "lstat", LStat);
2472
459
  env->SetMethod(target, "fstat", FStat);
2473
459
  env->SetMethod(target, "link", Link);
2474
459
  env->SetMethod(target, "symlink", Symlink);
2475
459
  env->SetMethod(target, "readlink", ReadLink);
2476
459
  env->SetMethod(target, "unlink", Unlink);
2477
459
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2478
459
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2479
459
  env->SetMethod(target, "writeString", WriteString);
2480
459
  env->SetMethod(target, "realpath", RealPath);
2481
459
  env->SetMethod(target, "copyFile", CopyFile);
2482
2483
459
  env->SetMethod(target, "chmod", Chmod);
2484
459
  env->SetMethod(target, "fchmod", FChmod);
2485
2486
459
  env->SetMethod(target, "chown", Chown);
2487
459
  env->SetMethod(target, "fchown", FChown);
2488
459
  env->SetMethod(target, "lchown", LChown);
2489
2490
459
  env->SetMethod(target, "utimes", UTimes);
2491
459
  env->SetMethod(target, "futimes", FUTimes);
2492
459
  env->SetMethod(target, "lutimes", LUTimes);
2493
2494
459
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2495
2496
  target
2497
918
      ->Set(context,
2498
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2499
            Integer::New(
2500
                isolate,
2501
1836
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2502
      .Check();
2503
2504
459
  StatWatcher::Initialize(env, target);
2505
2506
  // Create FunctionTemplate for FSReqCallback
2507
459
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2508
1377
  fst->InstanceTemplate()->SetInternalFieldCount(
2509
459
      FSReqBase::kInternalFieldCount);
2510
918
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2511
459
  env->SetConstructorFunction(target, "FSReqCallback", fst);
2512
2513
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2514
  // to do anything in the constructor, so we only store the instance template.
2515
459
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2516
1377
  fh_rw->InstanceTemplate()->SetInternalFieldCount(
2517
459
      FSReqBase::kInternalFieldCount);
2518
918
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2519
  Local<String> fhWrapString =
2520
459
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2521
459
  fh_rw->SetClassName(fhWrapString);
2522
459
  env->set_filehandlereadwrap_template(
2523
459
      fst->InstanceTemplate());
2524
2525
  // Create Function Template for FSReqPromise
2526
459
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2527
918
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2528
  Local<String> promiseString =
2529
459
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2530
459
  fpt->SetClassName(promiseString);
2531
459
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2532
459
  fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2533
459
  env->set_fsreqpromise_constructor_template(fpo);
2534
2535
  // Create FunctionTemplate for FileHandle
2536
459
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2537
918
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2538
459
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2539
459
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2540
459
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2541
459
  fdt->SetInternalFieldCount(StreamBase::kInternalFieldCount);
2542
459
  StreamBase::AddMethods(env, fd);
2543
459
  env->SetConstructorFunction(target, "FileHandle", fd);
2544
459
  env->set_fd_constructor_template(fdt);
2545
2546
  // Create FunctionTemplate for FileHandle::CloseReq
2547
459
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2548
918
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2549
459
                        "FileHandleCloseReq"));
2550
918
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2551
459
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2552
459
  fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2553
459
  env->set_fdclose_constructor_template(fdcloset);
2554
2555
  Local<Symbol> use_promises_symbol =
2556
    Symbol::New(isolate,
2557
459
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2558
459
  env->set_fs_use_promises_symbol(use_promises_symbol);
2559
918
  target->Set(context,
2560
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2561
1377
              use_promises_symbol).Check();
2562
}
2563
2564
3802
BindingData* FSReqBase::binding_data() {
2565
3802
  return binding_data_.get();
2566
}
2567
2568
4779
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2569
4779
  registry->Register(Access);
2570
4779
  StatWatcher::RegisterExternalReferences(registry);
2571
2572
4779
  registry->Register(Close);
2573
4779
  registry->Register(Open);
2574
4779
  registry->Register(OpenFileHandle);
2575
4779
  registry->Register(Read);
2576
4779
  registry->Register(ReadBuffers);
2577
4779
  registry->Register(Fdatasync);
2578
4779
  registry->Register(Fsync);
2579
4779
  registry->Register(Rename);
2580
4779
  registry->Register(FTruncate);
2581
4779
  registry->Register(RMDir);
2582
4779
  registry->Register(MKDir);
2583
4779
  registry->Register(ReadDir);
2584
4779
  registry->Register(InternalModuleReadJSON);
2585
4779
  registry->Register(InternalModuleStat);
2586
4779
  registry->Register(Stat);
2587
4779
  registry->Register(LStat);
2588
4779
  registry->Register(FStat);
2589
4779
  registry->Register(Link);
2590
4779
  registry->Register(Symlink);
2591
4779
  registry->Register(ReadLink);
2592
4779
  registry->Register(Unlink);
2593
4779
  registry->Register(WriteBuffer);
2594
4779
  registry->Register(WriteBuffers);
2595
4779
  registry->Register(WriteString);
2596
4779
  registry->Register(RealPath);
2597
4779
  registry->Register(CopyFile);
2598
2599
4779
  registry->Register(Chmod);
2600
4779
  registry->Register(FChmod);
2601
2602
4779
  registry->Register(Chown);
2603
4779
  registry->Register(FChown);
2604
4779
  registry->Register(LChown);
2605
2606
4779
  registry->Register(UTimes);
2607
4779
  registry->Register(FUTimes);
2608
4779
  registry->Register(LUTimes);
2609
2610
4779
  registry->Register(Mkdtemp);
2611
4779
  registry->Register(NewFSReqCallback);
2612
2613
4779
  registry->Register(FileHandle::New);
2614
4779
  registry->Register(FileHandle::Close);
2615
4779
  registry->Register(FileHandle::ReleaseFD);
2616
4779
  StreamBase::RegisterExternalReferences(registry);
2617
4779
}
2618
2619
}  // namespace fs
2620
2621
}  // end namespace node
2622
2623
4837
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2624

19314
NODE_MODULE_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)