GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.cc Lines: 1438 1517 94.8 %
Date: 2022-08-14 04:19:53 Branches: 797 1248 63.9 %

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
11
std::string Basename(const std::string& str, const std::string& extension) {
88
  // Remove everything leading up to and including the final path separator.
89
11
  std::string::size_type pos = str.find_last_of(kPathSeparator);
90
91
  // Starting index for the resulting string
92
11
  std::size_t start_pos = 0;
93
  // String size to return
94
11
  std::size_t str_size = str.size();
95
11
  if (pos != std::string::npos) {
96
11
    start_pos = pos + 1;
97
11
    str_size -= start_pos;
98
  }
99
100
  // Strip away the extension, if any.
101

22
  if (str_size >= extension.size() &&
102
11
      str.compare(str.size() - extension.size(),
103
        extension.size(), extension) == 0) {
104
    str_size -= extension.size();
105
  }
106
107
11
  return str.substr(start_pos, str_size);
108
}
109
110
217515
inline int64_t GetOffset(Local<Value> value) {
111
218616
  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
1328
FileHandle::FileHandle(BindingData* binding_data,
149
1328
                       Local<Object> obj, int fd)
150
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
151
      StreamBase(env()),
152
      fd_(fd),
153
1328
      binding_data_(binding_data) {
154
1328
  MakeWeak();
155
1328
  StreamBase::AttachToObject(GetObject());
156
1328
}
157
158
1328
FileHandle* FileHandle::New(BindingData* binding_data,
159
                            int fd, Local<Object> obj) {
160
1328
  Environment* env = binding_data->env();
161
2641
  if (obj.IsEmpty() && !env->fd_constructor_template()
162
2641
                            ->NewInstance(env->context())
163
1313
                            .ToLocal(&obj)) {
164
    return nullptr;
165
  }
166
1328
  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
15
  CHECK(args[0]->IsInt32());
174
175
  FileHandle* handle =
176
30
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
177
15
  if (handle == nullptr) return;
178
30
  if (args[1]->IsNumber())
179
30
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
180
15
  if (args[2]->IsNumber())
181
30
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
182
}
183
184
5144
FileHandle::~FileHandle() {
185
2572
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
186
2572
  Close();           // Close synchronously and emit warning
187
2572
  CHECK(closed_);    // We have to be closed at the point
188
5144
}
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
6
  return ret;
211
}
212
213
6
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
214
215
24
FileHandle::TransferData::~TransferData() {
216
12
  if (fd_ > 0) {
217
    uv_fs_t close_req;
218
8
    CHECK_NE(fd_, -1);
219
8
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
220
8
    uv_fs_req_cleanup(&close_req);
221
  }
222
24
}
223
224
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
225
    Environment* env,
226
    v8::Local<v8::Context> context,
227
    std::unique_ptr<worker::TransferData> self) {
228
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
229
2
  if (bd == nullptr) return {};
230
231
2
  int fd = fd_;
232
2
  fd_ = -1;
233
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
234
}
235
236
// Close the file descriptor if it hasn't already been closed. A process
237
// warning will be emitted using a SetImmediate to avoid calling back to
238
// JS during GC. If closing the fd fails at this point, a fatal exception
239
// will crash the process immediately.
240
1286
inline void FileHandle::Close() {
241

1286
  if (closed_ || closing_) return;
242
  uv_fs_t req;
243
20
  CHECK_NE(fd_, -1);
244
20
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
245
20
  uv_fs_req_cleanup(&req);
246
247
  struct err_detail { int ret; int fd; };
248
249
20
  err_detail detail { ret, fd_ };
250
251
20
  AfterClose();
252
253
20
  if (ret < 0) {
254
    // Do not unref this
255
    env()->SetImmediate([detail](Environment* env) {
256
      char msg[70];
257
      snprintf(msg, arraysize(msg),
258
              "Closing file descriptor %d on garbage collection failed",
259
              detail.fd);
260
      // This exception will end up being fatal for the process because
261
      // it is being thrown from within the SetImmediate handler and
262
      // there is no JS stack to bubble it to. In other words, tearing
263
      // down the process is the only reasonable thing we can do here.
264
      HandleScope handle_scope(env->isolate());
265
      env->ThrowUVException(detail.ret, "close", msg);
266
    });
267
    return;
268
  }
269
270
  // If the close was successful, we still want to emit a process warning
271
  // to notify that the file descriptor was gc'd. We want to be noisy about
272
  // this because not explicitly closing the FileHandle is a bug.
273
274
20
  env()->SetImmediate([detail](Environment* env) {
275
    ProcessEmitWarning(env,
276
                       "Closing file descriptor %d on garbage collection",
277
4
                       detail.fd);
278
4
    if (env->filehandle_close_warning()) {
279
3
      env->set_filehandle_close_warning(false);
280
3
      USE(ProcessEmitDeprecationWarning(
281
          env,
282
          "Closing a FileHandle object on garbage collection is deprecated. "
283
          "Please close FileHandle objects explicitly using "
284
          "FileHandle.prototype.close(). In the future, an error will be "
285
          "thrown if a file descriptor is closed during garbage collection.",
286
3
          "DEP0137"));
287
    }
288
4
  }, CallbackFlags::kUnrefed);
289
}
290
291
1291
void FileHandle::CloseReq::Resolve() {
292
1291
  Isolate* isolate = env()->isolate();
293
2551
  HandleScope scope(isolate);
294
1291
  Context::Scope context_scope(env()->context());
295
1291
  InternalCallbackScope callback_scope(this);
296
2582
  Local<Promise> promise = promise_.Get(isolate);
297
1291
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
298
3873
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
299
1260
}
300
301
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
302
1
  Isolate* isolate = env()->isolate();
303
2
  HandleScope scope(isolate);
304
1
  Context::Scope context_scope(env()->context());
305
1
  InternalCallbackScope callback_scope(this);
306
2
  Local<Promise> promise = promise_.Get(isolate);
307
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
308
2
  resolver->Reject(env()->context(), reason).Check();
309
1
}
310
311
1292
FileHandle* FileHandle::CloseReq::file_handle() {
312
1292
  Isolate* isolate = env()->isolate();
313
1292
  HandleScope scope(isolate);
314
2584
  Local<Value> val = ref_.Get(isolate);
315
1292
  Local<Object> obj = val.As<Object>();
316
1292
  return Unwrap<FileHandle>(obj);
317
}
318
319
1292
FileHandle::CloseReq::CloseReq(Environment* env,
320
                               Local<Object> obj,
321
                               Local<Promise> promise,
322
1292
                               Local<Value> ref)
323
1292
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
324
1292
  promise_.Reset(env->isolate(), promise);
325
1292
  ref_.Reset(env->isolate(), ref);
326
1292
}
327
328
10088
FileHandle::CloseReq::~CloseReq() {
329
2522
  uv_fs_req_cleanup(req());
330
2522
  promise_.Reset();
331
2522
  ref_.Reset();
332
5044
}
333
334
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
335
  tracker->TrackField("promise", promise_);
336
  tracker->TrackField("ref", ref_);
337
}
338
339
340
341
// Closes this FileHandle asynchronously and returns a Promise that will be
342
// resolved when the callback is invoked, or rejects with a UVException if
343
// there was a problem closing the fd. This is the preferred mechanism for
344
// closing the FD object even tho the object will attempt to close
345
// automatically on gc.
346
1292
MaybeLocal<Promise> FileHandle::ClosePromise() {
347
1292
  Isolate* isolate = env()->isolate();
348
1292
  EscapableHandleScope scope(isolate);
349
1292
  Local<Context> context = env()->context();
350
351
  Local<Value> close_resolver =
352
3876
      object()->GetInternalField(FileHandle::kClosingPromiseSlot);
353

3876
  if (!close_resolver.IsEmpty() && !close_resolver->IsUndefined()) {
354
    CHECK(close_resolver->IsPromise());
355
    return close_resolver.As<Promise>();
356
  }
357
358
1292
  CHECK(!closed_);
359
1292
  CHECK(!closing_);
360
1292
  CHECK(!reading_);
361
362
1292
  auto maybe_resolver = Promise::Resolver::New(context);
363
1292
  CHECK(!maybe_resolver.IsEmpty());
364
1292
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
365
1292
  Local<Promise> promise = resolver.As<Promise>();
366
367
  Local<Object> close_req_obj;
368
1292
  if (!env()->fdclose_constructor_template()
369
2584
          ->NewInstance(env()->context()).ToLocal(&close_req_obj)) {
370
    return MaybeLocal<Promise>();
371
  }
372
1292
  closing_ = true;
373
2584
  object()->SetInternalField(FileHandle::kClosingPromiseSlot, promise);
374
375
2584
  CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
376
2584
  auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
377
1292
    std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
378
1292
    CHECK_NOT_NULL(close);
379
1292
    close->file_handle()->AfterClose();
380
1292
    if (!close->env()->can_call_into_js()) return;
381
1292
    Isolate* isolate = close->env()->isolate();
382
1292
    if (req->result < 0) {
383
2
      HandleScope handle_scope(isolate);
384
2
      close->Reject(
385
1
          UVException(isolate, static_cast<int>(req->result), "close"));
386
    } else {
387
1291
      close->Resolve();
388
    }
389
  }};
390
1292
  CHECK_NE(fd_, -1);
391
1292
  int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
392
1292
  if (ret < 0) {
393
    req->Reject(UVException(isolate, ret, "close"));
394
    delete req;
395
  }
396
397
1292
  return scope.Escape(promise);
398
}
399
400
1292
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
401
  FileHandle* fd;
402
1292
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
403
  Local<Promise> ret;
404
2584
  if (!fd->ClosePromise().ToLocal(&ret)) return;
405
2584
  args.GetReturnValue().Set(ret);
406
}
407
408
409
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
410
  FileHandle* fd;
411
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
412
  // Just act as if this FileHandle has been closed.
413
8
  fd->AfterClose();
414
}
415
416
417
1320
void FileHandle::AfterClose() {
418
1320
  closing_ = false;
419
1320
  closed_ = true;
420
1320
  fd_ = -1;
421

1320
  if (reading_ && !persistent().IsEmpty())
422
    EmitRead(UV_EOF);
423
1320
}
424
425
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
426
  tracker->TrackField("buffer", buffer_);
427
  tracker->TrackField("file_handle", this->file_handle_);
428
}
429
430
18
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
431
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
432
18
    file_handle_(handle) {}
433
434
227
int FileHandle::ReadStart() {
435

227
  if (!IsAlive() || IsClosing())
436
    return UV_EOF;
437
438
227
  reading_ = true;
439
440
227
  if (current_read_)
441
9
    return 0;
442
443
436
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
444
445
218
  if (read_length_ == 0) {
446
5
    EmitRead(UV_EOF);
447
5
    return 0;
448
  }
449
450
  {
451
    // Create a new FileHandleReadWrap or re-use one.
452
    // Either way, we need these two scopes for AsyncReset() or otherwise
453
    // for creating the new instance.
454
213
    HandleScope handle_scope(env()->isolate());
455
213
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
456
457
213
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
458
213
    if (freelist.size() > 0) {
459
195
      read_wrap = std::move(freelist.back());
460
195
      freelist.pop_back();
461
      // Use a fresh async resource.
462
      // Lifetime is ensured via AsyncWrap::resource_.
463
195
      Local<Object> resource = Object::New(env()->isolate());
464
195
      USE(resource->Set(
465
585
          env()->context(), env()->handle_string(), read_wrap->object()));
466
195
      read_wrap->AsyncReset(resource);
467
195
      read_wrap->file_handle_ = this;
468
    } else {
469
      Local<Object> wrap_obj;
470
36
      if (!env()
471
18
               ->filehandlereadwrap_template()
472
18
               ->NewInstance(env()->context())
473
18
               .ToLocal(&wrap_obj)) {
474
        return UV_EBUSY;
475
      }
476
18
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
477
    }
478
  }
479
213
  int64_t recommended_read = 65536;
480

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

212
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
523
        result = handle->read_length_;
524
525
      // If we read data and we have an expected length, decrease it by
526
      // how much we have read.
527
212
      if (handle->read_length_ >= 0)
528
9
        handle->read_length_ -= result;
529
530
      // If we have an offset, increase it by how much we have read.
531
212
      if (handle->read_offset_ >= 0)
532
204
        handle->read_offset_ += result;
533
    }
534
535
    // Reading 0 bytes from a file always means EOF, or that we reached
536
    // the end of the requested range.
537
213
    if (result == 0)
538
10
      result = UV_EOF;
539
540
213
    handle->EmitRead(result, buffer);
541
542
    // Start over, if EmitRead() didn’t tell us to stop.
543
213
    if (handle->reading_)
544
3
      handle->ReadStart();
545
213
  }});
546
547
213
  return 0;
548
}
549
550
230
int FileHandle::ReadStop() {
551
230
  reading_ = false;
552
230
  return 0;
553
}
554
555
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
556
557
3
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
558
3
  return new FileHandleCloseWrap(this, object);
559
}
560
561
3
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
562

3
  if (closing_ || closed_) {
563
3
    req_wrap->Done(0);
564
3
    return 1;
565
  }
566
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
567
  closing_ = true;
568
  CHECK_NE(fd_, -1);
569
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
570
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
571
        FileHandleCloseWrap::from_req(req));
572
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
573
    handle->AfterClose();
574
575
    int result = static_cast<int>(req->result);
576
    uv_fs_req_cleanup(req);
577
    wrap->Done(result);
578
  }});
579
580
  return 0;
581
}
582
583
584
4806
void FSReqCallback::Reject(Local<Value> reject) {
585
4806
  MakeCallback(env()->oncomplete_string(), 1, &reject);
586
4804
}
587
588
2519
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
589
2519
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
590
2519
}
591
592
47013
void FSReqCallback::Resolve(Local<Value> value) {
593
  Local<Value> argv[2] {
594
    Null(env()->isolate()),
595
    value
596
47013
  };
597
  MakeCallback(env()->oncomplete_string(),
598
86950
               value->IsUndefined() ? 1 : arraysize(argv),
599
133963
               argv);
600
47006
}
601
602
51819
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
603
51819
  args.GetReturnValue().SetUndefined();
604
51819
}
605
606
51819
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
607
51819
  CHECK(args.IsConstructCall());
608
51819
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
609
103638
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
610
51819
}
611
612
57021
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
613
    : wrap_(wrap),
614
      req_(req),
615
      handle_scope_(wrap->env()->isolate()),
616
57021
      context_scope_(wrap->env()->context()) {
617
57021
  CHECK_EQ(wrap_->req(), req);
618
57021
}
619
620
114024
FSReqAfterScope::~FSReqAfterScope() {
621
57012
  Clear();
622
57012
}
623
624
62368
void FSReqAfterScope::Clear() {
625
62368
  if (!wrap_) return;
626
627
57014
  uv_fs_req_cleanup(wrap_->req());
628
57014
  wrap_->Detach();
629
57014
  wrap_.reset();
630
}
631
632
// TODO(joyeecheung): create a normal context object, and
633
// construct the actual errors in the JS land using the context.
634
// The context should include fds for some fs APIs, currently they are
635
// missing in the error messages. The path, dest, syscall, fd, .etc
636
// can be put into the context before the binding is even invoked,
637
// the only information that has to come from the C++ layer is the
638
// error number (and possibly the syscall for abstraction),
639
// which is also why the errors should have been constructed
640
// in JS for more flexibility.
641
5212
void FSReqAfterScope::Reject(uv_fs_t* req) {
642
10422
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
643
5212
  Local<Value> exception = UVException(wrap_->env()->isolate(),
644
5212
                                       static_cast<int>(req->result),
645
                                       wrap_->syscall(),
646
                                       nullptr,
647
                                       req->path,
648
5212
                                       wrap_->data());
649
5212
  Clear();
650
5212
  wrap->Reject(exception);
651
5210
}
652
653
57021
bool FSReqAfterScope::Proceed() {
654
57021
  if (!wrap_->env()->can_call_into_js()) {
655
144
    return false;
656
  }
657
658
56877
  if (req_->result < 0) {
659
5212
    Reject(req_);
660
5210
    return false;
661
  }
662
51665
  return true;
663
}
664
665
7514
void AfterNoArgs(uv_fs_t* req) {
666
7514
  FSReqBase* req_wrap = FSReqBase::from_req(req);
667
15023
  FSReqAfterScope after(req_wrap, req);
668
669
7514
  if (after.Proceed())
670
14490
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
671
7509
}
672
673
8730
void AfterStat(uv_fs_t* req) {
674
8730
  FSReqBase* req_wrap = FSReqBase::from_req(req);
675
17460
  FSReqAfterScope after(req_wrap, req);
676
677
8730
  if (after.Proceed()) {
678
4121
    req_wrap->ResolveStat(&req->statbuf);
679
  }
680
8730
}
681
682
38226
void AfterInteger(uv_fs_t* req) {
683
38226
  FSReqBase* req_wrap = FSReqBase::from_req(req);
684
76449
  FSReqAfterScope after(req_wrap, req);
685
686
38226
  int result = static_cast<int>(req->result);
687

38226
  if (result >= 0 && req_wrap->is_plain_open())
688
5450
    req_wrap->env()->AddUnmanagedFd(result);
689
690
38226
  if (after.Proceed())
691
76094
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
692
38223
}
693
694
1588
void AfterOpenFileHandle(uv_fs_t* req) {
695
1588
  FSReqBase* req_wrap = FSReqBase::from_req(req);
696
1588
  FSReqAfterScope after(req_wrap, req);
697
698
1588
  if (after.Proceed()) {
699
1310
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
700
1310
                                     static_cast<int>(req->result));
701
1310
    if (fd == nullptr) return;
702
2620
    req_wrap->Resolve(fd->object());
703
  }
704
}
705
706
// Reverse the logic applied by path.toNamespacedPath() to create a
707
// namespace-prefixed path.
708
505
void FromNamespacedPath(std::string* path) {
709
#ifdef _WIN32
710
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
711
    *path = path->substr(8);
712
    path->insert(0, "\\\\");
713
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
714
    *path = path->substr(4);
715
  }
716
#endif
717
505
}
718
719
360
void AfterMkdirp(uv_fs_t* req) {
720
360
  FSReqBase* req_wrap = FSReqBase::from_req(req);
721
360
  FSReqAfterScope after(req_wrap, req);
722
360
  if (after.Proceed()) {
723
708
    std::string first_path(req_wrap->continuation_data()->first_path());
724
354
    if (first_path.empty())
725
252
      return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
726
228
    FromNamespacedPath(&first_path);
727
    Local<Value> path;
728
    Local<Value> error;
729
228
    if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
730
                             req_wrap->encoding(),
731
456
                             &error).ToLocal(&path)) {
732
      return req_wrap->Reject(error);
733
    }
734
228
    return req_wrap->Resolve(path);
735
  }
736
}
737
738
6
void AfterStringPath(uv_fs_t* req) {
739
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
740
12
  FSReqAfterScope after(req_wrap, req);
741
742
  MaybeLocal<Value> link;
743
  Local<Value> error;
744
745
6
  if (after.Proceed()) {
746
    link = StringBytes::Encode(req_wrap->env()->isolate(),
747
                               req->path,
748
                               req_wrap->encoding(),
749
5
                               &error);
750
5
    if (link.IsEmpty())
751
      req_wrap->Reject(error);
752
    else
753
10
      req_wrap->Resolve(link.ToLocalChecked());
754
  }
755
6
}
756
757
64
void AfterStringPtr(uv_fs_t* req) {
758
64
  FSReqBase* req_wrap = FSReqBase::from_req(req);
759
127
  FSReqAfterScope after(req_wrap, req);
760
761
  MaybeLocal<Value> link;
762
  Local<Value> error;
763
764
64
  if (after.Proceed()) {
765
    link = StringBytes::Encode(req_wrap->env()->isolate(),
766
58
                               static_cast<const char*>(req->ptr),
767
                               req_wrap->encoding(),
768
58
                               &error);
769
58
    if (link.IsEmpty())
770
      req_wrap->Reject(error);
771
    else
772
116
      req_wrap->Resolve(link.ToLocalChecked());
773
  }
774
63
}
775
776
222
void AfterScanDir(uv_fs_t* req) {
777
222
  FSReqBase* req_wrap = FSReqBase::from_req(req);
778
222
  FSReqAfterScope after(req_wrap, req);
779
780
222
  if (!after.Proceed()) {
781
7
    return;
782
  }
783
784
215
  Environment* env = req_wrap->env();
785
215
  Isolate* isolate = env->isolate();
786
  Local<Value> error;
787
  int r;
788
789
215
  std::vector<Local<Value>> name_v;
790
215
  std::vector<Local<Value>> type_v;
791
792
215
  const bool with_file_types = req_wrap->with_file_types();
793
794
  for (;;) {
795
    uv_dirent_t ent;
796
797
7844
    r = uv_fs_scandir_next(req, &ent);
798
7844
    if (r == UV_EOF)
799
215
      break;
800
7629
    if (r != 0) {
801
      return req_wrap->Reject(
802
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
803
    }
804
805
    Local<Value> filename;
806
7629
    if (!StringBytes::Encode(isolate, ent.name, req_wrap->encoding(), &error)
807
7629
             .ToLocal(&filename)) {
808
      return req_wrap->Reject(error);
809
    }
810
7629
    name_v.push_back(filename);
811
812
7629
    if (with_file_types) type_v.emplace_back(Integer::New(isolate, ent.type));
813
7629
  }
814
815
215
  if (with_file_types) {
816
    Local<Value> result[] = {Array::New(isolate, name_v.data(), name_v.size()),
817
246
                             Array::New(isolate, type_v.data(), type_v.size())};
818
246
    req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
819
  } else {
820
184
    req_wrap->Resolve(Array::New(isolate, name_v.data(), name_v.size()));
821
  }
822
}
823
824
4062
void Access(const FunctionCallbackInfo<Value>& args) {
825
4062
  Environment* env = Environment::GetCurrent(args);
826
4062
  Isolate* isolate = env->isolate();
827
8124
  HandleScope scope(isolate);
828
829
4062
  const int argc = args.Length();
830
4062
  CHECK_GE(argc, 2);
831
832
4062
  CHECK(args[1]->IsInt32());
833
8124
  int mode = args[1].As<Int32>()->Value();
834
835
8124
  BufferValue path(isolate, args[0]);
836
4062
  CHECK_NOT_NULL(*path);
837
838
4062
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
839
4062
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
840
44
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
841
              uv_fs_access, *path, mode);
842
  } else {  // access(path, mode, undefined, ctx)
843
4018
    CHECK_EQ(argc, 4);
844
8036
    FSReqWrapSync req_wrap_sync;
845

4020
    FS_SYNC_TRACE_BEGIN(access);
846
8036
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
847

4020
    FS_SYNC_TRACE_END(access);
848
  }
849
4062
}
850
851
852
61448
void Close(const FunctionCallbackInfo<Value>& args) {
853
61448
  Environment* env = Environment::GetCurrent(args);
854
855
61448
  const int argc = args.Length();
856
61448
  CHECK_GE(argc, 2);
857
858
61448
  CHECK(args[0]->IsInt32());
859
122896
  int fd = args[0].As<Int32>()->Value();
860
61448
  env->RemoveUnmanagedFd(fd);
861
862
61448
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
863
61448
  if (req_wrap_async != nullptr) {  // close(fd, req)
864
5363
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
865
              uv_fs_close, fd);
866
  } else {  // close(fd, undefined, ctx)
867
56085
    CHECK_EQ(argc, 3);
868
112170
    FSReqWrapSync req_wrap_sync;
869

56142
    FS_SYNC_TRACE_BEGIN(close);
870
56085
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
871

56142
    FS_SYNC_TRACE_END(close);
872
  }
873
61448
}
874
875
876
// Used to speed up module loading. Returns an array [string, boolean]
877
56097
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
878
56097
  Environment* env = Environment::GetCurrent(args);
879
56097
  Isolate* isolate = env->isolate();
880
56097
  uv_loop_t* loop = env->event_loop();
881
882
112194
  CHECK(args[0]->IsString());
883
56097
  node::Utf8Value path(isolate, args[0]);
884
885
56097
  if (strlen(*path) != path.length()) {
886
3
    args.GetReturnValue().Set(Array::New(isolate));
887
3
    return;  // Contains a nul byte.
888
  }
889
  uv_fs_t open_req;
890
56094
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
891
56094
  uv_fs_req_cleanup(&open_req);
892
893
56094
  if (fd < 0) {
894
49900
    args.GetReturnValue().Set(Array::New(isolate));
895
49900
    return;
896
  }
897
898
6194
  auto defer_close = OnScopeLeave([fd, loop]() {
899
    uv_fs_t close_req;
900
6194
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
901
6194
    uv_fs_req_cleanup(&close_req);
902
6194
  });
903
904
6194
  const size_t kBlockSize = 32 << 10;
905
6194
  std::vector<char> chars;
906
6194
  int64_t offset = 0;
907
  ssize_t numchars;
908
  do {
909
6194
    const size_t start = chars.size();
910
6194
    chars.resize(start + kBlockSize);
911
912
    uv_buf_t buf;
913
6194
    buf.base = &chars[start];
914
6194
    buf.len = kBlockSize;
915
916
    uv_fs_t read_req;
917
6194
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
918
6194
    uv_fs_req_cleanup(&read_req);
919
920
6194
    if (numchars < 0) {
921
1
      args.GetReturnValue().Set(Array::New(isolate));
922
1
      return;
923
    }
924
6193
    offset += numchars;
925
6193
  } while (static_cast<size_t>(numchars) == kBlockSize);
926
927
6193
  size_t start = 0;
928

6193
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
929
1
    start = 3;  // Skip UTF-8 BOM.
930
  }
931
932
6193
  const size_t size = offset - start;
933
6193
  char* p = &chars[start];
934
6193
  char* pe = &chars[size];
935
  char* pos[2];
936
6193
  char** ppos = &pos[0];
937
938
98119
  while (p < pe) {
939
98103
    char c = *p++;
940

98103
    if (c == '\\' && p < pe && *p == '"') p++;
941
98103
    if (c != '"') continue;
942
14832
    *ppos++ = p;
943
14832
    if (ppos < &pos[2]) continue;
944
7416
    ppos = &pos[0];
945
946
7416
    char* s = &pos[0][0];
947
7416
    char* se = &pos[1][-1];  // Exclude quote.
948
7416
    size_t n = se - s;
949
950
7416
    if (n == 4) {
951
6169
      if (0 == memcmp(s, "main", 4)) break;
952
6130
      if (0 == memcmp(s, "name", 4)) break;
953
49
      if (0 == memcmp(s, "type", 4)) break;
954
1247
    } else if (n == 7) {
955
13
      if (0 == memcmp(s, "exports", 7)) break;
956
7
      if (0 == memcmp(s, "imports", 7)) break;
957
    }
958
  }
959
960
961
  Local<Value> return_value[] = {
962
6193
    String::NewFromUtf8(isolate,
963
6193
                        &chars[start],
964
                        v8::NewStringType::kNormal,
965
6193
                        size).ToLocalChecked(),
966
    Boolean::New(isolate, p < pe ? true : false)
967
18579
  };
968
12386
  args.GetReturnValue().Set(
969
    Array::New(isolate, return_value, arraysize(return_value)));
970
}
971
972
// Used to speed up module loading.  Returns 0 if the path refers to
973
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
974
// The speedup comes from not creating thousands of Stat and Error objects.
975
156642
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
976
156642
  Environment* env = Environment::GetCurrent(args);
977
978
313284
  CHECK(args[0]->IsString());
979
156642
  node::Utf8Value path(env->isolate(), args[0]);
980
981
  uv_fs_t req;
982
156642
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
983
156642
  if (rc == 0) {
984
73565
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
985
73565
    rc = !!(s->st_mode & S_IFDIR);
986
  }
987
156642
  uv_fs_req_cleanup(&req);
988
989
313284
  args.GetReturnValue().Set(rc);
990
156642
}
991
992
18131
static void Stat(const FunctionCallbackInfo<Value>& args) {
993
18131
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
994
18131
  Environment* env = binding_data->env();
995
996
18131
  const int argc = args.Length();
997
18131
  CHECK_GE(argc, 2);
998
999
18131
  BufferValue path(env->isolate(), args[0]);
1000
18131
  CHECK_NOT_NULL(*path);
1001
1002
18131
  bool use_bigint = args[1]->IsTrue();
1003
18131
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1004
18131
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1005
2693
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1006
              uv_fs_stat, *path);
1007
  } else {  // stat(path, use_bigint, undefined, ctx)
1008
15438
    CHECK_EQ(argc, 4);
1009
15438
    FSReqWrapSync req_wrap_sync;
1010

15440
    FS_SYNC_TRACE_BEGIN(stat);
1011
30876
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1012

15440
    FS_SYNC_TRACE_END(stat);
1013
15438
    if (err != 0) {
1014
705
      return;  // error info is in ctx
1015
    }
1016
1017
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1018
14733
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1019
29466
    args.GetReturnValue().Set(arr);
1020
  }
1021
}
1022
1023
112185
static void LStat(const FunctionCallbackInfo<Value>& args) {
1024
112185
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1025
112185
  Environment* env = binding_data->env();
1026
1027
112185
  const int argc = args.Length();
1028
112185
  CHECK_GE(argc, 3);
1029
1030
112185
  BufferValue path(env->isolate(), args[0]);
1031
112185
  CHECK_NOT_NULL(*path);
1032
1033
112185
  bool use_bigint = args[1]->IsTrue();
1034
112185
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1035
112185
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1036
4799
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1037
              uv_fs_lstat, *path);
1038
  } else {  // lstat(path, use_bigint, undefined, ctx)
1039
107386
    CHECK_EQ(argc, 4);
1040
107386
    FSReqWrapSync req_wrap_sync;
1041

107403
    FS_SYNC_TRACE_BEGIN(lstat);
1042
214772
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1043
                       *path);
1044

107403
    FS_SYNC_TRACE_END(lstat);
1045
107386
    if (err != 0) {
1046
456
      return;  // error info is in ctx
1047
    }
1048
1049
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1050
106930
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1051
213860
    args.GetReturnValue().Set(arr);
1052
  }
1053
}
1054
1055
51376
static void FStat(const FunctionCallbackInfo<Value>& args) {
1056
51376
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1057
51376
  Environment* env = binding_data->env();
1058
1059
51376
  const int argc = args.Length();
1060
51376
  CHECK_GE(argc, 2);
1061
1062
51376
  CHECK(args[0]->IsInt32());
1063
102752
  int fd = args[0].As<Int32>()->Value();
1064
1065
51376
  bool use_bigint = args[1]->IsTrue();
1066
51376
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1067
51376
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1068
1240
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1069
              uv_fs_fstat, fd);
1070
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1071
50136
    CHECK_EQ(argc, 4);
1072
50136
    FSReqWrapSync req_wrap_sync;
1073

50145
    FS_SYNC_TRACE_BEGIN(fstat);
1074
50136
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1075

50145
    FS_SYNC_TRACE_END(fstat);
1076
50136
    if (err != 0) {
1077
21
      return;  // error info is in ctx
1078
    }
1079
1080
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1081
50115
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1082
100230
    args.GetReturnValue().Set(arr);
1083
  }
1084
}
1085
1086
451
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1087
451
  Environment* env = Environment::GetCurrent(args);
1088
451
  Isolate* isolate = env->isolate();
1089
1090
451
  const int argc = args.Length();
1091
451
  CHECK_GE(argc, 4);
1092
1093
902
  BufferValue target(isolate, args[0]);
1094
451
  CHECK_NOT_NULL(*target);
1095
902
  BufferValue path(isolate, args[1]);
1096
451
  CHECK_NOT_NULL(*path);
1097
1098
451
  CHECK(args[2]->IsInt32());
1099
902
  int flags = args[2].As<Int32>()->Value();
1100
1101
451
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1102
451
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1103
119
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1104
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1105
  } else {  // symlink(target, path, flags, undefinec, ctx)
1106
332
    CHECK_EQ(argc, 5);
1107
664
    FSReqWrapSync req_wrap_sync;
1108

336
    FS_SYNC_TRACE_BEGIN(symlink);
1109
664
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1110
             uv_fs_symlink, *target, *path, flags);
1111

336
    FS_SYNC_TRACE_END(symlink);
1112
  }
1113
451
}
1114
1115
9
static void Link(const FunctionCallbackInfo<Value>& args) {
1116
9
  Environment* env = Environment::GetCurrent(args);
1117
9
  Isolate* isolate = env->isolate();
1118
1119
9
  const int argc = args.Length();
1120
9
  CHECK_GE(argc, 3);
1121
1122
18
  BufferValue src(isolate, args[0]);
1123
9
  CHECK_NOT_NULL(*src);
1124
1125
18
  BufferValue dest(isolate, args[1]);
1126
9
  CHECK_NOT_NULL(*dest);
1127
1128
9
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1129
9
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1130
4
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1131
                  AfterNoArgs, uv_fs_link, *src, *dest);
1132
  } else {  // link(src, dest)
1133
5
    CHECK_EQ(argc, 4);
1134
10
    FSReqWrapSync req_wrap_sync;
1135

11
    FS_SYNC_TRACE_BEGIN(link);
1136
10
    SyncCall(env, args[3], &req_wrap_sync, "link",
1137
             uv_fs_link, *src, *dest);
1138

11
    FS_SYNC_TRACE_END(link);
1139
  }
1140
9
}
1141
1142
109
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1143
109
  Environment* env = Environment::GetCurrent(args);
1144
109
  Isolate* isolate = env->isolate();
1145
1146
109
  const int argc = args.Length();
1147
109
  CHECK_GE(argc, 3);
1148
1149
109
  BufferValue path(isolate, args[0]);
1150
109
  CHECK_NOT_NULL(*path);
1151
1152
109
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1153
1154
109
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1155
109
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1156
42
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1157
              uv_fs_readlink, *path);
1158
  } else {
1159
67
    CHECK_EQ(argc, 4);
1160
67
    FSReqWrapSync req_wrap_sync;
1161

69
    FS_SYNC_TRACE_BEGIN(readlink);
1162
134
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1163
                       uv_fs_readlink, *path);
1164

69
    FS_SYNC_TRACE_END(readlink);
1165
67
    if (err < 0) {
1166
2
      return;  // syscall failed, no need to continue, error info is in ctx
1167
    }
1168
65
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1169
1170
    Local<Value> error;
1171
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1172
                                               link_path,
1173
                                               encoding,
1174
65
                                               &error);
1175
65
    if (rc.IsEmpty()) {
1176
      Local<Object> ctx = args[3].As<Object>();
1177
      ctx->Set(env->context(), env->error_string(), error).Check();
1178
      return;
1179
    }
1180
1181
130
    args.GetReturnValue().Set(rc.ToLocalChecked());
1182
  }
1183
}
1184
1185
6
static void Rename(const FunctionCallbackInfo<Value>& args) {
1186
6
  Environment* env = Environment::GetCurrent(args);
1187
6
  Isolate* isolate = env->isolate();
1188
1189
6
  const int argc = args.Length();
1190
6
  CHECK_GE(argc, 3);
1191
1192
12
  BufferValue old_path(isolate, args[0]);
1193
6
  CHECK_NOT_NULL(*old_path);
1194
12
  BufferValue new_path(isolate, args[1]);
1195
6
  CHECK_NOT_NULL(*new_path);
1196
1197
6
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1198
6
  if (req_wrap_async != nullptr) {
1199
3
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1200
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1201
                  *old_path, *new_path);
1202
  } else {
1203
3
    CHECK_EQ(argc, 4);
1204
6
    FSReqWrapSync req_wrap_sync;
1205

5
    FS_SYNC_TRACE_BEGIN(rename);
1206
6
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1207
             *old_path, *new_path);
1208

5
    FS_SYNC_TRACE_END(rename);
1209
  }
1210
6
}
1211
1212
69
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1213
69
  Environment* env = Environment::GetCurrent(args);
1214
1215
69
  const int argc = args.Length();
1216
69
  CHECK_GE(argc, 3);
1217
1218
69
  CHECK(args[0]->IsInt32());
1219
138
  const int fd = args[0].As<Int32>()->Value();
1220
1221
69
  CHECK(IsSafeJsInt(args[1]));
1222
138
  const int64_t len = args[1].As<Integer>()->Value();
1223
1224
69
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1225
69
  if (req_wrap_async != nullptr) {
1226
54
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1227
              uv_fs_ftruncate, fd, len);
1228
  } else {
1229
15
    CHECK_EQ(argc, 4);
1230
30
    FSReqWrapSync req_wrap_sync;
1231

17
    FS_SYNC_TRACE_BEGIN(ftruncate);
1232
15
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1233
             len);
1234

17
    FS_SYNC_TRACE_END(ftruncate);
1235
  }
1236
69
}
1237
1238
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1239
7
  Environment* env = Environment::GetCurrent(args);
1240
1241
7
  const int argc = args.Length();
1242
7
  CHECK_GE(argc, 2);
1243
1244
7
  CHECK(args[0]->IsInt32());
1245
14
  const int fd = args[0].As<Int32>()->Value();
1246
1247
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1248
7
  if (req_wrap_async != nullptr) {
1249
4
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1250
              uv_fs_fdatasync, fd);
1251
  } else {
1252
3
    CHECK_EQ(argc, 3);
1253
6
    FSReqWrapSync req_wrap_sync;
1254

5
    FS_SYNC_TRACE_BEGIN(fdatasync);
1255
3
    SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1256

5
    FS_SYNC_TRACE_END(fdatasync);
1257
  }
1258
7
}
1259
1260
21
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1261
21
  Environment* env = Environment::GetCurrent(args);
1262
1263
21
  const int argc = args.Length();
1264
21
  CHECK_GE(argc, 2);
1265
1266
21
  CHECK(args[0]->IsInt32());
1267
42
  const int fd = args[0].As<Int32>()->Value();
1268
1269
21
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1270
21
  if (req_wrap_async != nullptr) {
1271
4
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1272
              uv_fs_fsync, fd);
1273
  } else {
1274
17
    CHECK_EQ(argc, 3);
1275
34
    FSReqWrapSync req_wrap_sync;
1276

19
    FS_SYNC_TRACE_BEGIN(fsync);
1277
17
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1278

19
    FS_SYNC_TRACE_END(fsync);
1279
  }
1280
21
}
1281
1282
2682
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1283
2682
  Environment* env = Environment::GetCurrent(args);
1284
1285
2682
  const int argc = args.Length();
1286
2682
  CHECK_GE(argc, 2);
1287
1288
5364
  BufferValue path(env->isolate(), args[0]);
1289
2682
  CHECK_NOT_NULL(*path);
1290
1291
2682
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1292
2682
  if (req_wrap_async != nullptr) {
1293
1127
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1294
              uv_fs_unlink, *path);
1295
  } else {
1296
1555
    CHECK_EQ(argc, 3);
1297
3110
    FSReqWrapSync req_wrap_sync;
1298

1610
    FS_SYNC_TRACE_BEGIN(unlink);
1299
3110
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1300

1610
    FS_SYNC_TRACE_END(unlink);
1301
  }
1302
2682
}
1303
1304
1868
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1305
1868
  Environment* env = Environment::GetCurrent(args);
1306
1307
1868
  const int argc = args.Length();
1308
1868
  CHECK_GE(argc, 2);
1309
1310
3736
  BufferValue path(env->isolate(), args[0]);
1311
1868
  CHECK_NOT_NULL(*path);
1312
1313
1868
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1314
1868
  if (req_wrap_async != nullptr) {
1315
259
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1316
              uv_fs_rmdir, *path);
1317
  } else {  // rmdir(path, undefined, ctx)
1318
1609
    CHECK_EQ(argc, 3);
1319
3218
    FSReqWrapSync req_wrap_sync;
1320

1615
    FS_SYNC_TRACE_BEGIN(rmdir);
1321
3218
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1322
             uv_fs_rmdir, *path);
1323

1615
    FS_SYNC_TRACE_END(rmdir);
1324
  }
1325
1868
}
1326
1327
6263
int MKDirpSync(uv_loop_t* loop,
1328
               uv_fs_t* req,
1329
               const std::string& path,
1330
               int mode,
1331
               uv_fs_cb cb) {
1332
6263
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1333
1334
  // on the first iteration of algorithm, stash state information.
1335
6263
  if (req_wrap->continuation_data() == nullptr) {
1336
6263
    req_wrap->set_continuation_data(
1337
12526
        std::make_unique<FSContinuationData>(req, mode, cb));
1338
6263
    req_wrap->continuation_data()->PushPath(std::move(path));
1339
  }
1340
1341
12384
  while (req_wrap->continuation_data()->paths().size() > 0) {
1342
6413
    std::string next_path = req_wrap->continuation_data()->PopPath();
1343
6413
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1344
    while (true) {
1345

6414
      switch (err) {
1346
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1347
        // ~FSReqWrapSync():
1348
362
        case 0:
1349
362
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1350
362
          if (req_wrap->continuation_data()->paths().size() == 0) {
1351
288
            return 0;
1352
          }
1353
74
          break;
1354
2
        case UV_EACCES:
1355
        case UV_ENOSPC:
1356
        case UV_ENOTDIR:
1357
        case UV_EPERM: {
1358
2
          return err;
1359
        }
1360
76
        case UV_ENOENT: {
1361
          std::string dirname = next_path.substr(0,
1362
76
                                        next_path.find_last_of(kPathSeparator));
1363
76
          if (dirname != next_path) {
1364
75
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1365
75
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1366
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1367
1
            err = UV_EEXIST;
1368
1
            continue;
1369
          }
1370
75
          break;
1371
        }
1372
5974
        default:
1373
5974
          uv_fs_req_cleanup(req);
1374
5974
          int orig_err = err;
1375
5974
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1376

5974
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1377
1
            uv_fs_req_cleanup(req);
1378

2
            if (orig_err == UV_EEXIST &&
1379
1
              req_wrap->continuation_data()->paths().size() > 0) {
1380
              return UV_ENOTDIR;
1381
            }
1382
1
            return UV_EEXIST;
1383
          }
1384
5973
          if (err < 0) return err;
1385
5972
          break;
1386
      }
1387
6121
      break;
1388
1
    }
1389
6121
    uv_fs_req_cleanup(req);
1390
  }
1391
1392
5971
  return 0;
1393
}
1394
1395
804
int MKDirpAsync(uv_loop_t* loop,
1396
                uv_fs_t* req,
1397
                const char* path,
1398
                int mode,
1399
                uv_fs_cb cb) {
1400
804
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1401
  // on the first iteration of algorithm, stash state information.
1402
804
  if (req_wrap->continuation_data() == nullptr) {
1403
360
    req_wrap->set_continuation_data(
1404
720
        std::make_unique<FSContinuationData>(req, mode, cb));
1405
360
    req_wrap->continuation_data()->PushPath(std::move(path));
1406
  }
1407
1408
  // on each iteration of algorithm, mkdir directory on top of stack.
1409
804
  std::string next_path = req_wrap->continuation_data()->PopPath();
1410
804
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1411
804
                        uv_fs_callback_t{[](uv_fs_t* req) {
1412
804
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1413
804
    Environment* env = req_wrap->env();
1414
804
    uv_loop_t* loop = env->event_loop();
1415
1608
    std::string path = req->path;
1416
804
    int err = static_cast<int>(req->result);
1417
1418
    while (true) {
1419

805
      switch (err) {
1420
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1421
        // FSReqAfterScope::~FSReqAfterScope()
1422
332
        case 0: {
1423
332
          if (req_wrap->continuation_data()->paths().size() == 0) {
1424
228
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1425
228
            req_wrap->continuation_data()->Done(0);
1426
          } else {
1427
104
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1428
104
            uv_fs_req_cleanup(req);
1429
104
            MKDirpAsync(loop, req, path.c_str(),
1430
                        req_wrap->continuation_data()->mode(), nullptr);
1431
          }
1432
332
          break;
1433
        }
1434
3
        case UV_EACCES:
1435
        case UV_ENOTDIR:
1436
        case UV_EPERM: {
1437
3
          req_wrap->continuation_data()->Done(err);
1438
3
          break;
1439
        }
1440
223
        case UV_ENOENT: {
1441
          std::string dirname = path.substr(0,
1442
223
                                            path.find_last_of(kPathSeparator));
1443
223
          if (dirname != path) {
1444
222
            req_wrap->continuation_data()->PushPath(std::move(path));
1445
222
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1446
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1447
1
            err = UV_EEXIST;
1448
1
            continue;
1449
          }
1450
222
          uv_fs_req_cleanup(req);
1451
222
          MKDirpAsync(loop, req, path.c_str(),
1452
                      req_wrap->continuation_data()->mode(), nullptr);
1453
222
          break;
1454
        }
1455
247
        default:
1456
247
          uv_fs_req_cleanup(req);
1457
          // Stash err for use in the callback.
1458
247
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1459
247
          int err = uv_fs_stat(loop, req, path.c_str(),
1460
247
                               uv_fs_callback_t{[](uv_fs_t* req) {
1461
247
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1462
247
            int err = static_cast<int>(req->result);
1463

494
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1464
247
                  req_wrap->continuation_data()->paths().size() > 0) {
1465

118
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1466
118
                Environment* env = req_wrap->env();
1467
118
                uv_loop_t* loop = env->event_loop();
1468
118
                std::string path = req->path;
1469
118
                uv_fs_req_cleanup(req);
1470
118
                MKDirpAsync(loop, req, path.c_str(),
1471
                            req_wrap->continuation_data()->mode(), nullptr);
1472
118
                return;
1473
              }
1474
              err = UV_ENOTDIR;
1475
            }
1476
            // verify that the path pointed to is actually a directory.
1477

129
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1478
129
            req_wrap->continuation_data()->Done(err);
1479
247
          }});
1480
247
          if (err < 0) req_wrap->continuation_data()->Done(err);
1481
247
          break;
1482
      }
1483
804
      break;
1484
1
    }
1485
804
  }});
1486
1487
804
  return err;
1488
}
1489
1490
283
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1491
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1492
283
  env->PrintSyncTrace();
1493
283
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1494
                       nullptr);
1495
283
  if (err < 0) {
1496
4
    v8::Local<v8::Context> context = env->context();
1497
4
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1498
4
    v8::Isolate* isolate = env->isolate();
1499
4
    ctx_obj->Set(context,
1500
                 env->errno_string(),
1501
16
                 v8::Integer::New(isolate, err)).Check();
1502
4
    ctx_obj->Set(context,
1503
                 env->syscall_string(),
1504
16
                 OneByteString(isolate, "mkdir")).Check();
1505
  }
1506
283
  return err;
1507
}
1508
1509
1803
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1510
1803
  Environment* env = Environment::GetCurrent(args);
1511
1512
1803
  const int argc = args.Length();
1513
1803
  CHECK_GE(argc, 4);
1514
1515
1803
  BufferValue path(env->isolate(), args[0]);
1516
1803
  CHECK_NOT_NULL(*path);
1517
1518
1803
  CHECK(args[1]->IsInt32());
1519
3606
  const int mode = args[1].As<Int32>()->Value();
1520
1521
1803
  CHECK(args[2]->IsBoolean());
1522
1803
  bool mkdirp = args[2]->IsTrue();
1523
1524
1803
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1525
1803
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1526

585
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1527
              mkdirp ? AfterMkdirp : AfterNoArgs,
1528
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1529
  } else {  // mkdir(path, mode, undefined, ctx)
1530
1218
    CHECK_EQ(argc, 5);
1531
1218
    FSReqWrapSync req_wrap_sync;
1532

1222
    FS_SYNC_TRACE_BEGIN(mkdir);
1533
1218
    if (mkdirp) {
1534
283
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1535

562
      if (err == 0 &&
1536
279
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1537
        Local<Value> error;
1538
277
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1539
277
        FromNamespacedPath(&first_path);
1540
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1541
                                                     first_path.c_str(),
1542
277
                                                     UTF8, &error);
1543
277
        if (path.IsEmpty()) {
1544
          Local<Object> ctx = args[4].As<Object>();
1545
          ctx->Set(env->context(), env->error_string(), error).Check();
1546
          return;
1547
        }
1548
554
        args.GetReturnValue().Set(path.ToLocalChecked());
1549
      }
1550
    } else {
1551
1870
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1552
               uv_fs_mkdir, *path, mode);
1553
    }
1554

1222
    FS_SYNC_TRACE_END(mkdir);
1555
  }
1556
}
1557
1558
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1559
42
  Environment* env = Environment::GetCurrent(args);
1560
42
  Isolate* isolate = env->isolate();
1561
1562
42
  const int argc = args.Length();
1563
42
  CHECK_GE(argc, 3);
1564
1565
42
  BufferValue path(isolate, args[0]);
1566
42
  CHECK_NOT_NULL(*path);
1567
1568
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1569
1570
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1571
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1572
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1573
              uv_fs_realpath, *path);
1574
  } else {  // realpath(path, encoding, undefined, ctx)
1575
20
    CHECK_EQ(argc, 4);
1576
20
    FSReqWrapSync req_wrap_sync;
1577

22
    FS_SYNC_TRACE_BEGIN(realpath);
1578
40
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1579
                       uv_fs_realpath, *path);
1580

22
    FS_SYNC_TRACE_END(realpath);
1581
20
    if (err < 0) {
1582
2
      return;  // syscall failed, no need to continue, error info is in ctx
1583
    }
1584
1585
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1586
1587
    Local<Value> error;
1588
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1589
                                               link_path,
1590
                                               encoding,
1591
18
                                               &error);
1592
18
    if (rc.IsEmpty()) {
1593
      Local<Object> ctx = args[3].As<Object>();
1594
      ctx->Set(env->context(), env->error_string(), error).Check();
1595
      return;
1596
    }
1597
1598
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1599
  }
1600
}
1601
1602
13954
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1603
13954
  Environment* env = Environment::GetCurrent(args);
1604
13954
  Isolate* isolate = env->isolate();
1605
1606
13954
  const int argc = args.Length();
1607
13954
  CHECK_GE(argc, 3);
1608
1609
13954
  BufferValue path(isolate, args[0]);
1610
13954
  CHECK_NOT_NULL(*path);
1611
1612
13954
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1613
1614
13954
  bool with_types = args[2]->IsTrue();
1615
1616
13954
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1617
13954
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1618
222
    req_wrap_async->set_with_file_types(with_types);
1619
222
    AsyncCall(env,
1620
              req_wrap_async,
1621
              args,
1622
              "scandir",
1623
              encoding,
1624
              AfterScanDir,
1625
              uv_fs_scandir,
1626
              *path,
1627
              0 /*flags*/);
1628
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1629
13732
    CHECK_EQ(argc, 5);
1630
13732
    FSReqWrapSync req_wrap_sync;
1631

13734
    FS_SYNC_TRACE_BEGIN(readdir);
1632
27464
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1633
                       uv_fs_scandir, *path, 0 /*flags*/);
1634

13734
    FS_SYNC_TRACE_END(readdir);
1635
13732
    if (err < 0) {
1636
133
      return;  // syscall failed, no need to continue, error info is in ctx
1637
    }
1638
1639
13599
    CHECK_GE(req_wrap_sync.req.result, 0);
1640
    int r;
1641
13599
    std::vector<Local<Value>> name_v;
1642
13599
    std::vector<Local<Value>> type_v;
1643
1644
    for (;;) {
1645
      uv_dirent_t ent;
1646
1647
722303
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1648
722303
      if (r == UV_EOF)
1649
13599
        break;
1650
708704
      if (r != 0) {
1651
        Local<Object> ctx = args[4].As<Object>();
1652
        ctx->Set(env->context(), env->errno_string(),
1653
                 Integer::New(isolate, r)).Check();
1654
        ctx->Set(env->context(), env->syscall_string(),
1655
                 OneByteString(isolate, "readdir")).Check();
1656
        return;
1657
      }
1658
1659
      Local<Value> error;
1660
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1661
                                                       ent.name,
1662
                                                       encoding,
1663
708704
                                                       &error);
1664
1665
708704
      if (filename.IsEmpty()) {
1666
        Local<Object> ctx = args[4].As<Object>();
1667
        ctx->Set(env->context(), env->error_string(), error).Check();
1668
        return;
1669
      }
1670
1671
708704
      name_v.push_back(filename.ToLocalChecked());
1672
1673
708704
      if (with_types) {
1674
50473
        type_v.emplace_back(Integer::New(isolate, ent.type));
1675
      }
1676
708704
    }
1677
1678
1679
13599
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1680
13599
    if (with_types) {
1681
      Local<Value> result[] = {
1682
        names,
1683
        Array::New(isolate, type_v.data(), type_v.size())
1684
386
      };
1685
386
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1686
    } else {
1687
26812
      args.GetReturnValue().Set(names);
1688
    }
1689
  }
1690
}
1691
1692
62178
static void Open(const FunctionCallbackInfo<Value>& args) {
1693
62178
  Environment* env = Environment::GetCurrent(args);
1694
1695
62178
  const int argc = args.Length();
1696
62178
  CHECK_GE(argc, 3);
1697
1698
124356
  BufferValue path(env->isolate(), args[0]);
1699
62178
  CHECK_NOT_NULL(*path);
1700
1701
62178
  CHECK(args[1]->IsInt32());
1702
124356
  const int flags = args[1].As<Int32>()->Value();
1703
1704
62178
  CHECK(args[2]->IsInt32());
1705
124356
  const int mode = args[2].As<Int32>()->Value();
1706
1707
62178
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1708
62178
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1709
5622
    req_wrap_async->set_is_plain_open(true);
1710
5622
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1711
              uv_fs_open, *path, flags, mode);
1712
  } else {  // open(path, flags, mode, undefined, ctx)
1713
56556
    CHECK_EQ(argc, 5);
1714
56556
    FSReqWrapSync req_wrap_sync;
1715

56619
    FS_SYNC_TRACE_BEGIN(open);
1716
113112
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1717
                          uv_fs_open, *path, flags, mode);
1718

56619
    FS_SYNC_TRACE_END(open);
1719
56556
    if (result >= 0) env->AddUnmanagedFd(result);
1720
113112
    args.GetReturnValue().Set(result);
1721
  }
1722
62178
}
1723
1724
1591
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1725
1591
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1726
1591
  Environment* env = binding_data->env();
1727
1591
  Isolate* isolate = env->isolate();
1728
1729
1591
  const int argc = args.Length();
1730
1591
  CHECK_GE(argc, 3);
1731
1732
1591
  BufferValue path(isolate, args[0]);
1733
1591
  CHECK_NOT_NULL(*path);
1734
1735
1591
  CHECK(args[1]->IsInt32());
1736
3182
  const int flags = args[1].As<Int32>()->Value();
1737
1738
1591
  CHECK(args[2]->IsInt32());
1739
3182
  const int mode = args[2].As<Int32>()->Value();
1740
1741
1591
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1742
1591
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1743
1590
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1744
              uv_fs_open, *path, flags, mode);
1745
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1746
1
    CHECK_EQ(argc, 5);
1747
1
    FSReqWrapSync req_wrap_sync;
1748

1
    FS_SYNC_TRACE_BEGIN(open);
1749
2
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1750
                          uv_fs_open, *path, flags, mode);
1751

1
    FS_SYNC_TRACE_END(open);
1752
1
    if (result < 0) {
1753
      return;  // syscall failed, no need to continue, error info is in ctx
1754
    }
1755
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1756
1
    if (fd == nullptr) return;
1757
2
    args.GetReturnValue().Set(fd->object());
1758
  }
1759
}
1760
1761
219
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1762
219
  Environment* env = Environment::GetCurrent(args);
1763
219
  Isolate* isolate = env->isolate();
1764
1765
219
  const int argc = args.Length();
1766
219
  CHECK_GE(argc, 3);
1767
1768
438
  BufferValue src(isolate, args[0]);
1769
219
  CHECK_NOT_NULL(*src);
1770
1771
438
  BufferValue dest(isolate, args[1]);
1772
219
  CHECK_NOT_NULL(*dest);
1773
1774
219
  CHECK(args[2]->IsInt32());
1775
438
  const int flags = args[2].As<Int32>()->Value();
1776
1777
219
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1778
219
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1779
204
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1780
102
                  *dest, dest.length(), UTF8, AfterNoArgs,
1781
                  uv_fs_copyfile, *src, *dest, flags);
1782
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1783
117
    CHECK_EQ(argc, 5);
1784
234
    FSReqWrapSync req_wrap_sync;
1785

119
    FS_SYNC_TRACE_BEGIN(copyfile);
1786
234
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1787
             uv_fs_copyfile, *src, *dest, flags);
1788

119
    FS_SYNC_TRACE_END(copyfile);
1789
  }
1790
219
}
1791
1792
1793
// Wrapper for write(2).
1794
//
1795
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1796
// 0 fd        integer. file descriptor
1797
// 1 buffer    the data to write
1798
// 2 offset    where in the buffer to start from
1799
// 3 length    how much to write
1800
// 4 position  if integer, position to write at in the file.
1801
//             if null, write from the current position
1802
87245
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1803
87245
  Environment* env = Environment::GetCurrent(args);
1804
1805
87245
  const int argc = args.Length();
1806
87245
  CHECK_GE(argc, 4);
1807
1808
87245
  CHECK(args[0]->IsInt32());
1809
174490
  const int fd = args[0].As<Int32>()->Value();
1810
1811
87245
  CHECK(Buffer::HasInstance(args[1]));
1812
87245
  Local<Object> buffer_obj = args[1].As<Object>();
1813
87245
  char* buffer_data = Buffer::Data(buffer_obj);
1814
87245
  size_t buffer_length = Buffer::Length(buffer_obj);
1815
1816
87245
  CHECK(IsSafeJsInt(args[2]));
1817
174490
  const int64_t off_64 = args[2].As<Integer>()->Value();
1818
87245
  CHECK_GE(off_64, 0);
1819
87245
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1820
87245
  const size_t off = static_cast<size_t>(off_64);
1821
1822
87245
  CHECK(args[3]->IsInt32());
1823
174490
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1824
87245
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1825
87245
  CHECK_LE(len, buffer_length);
1826
87245
  CHECK_GE(off + len, off);
1827
1828
87245
  const int64_t pos = GetOffset(args[4]);
1829
1830
87245
  char* buf = buffer_data + off;
1831
87245
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1832
1833
87245
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1834
87245
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1835
17612
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1836
              uv_fs_write, fd, &uvbuf, 1, pos);
1837
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1838
69633
    CHECK_EQ(argc, 7);
1839
69633
    FSReqWrapSync req_wrap_sync;
1840

69683
    FS_SYNC_TRACE_BEGIN(write);
1841
69633
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1842
69633
                                uv_fs_write, fd, &uvbuf, 1, pos);
1843

69683
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1844
139266
    args.GetReturnValue().Set(bytesWritten);
1845
  }
1846
87245
}
1847
1848
1849
// Wrapper for writev(2).
1850
//
1851
// bytesWritten = writev(fd, chunks, position, callback)
1852
// 0 fd        integer. file descriptor
1853
// 1 chunks    array of buffers to write
1854
// 2 position  if integer, position to write at in the file.
1855
//             if null, write from the current position
1856
19
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1857
19
  Environment* env = Environment::GetCurrent(args);
1858
1859
19
  const int argc = args.Length();
1860
19
  CHECK_GE(argc, 3);
1861
1862
19
  CHECK(args[0]->IsInt32());
1863
38
  const int fd = args[0].As<Int32>()->Value();
1864
1865
19
  CHECK(args[1]->IsArray());
1866
38
  Local<Array> chunks = args[1].As<Array>();
1867
1868
19
  int64_t pos = GetOffset(args[2]);
1869
1870
38
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1871
1872
75
  for (uint32_t i = 0; i < iovs.length(); i++) {
1873
56
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1874
56
    CHECK(Buffer::HasInstance(chunk));
1875
56
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1876
  }
1877
1878
19
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1879
19
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1880
15
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1881
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1882
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1883
4
    CHECK_EQ(argc, 5);
1884
4
    FSReqWrapSync req_wrap_sync;
1885

4
    FS_SYNC_TRACE_BEGIN(write);
1886
8
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1887
4
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1888

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

390560
  if (!is_async && value->IsString()) {
1931
130160
    auto string = value.As<String>();
1932


130161
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1933
1
      auto ext = string->GetExternalOneByteStringResource();
1934
1
      buf = const_cast<char*>(ext->data());
1935
1
      len = ext->length();
1936


130160
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
1937
1
      auto ext = string->GetExternalStringResource();
1938
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1939
1
      len = ext->length() * sizeof(*ext->data());
1940
    }
1941
  }
1942
1943
130240
  if (is_async) {  // write(fd, string, pos, enc, req)
1944
80
    CHECK_NOT_NULL(req_wrap_async);
1945
160
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1946
    FSReqBase::FSReqBuffer& stack_buffer =
1947
80
        req_wrap_async->Init("write", len, enc);
1948
    // StorageSize may return too large a char, so correct the actual length
1949
    // by the write size
1950
80
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1951
80
    stack_buffer.SetLengthAndZeroTerminate(len);
1952
80
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1953
80
    int err = req_wrap_async->Dispatch(uv_fs_write,
1954
                                       fd,
1955
                                       &uvbuf,
1956
                                       1,
1957
                                       pos,
1958
                                       AfterInteger);
1959
80
    if (err < 0) {
1960
      uv_fs_t* uv_req = req_wrap_async->req();
1961
      uv_req->result = err;
1962
      uv_req->path = nullptr;
1963
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1964
                             // an error
1965
    } else {
1966
80
      req_wrap_async->SetReturnValue(args);
1967
    }
1968
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1969
130160
    CHECK_EQ(argc, 6);
1970
130160
    FSReqWrapSync req_wrap_sync;
1971
130160
    FSReqBase::FSReqBuffer stack_buffer;
1972
130160
    if (buf == nullptr) {
1973
260316
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1974
        return;
1975
130158
      stack_buffer.AllocateSufficientStorage(len + 1);
1976
      // StorageSize may return too large a char, so correct the actual length
1977
      // by the write size
1978
130158
      len = StringBytes::Write(isolate, *stack_buffer,
1979
                               len, args[1], enc);
1980
130158
      stack_buffer.SetLengthAndZeroTerminate(len);
1981
130158
      buf = *stack_buffer;
1982
    }
1983
130160
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1984

130160
    FS_SYNC_TRACE_BEGIN(write);
1985
130160
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1986
130160
                                uv_fs_write, fd, &uvbuf, 1, pos);
1987

130160
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1988
260320
    args.GetReturnValue().Set(bytesWritten);
1989
  }
1990
}
1991
1992
1993
/*
1994
 * Wrapper for read(2).
1995
 *
1996
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1997
 *
1998
 * 0 fd        int32. file descriptor
1999
 * 1 buffer    instance of Buffer
2000
 * 2 offset    int64. offset to start reading into inside buffer
2001
 * 3 length    int32. length to read
2002
 * 4 position  int64. file position - -1 for current position
2003
 */
2004
204886
static void Read(const FunctionCallbackInfo<Value>& args) {
2005
204886
  Environment* env = Environment::GetCurrent(args);
2006
2007
204886
  const int argc = args.Length();
2008
204886
  CHECK_GE(argc, 5);
2009
2010
204886
  CHECK(args[0]->IsInt32());
2011
409772
  const int fd = args[0].As<Int32>()->Value();
2012
2013
204886
  CHECK(Buffer::HasInstance(args[1]));
2014
204886
  Local<Object> buffer_obj = args[1].As<Object>();
2015
204886
  char* buffer_data = Buffer::Data(buffer_obj);
2016
204886
  size_t buffer_length = Buffer::Length(buffer_obj);
2017
2018
204886
  CHECK(IsSafeJsInt(args[2]));
2019
409772
  const int64_t off_64 = args[2].As<Integer>()->Value();
2020
204886
  CHECK_GE(off_64, 0);
2021
204886
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2022
204886
  const size_t off = static_cast<size_t>(off_64);
2023
2024
204886
  CHECK(args[3]->IsInt32());
2025
409772
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2026
204886
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2027
2028

204916
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2029
204886
  const int64_t pos = args[4]->IsNumber() ?
2030
409712
                      args[4].As<Integer>()->Value() :
2031
60
                      args[4].As<BigInt>()->Int64Value();
2032
2033
204886
  char* buf = buffer_data + off;
2034
204886
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2035
2036
204886
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2037
204886
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2038
14890
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2039
              uv_fs_read, fd, &uvbuf, 1, pos);
2040
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2041
189996
    CHECK_EQ(argc, 7);
2042
189996
    FSReqWrapSync req_wrap_sync;
2043

190035
    FS_SYNC_TRACE_BEGIN(read);
2044
189996
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2045
189996
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2046

190035
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2047
379992
    args.GetReturnValue().Set(bytesRead);
2048
  }
2049
204886
}
2050
2051
2052
// Wrapper for readv(2).
2053
//
2054
// bytesRead = fs.readv(fd, buffers[, position], callback)
2055
// 0 fd        integer. file descriptor
2056
// 1 buffers   array of buffers to read
2057
// 2 position  if integer, position to read at in the file.
2058
//             if null, read from the current position
2059
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2060
11
  Environment* env = Environment::GetCurrent(args);
2061
2062
11
  const int argc = args.Length();
2063
11
  CHECK_GE(argc, 3);
2064
2065
11
  CHECK(args[0]->IsInt32());
2066
22
  const int fd = args[0].As<Int32>()->Value();
2067
2068
11
  CHECK(args[1]->IsArray());
2069
22
  Local<Array> buffers = args[1].As<Array>();
2070
2071
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2072
2073
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2074
2075
  // Init uv buffers from ArrayBufferViews
2076
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2077
17
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2078
17
    CHECK(Buffer::HasInstance(buffer));
2079
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2080
  }
2081
2082
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2083
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2084
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2085
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2086
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2087
4
    CHECK_EQ(argc, 5);
2088
4
    FSReqWrapSync req_wrap_sync;
2089

4
    FS_SYNC_TRACE_BEGIN(read);
2090
8
    int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2091
4
                             uv_fs_read, fd, *iovs, iovs.length(), pos);
2092

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2093
8
    args.GetReturnValue().Set(bytesRead);
2094
  }
2095
11
}
2096
2097
2098
/* fs.chmod(path, mode);
2099
 * Wrapper for chmod(1) / EIO_CHMOD
2100
 */
2101
310
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2102
310
  Environment* env = Environment::GetCurrent(args);
2103
2104
310
  const int argc = args.Length();
2105
310
  CHECK_GE(argc, 2);
2106
2107
620
  BufferValue path(env->isolate(), args[0]);
2108
310
  CHECK_NOT_NULL(*path);
2109
2110
310
  CHECK(args[1]->IsInt32());
2111
620
  int mode = args[1].As<Int32>()->Value();
2112
2113
310
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2114
310
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2115
141
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2116
              uv_fs_chmod, *path, mode);
2117
  } else {  // chmod(path, mode, undefined, ctx)
2118
169
    CHECK_EQ(argc, 4);
2119
338
    FSReqWrapSync req_wrap_sync;
2120

171
    FS_SYNC_TRACE_BEGIN(chmod);
2121
338
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2122
             uv_fs_chmod, *path, mode);
2123

171
    FS_SYNC_TRACE_END(chmod);
2124
  }
2125
310
}
2126
2127
2128
/* fs.fchmod(fd, mode);
2129
 * Wrapper for fchmod(1) / EIO_FCHMOD
2130
 */
2131
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2132
12
  Environment* env = Environment::GetCurrent(args);
2133
2134
12
  const int argc = args.Length();
2135
12
  CHECK_GE(argc, 2);
2136
2137
12
  CHECK(args[0]->IsInt32());
2138
24
  const int fd = args[0].As<Int32>()->Value();
2139
2140
12
  CHECK(args[1]->IsInt32());
2141
24
  const int mode = args[1].As<Int32>()->Value();
2142
2143
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2144
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2145
7
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2146
              uv_fs_fchmod, fd, mode);
2147
  } else {  // fchmod(fd, mode, undefined, ctx)
2148
5
    CHECK_EQ(argc, 4);
2149
10
    FSReqWrapSync req_wrap_sync;
2150

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2151
5
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2152
             uv_fs_fchmod, fd, mode);
2153

7
    FS_SYNC_TRACE_END(fchmod);
2154
  }
2155
12
}
2156
2157
2158
/* fs.chown(path, uid, gid);
2159
 * Wrapper for chown(1) / EIO_CHOWN
2160
 */
2161
4
static void Chown(const FunctionCallbackInfo<Value>& args) {
2162
4
  Environment* env = Environment::GetCurrent(args);
2163
2164
4
  const int argc = args.Length();
2165
4
  CHECK_GE(argc, 3);
2166
2167
8
  BufferValue path(env->isolate(), args[0]);
2168
4
  CHECK_NOT_NULL(*path);
2169
2170
4
  CHECK(IsSafeJsInt(args[1]));
2171
8
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2172
2173
4
  CHECK(IsSafeJsInt(args[2]));
2174
8
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2175
2176
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2177
4
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2178
2
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2179
              uv_fs_chown, *path, uid, gid);
2180
  } else {  // chown(path, uid, gid, undefined, ctx)
2181
2
    CHECK_EQ(argc, 5);
2182
4
    FSReqWrapSync req_wrap_sync;
2183

4
    FS_SYNC_TRACE_BEGIN(chown);
2184
4
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2185
             uv_fs_chown, *path, uid, gid);
2186

4
    FS_SYNC_TRACE_END(chown);
2187
  }
2188
4
}
2189
2190
2191
/* fs.fchown(fd, uid, gid);
2192
 * Wrapper for fchown(1) / EIO_FCHOWN
2193
 */
2194
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2195
4
  Environment* env = Environment::GetCurrent(args);
2196
2197
4
  const int argc = args.Length();
2198
4
  CHECK_GE(argc, 3);
2199
2200
4
  CHECK(args[0]->IsInt32());
2201
8
  const int fd = args[0].As<Int32>()->Value();
2202
2203
4
  CHECK(IsSafeJsInt(args[1]));
2204
8
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2205
2206
4
  CHECK(IsSafeJsInt(args[2]));
2207
8
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2208
2209
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2210
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2211
2
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2212
              uv_fs_fchown, fd, uid, gid);
2213
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2214
2
    CHECK_EQ(argc, 5);
2215
4
    FSReqWrapSync req_wrap_sync;
2216

4
    FS_SYNC_TRACE_BEGIN(fchown);
2217
2
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2218
             uv_fs_fchown, fd, uid, gid);
2219

4
    FS_SYNC_TRACE_END(fchown);
2220
  }
2221
4
}
2222
2223
2224
5
static void LChown(const FunctionCallbackInfo<Value>& args) {
2225
5
  Environment* env = Environment::GetCurrent(args);
2226
2227
5
  const int argc = args.Length();
2228
5
  CHECK_GE(argc, 3);
2229
2230
10
  BufferValue path(env->isolate(), args[0]);
2231
5
  CHECK_NOT_NULL(*path);
2232
2233
5
  CHECK(IsSafeJsInt(args[1]));
2234
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2235
2236
5
  CHECK(IsSafeJsInt(args[2]));
2237
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2238
2239
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2240
5
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2241
3
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2242
              uv_fs_lchown, *path, uid, gid);
2243
  } else {  // lchown(path, uid, gid, undefined, ctx)
2244
2
    CHECK_EQ(argc, 5);
2245
4
    FSReqWrapSync req_wrap_sync;
2246

4
    FS_SYNC_TRACE_BEGIN(lchown);
2247
4
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2248
             uv_fs_lchown, *path, uid, gid);
2249

4
    FS_SYNC_TRACE_END(lchown);
2250
  }
2251
5
}
2252
2253
2254
61
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2255
61
  Environment* env = Environment::GetCurrent(args);
2256
2257
61
  const int argc = args.Length();
2258
61
  CHECK_GE(argc, 3);
2259
2260
122
  BufferValue path(env->isolate(), args[0]);
2261
61
  CHECK_NOT_NULL(*path);
2262
2263
61
  CHECK(args[1]->IsNumber());
2264
122
  const double atime = args[1].As<Number>()->Value();
2265
2266
61
  CHECK(args[2]->IsNumber());
2267
122
  const double mtime = args[2].As<Number>()->Value();
2268
2269
61
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2270
61
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2271
34
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2272
              uv_fs_utime, *path, atime, mtime);
2273
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2274
27
    CHECK_EQ(argc, 5);
2275
54
    FSReqWrapSync req_wrap_sync;
2276

29
    FS_SYNC_TRACE_BEGIN(utimes);
2277
54
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2278
             uv_fs_utime, *path, atime, mtime);
2279

29
    FS_SYNC_TRACE_END(utimes);
2280
  }
2281
61
}
2282
2283
18
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2284
18
  Environment* env = Environment::GetCurrent(args);
2285
2286
18
  const int argc = args.Length();
2287
18
  CHECK_GE(argc, 3);
2288
2289
18
  CHECK(args[0]->IsInt32());
2290
36
  const int fd = args[0].As<Int32>()->Value();
2291
2292
18
  CHECK(args[1]->IsNumber());
2293
36
  const double atime = args[1].As<Number>()->Value();
2294
2295
18
  CHECK(args[2]->IsNumber());
2296
36
  const double mtime = args[2].As<Number>()->Value();
2297
2298
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2299
18
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2300
9
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2301
              uv_fs_futime, fd, atime, mtime);
2302
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2303
9
    CHECK_EQ(argc, 5);
2304
18
    FSReqWrapSync req_wrap_sync;
2305

11
    FS_SYNC_TRACE_BEGIN(futimes);
2306
9
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2307
             uv_fs_futime, fd, atime, mtime);
2308

11
    FS_SYNC_TRACE_END(futimes);
2309
  }
2310
18
}
2311
2312
15
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2313
15
  Environment* env = Environment::GetCurrent(args);
2314
2315
15
  const int argc = args.Length();
2316
15
  CHECK_GE(argc, 3);
2317
2318
30
  BufferValue path(env->isolate(), args[0]);
2319
15
  CHECK_NOT_NULL(*path);
2320
2321
15
  CHECK(args[1]->IsNumber());
2322
30
  const double atime = args[1].As<Number>()->Value();
2323
2324
15
  CHECK(args[2]->IsNumber());
2325
30
  const double mtime = args[2].As<Number>()->Value();
2326
2327
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2328
15
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2329
8
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2330
              uv_fs_lutime, *path, atime, mtime);
2331
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2332
7
    CHECK_EQ(argc, 5);
2333
14
    FSReqWrapSync req_wrap_sync;
2334

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2335
14
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2336
             uv_fs_lutime, *path, atime, mtime);
2337

7
    FS_SYNC_TRACE_END(lutimes);
2338
  }
2339
15
}
2340
2341
15
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2342
15
  Environment* env = Environment::GetCurrent(args);
2343
15
  Isolate* isolate = env->isolate();
2344
2345
15
  const int argc = args.Length();
2346
15
  CHECK_GE(argc, 2);
2347
2348
15
  BufferValue tmpl(isolate, args[0]);
2349
15
  CHECK_NOT_NULL(*tmpl);
2350
2351
15
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2352
2353
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2354
15
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2355
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2356
              uv_fs_mkdtemp, *tmpl);
2357
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2358
9
    CHECK_EQ(argc, 4);
2359
9
    FSReqWrapSync req_wrap_sync;
2360

11
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2361
18
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2362
             uv_fs_mkdtemp, *tmpl);
2363

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