GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_file.cc Lines: 592 1240 47.7 %
Date: 2019-02-01 22:03:38 Branches: 250 1164 21.5 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_file.h"
23
#include "aliased_buffer.h"
24
#include "node_buffer.h"
25
#include "node_process.h"
26
#include "node_stat_watcher.h"
27
#include "util.h"
28
29
#include "tracing/trace_event.h"
30
31
#include "req_wrap-inl.h"
32
#include "stream_base-inl.h"
33
#include "string_bytes.h"
34
#include "string_search.h"
35
36
#include <fcntl.h>
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <string.h>
40
#include <errno.h>
41
#include <limits.h>
42
43
#if defined(__MINGW32__) || defined(_MSC_VER)
44
# include <io.h>
45
#endif
46
47
#include <memory>
48
49
namespace node {
50
51
namespace fs {
52
53
using v8::Array;
54
using v8::BigUint64Array;
55
using v8::Context;
56
using v8::EscapableHandleScope;
57
using v8::Float64Array;
58
using v8::Function;
59
using v8::FunctionCallbackInfo;
60
using v8::FunctionTemplate;
61
using v8::HandleScope;
62
using v8::Int32;
63
using v8::Integer;
64
using v8::Isolate;
65
using v8::Local;
66
using v8::MaybeLocal;
67
using v8::Number;
68
using v8::Object;
69
using v8::ObjectTemplate;
70
using v8::Promise;
71
using v8::String;
72
using v8::Symbol;
73
using v8::Uint32;
74
using v8::Undefined;
75
using v8::Value;
76
77
#ifndef MIN
78
# define MIN(a, b) ((a) < (b) ? (a) : (b))
79
#endif
80
81
#ifndef S_ISDIR
82
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
83
#endif
84
85
#ifdef __POSIX__
86
constexpr char kPathSeparator = '/';
87
#else
88
const char* const kPathSeparator = "\\/";
89
#endif
90
91
#define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
92
#define TRACE_NAME(name) "fs.sync." #name
93
#define GET_TRACE_ENABLED                                                  \
94
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
95
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
96
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
97
  if (GET_TRACE_ENABLED)                                                   \
98
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
99
  ##__VA_ARGS__);
100
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
101
  if (GET_TRACE_ENABLED)                                                   \
102
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
103
  ##__VA_ARGS__);
104
105
// We sometimes need to convert a C++ lambda function to a raw C-style function.
106
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
107
// functions, and thus does not wrap them properly.
108
typedef void(*uv_fs_callback_t)(uv_fs_t*);
109
110
// The FileHandle object wraps a file descriptor and will close it on garbage
111
// collection if necessary. If that happens, a process warning will be
112
// emitted (or a fatal exception will occur if the fd cannot be closed.)
113
FileHandle::FileHandle(Environment* env, int fd, Local<Object> obj)
114
    : AsyncWrap(env,
115
                obj.IsEmpty() ? env->fd_constructor_template()
116
                    ->NewInstance(env->context()).ToLocalChecked() : obj,
117
                AsyncWrap::PROVIDER_FILEHANDLE),
118
      StreamBase(env),
119
      fd_(fd) {
120
  MakeWeak();
121
  v8::PropertyAttribute attr =
122
      static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
123
  object()->DefineOwnProperty(env->context(),
124
                              FIXED_ONE_BYTE_STRING(env->isolate(), "fd"),
125
                              Integer::New(env->isolate(), fd),
126
                              attr).FromJust();
127
}
128
129
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
130
  Environment* env = Environment::GetCurrent(args);
131
  CHECK(args.IsConstructCall());
132
  CHECK(args[0]->IsInt32());
133
134
  FileHandle* handle =
135
      new FileHandle(env, args[0].As<Int32>()->Value(), args.This());
136
  if (args[1]->IsNumber())
137
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
138
  if (args[2]->IsNumber())
139
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
140
}
141
142
FileHandle::~FileHandle() {
143
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
144
  Close();           // Close synchronously and emit warning
145
  CHECK(closed_);    // We have to be closed at the point
146
}
147
148
149
// Close the file descriptor if it hasn't already been closed. A process
150
// warning will be emitted using a SetImmediate to avoid calling back to
151
// JS during GC. If closing the fd fails at this point, a fatal exception
152
// will crash the process immediately.
153
inline void FileHandle::Close() {
154
  if (closed_) return;
155
  uv_fs_t req;
156
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
157
  uv_fs_req_cleanup(&req);
158
  AfterClose();
159
160
  struct err_detail { int ret; int fd; };
161
162
  err_detail* detail = new err_detail { ret, fd_ };
163
164
  if (ret < 0) {
165
    // Do not unref this
166
    env()->SetImmediate([](Environment* env, void* data) {
167
      char msg[70];
168
      std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
169
      snprintf(msg, arraysize(msg),
170
              "Closing file descriptor %d on garbage collection failed",
171
              detail->fd);
172
      // This exception will end up being fatal for the process because
173
      // it is being thrown from within the SetImmediate handler and
174
      // there is no JS stack to bubble it to. In other words, tearing
175
      // down the process is the only reasonable thing we can do here.
176
      HandleScope handle_scope(env->isolate());
177
      env->ThrowUVException(detail->ret, "close", msg);
178
    }, detail);
179
    return;
180
  }
181
182
  // If the close was successful, we still want to emit a process warning
183
  // to notify that the file descriptor was gc'd. We want to be noisy about
184
  // this because not explicitly closing the FileHandle is a bug.
185
  env()->SetUnrefImmediate([](Environment* env, void* data) {
186
    std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
187
    ProcessEmitWarning(env,
188
                       "Closing file descriptor %d on garbage collection",
189
                       detail->fd);
190
  }, detail);
191
}
192
193
void FileHandle::CloseReq::Resolve() {
194
  Isolate* isolate = env()->isolate();
195
  HandleScope scope(isolate);
196
  InternalCallbackScope callback_scope(this);
197
  Local<Promise> promise = promise_.Get(isolate);
198
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
199
  resolver->Resolve(env()->context(), Undefined(isolate)).FromJust();
200
}
201
202
void FileHandle::CloseReq::Reject(Local<Value> reason) {
203
  Isolate* isolate = env()->isolate();
204
  HandleScope scope(isolate);
205
  InternalCallbackScope callback_scope(this);
206
  Local<Promise> promise = promise_.Get(isolate);
207
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
208
  resolver->Reject(env()->context(), reason).FromJust();
209
}
210
211
FileHandle* FileHandle::CloseReq::file_handle() {
212
  Isolate* isolate = env()->isolate();
213
  HandleScope scope(isolate);
214
  Local<Value> val = ref_.Get(isolate);
215
  Local<Object> obj = val.As<Object>();
216
  return Unwrap<FileHandle>(obj);
217
}
218
219
// Closes this FileHandle asynchronously and returns a Promise that will be
220
// resolved when the callback is invoked, or rejects with a UVException if
221
// there was a problem closing the fd. This is the preferred mechanism for
222
// closing the FD object even tho the object will attempt to close
223
// automatically on gc.
224
inline MaybeLocal<Promise> FileHandle::ClosePromise() {
225
  Isolate* isolate = env()->isolate();
226
  EscapableHandleScope scope(isolate);
227
  Local<Context> context = env()->context();
228
  auto maybe_resolver = Promise::Resolver::New(context);
229
  CHECK(!maybe_resolver.IsEmpty());
230
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
231
  Local<Promise> promise = resolver.As<Promise>();
232
  CHECK(!reading_);
233
  if (!closed_ && !closing_) {
234
    closing_ = true;
235
    CloseReq* req = new CloseReq(env(), promise, object());
236
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
237
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
238
      CHECK_NOT_NULL(close);
239
      close->file_handle()->AfterClose();
240
      Isolate* isolate = close->env()->isolate();
241
      if (req->result < 0) {
242
        close->Reject(UVException(isolate, req->result, "close"));
243
      } else {
244
        close->Resolve();
245
      }
246
    }};
247
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
248
    if (ret < 0) {
249
      req->Reject(UVException(isolate, ret, "close"));
250
      delete req;
251
    }
252
  } else {
253
    // Already closed. Just reject the promise immediately
254
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
255
        .FromJust();
256
  }
257
  return scope.Escape(promise);
258
}
259
260
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
261
  FileHandle* fd;
262
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
263
  args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked());
264
}
265
266
267
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
268
  FileHandle* fd;
269
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
270
  // Just act as if this FileHandle has been closed.
271
  fd->AfterClose();
272
}
273
274
275
void FileHandle::AfterClose() {
276
  closing_ = false;
277
  closed_ = true;
278
  if (reading_ && !persistent().IsEmpty())
279
    EmitRead(UV_EOF);
280
}
281
282
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
283
  tracker->TrackField("buffer", buffer_);
284
  tracker->TrackField("file_handle", this->file_handle_);
285
}
286
287
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
288
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
289
    file_handle_(handle) {}
290
291
int FileHandle::ReadStart() {
292
  if (!IsAlive() || IsClosing())
293
    return UV_EOF;
294
295
  reading_ = true;
296
297
  if (current_read_)
298
    return 0;
299
300
  std::unique_ptr<FileHandleReadWrap> read_wrap;
301
302
  if (read_length_ == 0) {
303
    EmitRead(UV_EOF);
304
    return 0;
305
  }
306
307
  {
308
    // Create a new FileHandleReadWrap or re-use one.
309
    // Either way, we need these two scopes for AsyncReset() or otherwise
310
    // for creating the new instance.
311
    HandleScope handle_scope(env()->isolate());
312
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
313
314
    auto& freelist = env()->file_handle_read_wrap_freelist();
315
    if (freelist.size() > 0) {
316
      read_wrap = std::move(freelist.back());
317
      freelist.pop_back();
318
      read_wrap->AsyncReset();
319
      read_wrap->file_handle_ = this;
320
    } else {
321
      Local<Object> wrap_obj = env()->filehandlereadwrap_template()
322
          ->NewInstance(env()->context()).ToLocalChecked();
323
      read_wrap.reset(new FileHandleReadWrap(this, wrap_obj));
324
    }
325
  }
326
  int64_t recommended_read = 65536;
327
  if (read_length_ >= 0 && read_length_ <= recommended_read)
328
    recommended_read = read_length_;
329
330
  read_wrap->buffer_ = EmitAlloc(recommended_read);
331
332
  current_read_ = std::move(read_wrap);
333
334
  current_read_->Dispatch(uv_fs_read,
335
                          fd_,
336
                          &current_read_->buffer_,
337
                          1,
338
                          read_offset_,
339
                          uv_fs_callback_t{[](uv_fs_t* req) {
340
    FileHandle* handle;
341
    {
342
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
343
      handle = req_wrap->file_handle_;
344
      CHECK_EQ(handle->current_read_.get(), req_wrap);
345
    }
346
347
    // ReadStart() checks whether current_read_ is set to determine whether
348
    // a read is in progress. Moving it into a local variable makes sure that
349
    // the ReadStart() call below doesn't think we're still actively reading.
350
    std::unique_ptr<FileHandleReadWrap> read_wrap =
351
        std::move(handle->current_read_);
352
353
    int result = req->result;
354
    uv_buf_t buffer = read_wrap->buffer_;
355
356
    uv_fs_req_cleanup(req);
357
358
    // Push the read wrap back to the freelist, or let it be destroyed
359
    // once we’re exiting the current scope.
360
    constexpr size_t wanted_freelist_fill = 100;
361
    auto& freelist = handle->env()->file_handle_read_wrap_freelist();
362
    if (freelist.size() < wanted_freelist_fill) {
363
      read_wrap->Reset();
364
      freelist.emplace_back(std::move(read_wrap));
365
    }
366
367
    if (result >= 0) {
368
      // Read at most as many bytes as we originally planned to.
369
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
370
        result = handle->read_length_;
371
372
      // If we read data and we have an expected length, decrease it by
373
      // how much we have read.
374
      if (handle->read_length_ >= 0)
375
        handle->read_length_ -= result;
376
377
      // If we have an offset, increase it by how much we have read.
378
      if (handle->read_offset_ >= 0)
379
        handle->read_offset_ += result;
380
    }
381
382
    // Reading 0 bytes from a file always means EOF, or that we reached
383
    // the end of the requested range.
384
    if (result == 0)
385
      result = UV_EOF;
386
387
    handle->EmitRead(result, buffer);
388
389
    // Start over, if EmitRead() didn’t tell us to stop.
390
    if (handle->reading_)
391
      handle->ReadStart();
392
  }});
393
394
  return 0;
395
}
396
397
int FileHandle::ReadStop() {
398
  reading_ = false;
399
  return 0;
400
}
401
402
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
403
404
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
405
  return new FileHandleCloseWrap(this, object);
406
}
407
408
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
409
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
410
  closing_ = true;
411
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
412
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
413
        FileHandleCloseWrap::from_req(req));
414
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
415
    handle->AfterClose();
416
417
    int result = req->result;
418
    uv_fs_req_cleanup(req);
419
    wrap->Done(result);
420
  }});
421
422
  return 0;
423
}
424
425
426
1775
void FSReqCallback::Reject(Local<Value> reject) {
427
1775
  MakeCallback(env()->oncomplete_string(), 1, &reject);
428
1775
}
429
430
592
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
431
592
  Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
432
592
}
433
434
5194
void FSReqCallback::Resolve(Local<Value> value) {
435
  Local<Value> argv[2] {
436
    Null(env()->isolate()),
437
    value
438
10388
  };
439
  MakeCallback(env()->oncomplete_string(),
440
13494
               value->IsUndefined() ? 1 : arraysize(argv),
441
8300
               argv);
442
5194
}
443
444
6969
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
445
13938
  args.GetReturnValue().SetUndefined();
446
6969
}
447
448
6969
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
449
6969
  CHECK(args.IsConstructCall());
450
6969
  Environment* env = Environment::GetCurrent(args);
451
20907
  new FSReqCallback(env, args.This(), args[0]->IsTrue());
452
6969
}
453
454
7064
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
455
    : wrap_(wrap),
456
      req_(req),
457
      handle_scope_(wrap->env()->isolate()),
458
7064
      context_scope_(wrap->env()->context()) {
459
7064
  CHECK_EQ(wrap_->req(), req);
460
7064
}
461
462
21192
FSReqAfterScope::~FSReqAfterScope() {
463
7064
  uv_fs_req_cleanup(wrap_->req());
464
7064
  delete wrap_;
465
7064
}
466
467
// TODO(joyeecheung): create a normal context object, and
468
// construct the actual errors in the JS land using the context.
469
// The context should include fds for some fs APIs, currently they are
470
// missing in the error messages. The path, dest, syscall, fd, .etc
471
// can be put into the context before the binding is even invoked,
472
// the only information that has to come from the C++ layer is the
473
// error number (and possibly the syscall for abstraction),
474
// which is also why the errors should have been constructed
475
// in JS for more flexibility.
476
1787
void FSReqAfterScope::Reject(uv_fs_t* req) {
477
  wrap_->Reject(UVException(wrap_->env()->isolate(),
478
                            req->result,
479
                            wrap_->syscall(),
480
                            nullptr,
481
                            req->path,
482
1787
                            wrap_->data()));
483
1787
}
484
485
7064
bool FSReqAfterScope::Proceed() {
486
7064
  if (req_->result < 0) {
487
1787
    Reject(req_);
488
1787
    return false;
489
  }
490
5277
  return true;
491
}
492
493
2104
void AfterNoArgs(uv_fs_t* req) {
494
2104
  FSReqBase* req_wrap = FSReqBase::from_req(req);
495
2104
  FSReqAfterScope after(req_wrap, req);
496
497
2104
  if (after.Proceed())
498
4176
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
499
2104
}
500
501
2429
void AfterStat(uv_fs_t* req) {
502
2429
  FSReqBase* req_wrap = FSReqBase::from_req(req);
503
2429
  FSReqAfterScope after(req_wrap, req);
504
505
2429
  if (after.Proceed()) {
506
672
    req_wrap->ResolveStat(&req->statbuf);
507
2429
  }
508
2429
}
509
510
2518
void AfterInteger(uv_fs_t* req) {
511
2518
  FSReqBase* req_wrap = FSReqBase::from_req(req);
512
2518
  FSReqAfterScope after(req_wrap, req);
513
514
2518
  if (after.Proceed())
515
5016
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
516
2518
}
517
518
void AfterOpenFileHandle(uv_fs_t* req) {
519
  FSReqBase* req_wrap = FSReqBase::from_req(req);
520
  FSReqAfterScope after(req_wrap, req);
521
522
  if (after.Proceed()) {
523
    FileHandle* fd = new FileHandle(req_wrap->env(), req->result);
524
    req_wrap->Resolve(fd->object());
525
  }
526
}
527
528
void AfterStringPath(uv_fs_t* req) {
529
  FSReqBase* req_wrap = FSReqBase::from_req(req);
530
  FSReqAfterScope after(req_wrap, req);
531
532
  MaybeLocal<Value> link;
533
  Local<Value> error;
534
535
  if (after.Proceed()) {
536
    link = StringBytes::Encode(req_wrap->env()->isolate(),
537
                               static_cast<const char*>(req->path),
538
                               req_wrap->encoding(),
539
                               &error);
540
    if (link.IsEmpty())
541
      req_wrap->Reject(error);
542
    else
543
      req_wrap->Resolve(link.ToLocalChecked());
544
  }
545
}
546
547
4
void AfterStringPtr(uv_fs_t* req) {
548
4
  FSReqBase* req_wrap = FSReqBase::from_req(req);
549
4
  FSReqAfterScope after(req_wrap, req);
550
551
  MaybeLocal<Value> link;
552
  Local<Value> error;
553
554
4
  if (after.Proceed()) {
555
    link = StringBytes::Encode(req_wrap->env()->isolate(),
556
                               static_cast<const char*>(req->ptr),
557
                               req_wrap->encoding(),
558
                               &error);
559
    if (link.IsEmpty())
560
      req_wrap->Reject(error);
561
    else
562
      req_wrap->Resolve(link.ToLocalChecked());
563
4
  }
564
4
}
565
566
9
void AfterScanDir(uv_fs_t* req) {
567
9
  FSReqBase* req_wrap = FSReqBase::from_req(req);
568
9
  FSReqAfterScope after(req_wrap, req);
569
570
9
  if (!after.Proceed()) {
571
    return;
572
  }
573
9
  Environment* env = req_wrap->env();
574
  Local<Value> error;
575
  int r;
576
18
  std::vector<Local<Value>> name_v;
577
578
152
  for (int i = 0; ; i++) {
579
    uv_dirent_t ent;
580
581
152
    r = uv_fs_scandir_next(req, &ent);
582
152
    if (r == UV_EOF)
583
9
      break;
584
143
    if (r != 0) {
585
      return req_wrap->Reject(
586
          UVException(r, nullptr, req_wrap->syscall(),
587
            static_cast<const char*>(req->path)));
588
    }
589
590
    MaybeLocal<Value> filename =
591
      StringBytes::Encode(env->isolate(),
592
          ent.name,
593
          req_wrap->encoding(),
594
143
          &error);
595
143
    if (filename.IsEmpty())
596
      return req_wrap->Reject(error);
597
598
143
    name_v.push_back(filename.ToLocalChecked());
599
143
  }
600
601
27
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
602
}
603
604
void AfterScanDirWithTypes(uv_fs_t* req) {
605
  FSReqBase* req_wrap = FSReqBase::from_req(req);
606
  FSReqAfterScope after(req_wrap, req);
607
608
  if (!after.Proceed()) {
609
    return;
610
  }
611
612
  Environment* env = req_wrap->env();
613
  Isolate* isolate = env->isolate();
614
  Local<Value> error;
615
  int r;
616
617
  std::vector<Local<Value>> name_v;
618
  std::vector<Local<Value>> type_v;
619
620
  for (int i = 0; ; i++) {
621
    uv_dirent_t ent;
622
623
    r = uv_fs_scandir_next(req, &ent);
624
    if (r == UV_EOF)
625
      break;
626
    if (r != 0) {
627
      return req_wrap->Reject(
628
          UVException(r, nullptr, req_wrap->syscall(),
629
            static_cast<const char*>(req->path)));
630
    }
631
632
    MaybeLocal<Value> filename =
633
      StringBytes::Encode(isolate,
634
          ent.name,
635
          req_wrap->encoding(),
636
          &error);
637
    if (filename.IsEmpty())
638
      return req_wrap->Reject(error);
639
640
    name_v.push_back(filename.ToLocalChecked());
641
    type_v.push_back(Integer::New(isolate, ent.type));
642
  }
643
644
  Local<Array> result = Array::New(isolate, 2);
645
  result->Set(env->context(),
646
              0,
647
              Array::New(isolate, name_v.data(),
648
              name_v.size())).FromJust();
649
  result->Set(env->context(),
650
              1,
651
              Array::New(isolate, type_v.data(),
652
              type_v.size())).FromJust();
653
  req_wrap->Resolve(result);
654
}
655
656
657
// This class is only used on sync fs calls.
658
// For async calls FSReqCallback is used.
659
class FSReqWrapSync {
660
 public:
661
62980
  FSReqWrapSync() {}
662
62980
  ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
663
  uv_fs_t req;
664
665
 private:
666
  DISALLOW_COPY_AND_ASSIGN(FSReqWrapSync);
667
};
668
669
// Returns nullptr if the operation fails from the start.
670
template <typename Func, typename... Args>
671
7064
inline FSReqBase* AsyncDestCall(Environment* env,
672
    FSReqBase* req_wrap,
673
    const FunctionCallbackInfo<Value>& args,
674
    const char* syscall, const char* dest, size_t len,
675
    enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
676







7064
  CHECK_NOT_NULL(req_wrap);
677
7064
  req_wrap->Init(syscall, dest, len, enc);
678
7064
  int err = req_wrap->Dispatch(fn, fn_args..., after);
679







7064
  if (err < 0) {
680
    uv_fs_t* uv_req = req_wrap->req();
681
    uv_req->result = err;
682
    uv_req->path = nullptr;
683
    after(uv_req);  // after may delete req_wrap if there is an error
684
    req_wrap = nullptr;
685
  } else {
686
7064
    req_wrap->SetReturnValue(args);
687
  }
688
689
7064
  return req_wrap;
690
}
691
692
// Returns nullptr if the operation fails from the start.
693
template <typename Func, typename... Args>
694
7060
inline FSReqBase* AsyncCall(Environment* env,
695
    FSReqBase* req_wrap,
696
    const FunctionCallbackInfo<Value>& args,
697
    const char* syscall, enum encoding enc,
698
    uv_fs_cb after, Func fn, Args... fn_args) {
699
  return AsyncDestCall(env, req_wrap, args,
700
                       syscall, nullptr, 0, enc,
701
7060
                       after, fn, fn_args...);
702
}
703
704
// Template counterpart of SYNC_CALL, except that it only puts
705
// the error number and the syscall in the context instead of
706
// creating an error in the C++ land.
707
// ctx must be checked using value->IsObject() before being passed.
708
template <typename Func, typename... Args>
709
62980
inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap,
710
    const char* syscall, Func fn, Args... args) {
711
62980
  env->PrintSyncTrace();
712
62980
  int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
713







62980
  if (err < 0) {
714
136
    Local<Context> context = env->context();
715
136
    Local<Object> ctx_obj = ctx.As<Object>();
716
136
    Isolate* isolate = env->isolate();
717
    ctx_obj->Set(context,
718
             env->errno_string(),
719
544
             Integer::New(isolate, err)).FromJust();
720
    ctx_obj->Set(context,
721
             env->syscall_string(),
722
544
             OneByteString(isolate, syscall)).FromJust();
723
  }
724
62980
  return err;
725
}
726
727
70044
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
728
                             bool use_bigint = false) {
729
70044
  if (value->IsObject()) {
730
6969
    return Unwrap<FSReqBase>(value.As<Object>());
731
126150
  } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
732
95
    if (use_bigint) {
733
      return new FSReqPromise<uint64_t, BigUint64Array>(env, use_bigint);
734
    } else {
735
95
      return new FSReqPromise<double, Float64Array>(env, use_bigint);
736
    }
737
  }
738
62980
  return nullptr;
739
}
740
741
37
void Access(const FunctionCallbackInfo<Value>& args) {
742
37
  Environment* env = Environment::GetCurrent(args);
743
37
  Isolate* isolate = env->isolate();
744
37
  HandleScope scope(isolate);
745
746
37
  const int argc = args.Length();
747
37
  CHECK_GE(argc, 2);
748
749
74
  CHECK(args[1]->IsInt32());
750
111
  int mode = args[1].As<Int32>()->Value();
751
752
74
  BufferValue path(isolate, args[0]);
753
37
  CHECK_NOT_NULL(*path);
754
755
37
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
756
37
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
757
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
758
              uv_fs_access, *path, mode);
759
  } else {  // access(path, mode, undefined, ctx)
760
37
    CHECK_EQ(argc, 4);
761
37
    FSReqWrapSync req_wrap_sync;
762

37
    FS_SYNC_TRACE_BEGIN(access);
763
74
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
764

37
    FS_SYNC_TRACE_END(access);
765
37
  }
766
37
}
767
768
769
12101
void Close(const FunctionCallbackInfo<Value>& args) {
770
12101
  Environment* env = Environment::GetCurrent(args);
771
772
12101
  const int argc = args.Length();
773
12101
  CHECK_GE(argc, 2);
774
775
24202
  CHECK(args[0]->IsInt32());
776
36303
  int fd = args[0].As<Int32>()->Value();
777
778
12101
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
779
12101
  if (req_wrap_async != nullptr) {  // close(fd, req)
780
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
781
1120
              uv_fs_close, fd);
782
  } else {  // close(fd, undefined, ctx)
783
10981
    CHECK_EQ(argc, 3);
784
10981
    FSReqWrapSync req_wrap_sync;
785

10981
    FS_SYNC_TRACE_BEGIN(close);
786
10981
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
787

10981
    FS_SYNC_TRACE_END(close);
788
  }
789
12101
}
790
791
792
// Used to speed up module loading.  Returns the contents of the file as
793
// a string or undefined when the file cannot be opened or "main" is not found
794
// in the file.
795
5411
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
796
5411
  Environment* env = Environment::GetCurrent(args);
797
5411
  Isolate* isolate = env->isolate();
798
5411
  uv_loop_t* loop = env->event_loop();
799
800
16233
  CHECK(args[0]->IsString());
801
5411
  node::Utf8Value path(isolate, args[0]);
802
803
5411
  if (strlen(*path) != path.length())
804
    return;  // Contains a nul byte.
805
806
  uv_fs_t open_req;
807
5411
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
808
5411
  uv_fs_req_cleanup(&open_req);
809
810
5411
  if (fd < 0) {
811
60
    return;
812
  }
813
814
5351
  std::shared_ptr<void> defer_close(nullptr, [fd, loop] (...) {
815
    uv_fs_t close_req;
816
5351
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
817
5351
    uv_fs_req_cleanup(&close_req);
818
14362
  });
819
820
5351
  const size_t kBlockSize = 32 << 10;
821
9011
  std::vector<char> chars;
822
5351
  int64_t offset = 0;
823
  ssize_t numchars;
824
5351
  do {
825
5351
    const size_t start = chars.size();
826
5351
    chars.resize(start + kBlockSize);
827
828
    uv_buf_t buf;
829
5351
    buf.base = &chars[start];
830
5351
    buf.len = kBlockSize;
831
832
    uv_fs_t read_req;
833
5351
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
834
5351
    uv_fs_req_cleanup(&read_req);
835
836
5351
    if (numchars < 0)
837
      return;
838
839
5351
    offset += numchars;
840
  } while (static_cast<size_t>(numchars) == kBlockSize);
841
842
5351
  size_t start = 0;
843

5351
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
844
    start = 3;  // Skip UTF-8 BOM.
845
  }
846
847
5351
  const size_t size = offset - start;
848

5351
  if (size == 0 || size == SearchString(&chars[start], size, "\"main\"")) {
849
1691
    return;
850
  } else {
851
    Local<String> chars_string =
852
        String::NewFromUtf8(isolate,
853
3660
                            &chars[start],
854
                            v8::NewStringType::kNormal,
855
10980
                            size).ToLocalChecked();
856
7320
    args.GetReturnValue().Set(chars_string);
857
3660
  }
858
}
859
860
// Used to speed up module loading.  Returns 0 if the path refers to
861
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
862
// The speedup comes from not creating thousands of Stat and Error objects.
863
73232
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
864
73232
  Environment* env = Environment::GetCurrent(args);
865
866
219696
  CHECK(args[0]->IsString());
867
73232
  node::Utf8Value path(env->isolate(), args[0]);
868
869
  uv_fs_t req;
870
73232
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
871
73232
  if (rc == 0) {
872
34078
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
873
34078
    rc = !!(s->st_mode & S_IFDIR);
874
  }
875
73232
  uv_fs_req_cleanup(&req);
876
877
146464
  args.GetReturnValue().Set(rc);
878
73232
}
879
880
1310
static void Stat(const FunctionCallbackInfo<Value>& args) {
881
1310
  Environment* env = Environment::GetCurrent(args);
882
883
1310
  const int argc = args.Length();
884
1310
  CHECK_GE(argc, 2);
885
886
1310
  BufferValue path(env->isolate(), args[0]);
887
1310
  CHECK_NOT_NULL(*path);
888
889
2620
  bool use_bigint = args[1]->IsTrue();
890
2620
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
891
1310
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
892
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
893
1123
              uv_fs_stat, *path);
894
  } else {  // stat(path, use_bigint, undefined, ctx)
895
187
    CHECK_EQ(argc, 4);
896
187
    FSReqWrapSync req_wrap_sync;
897

187
    FS_SYNC_TRACE_BEGIN(stat);
898
374
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
899

187
    FS_SYNC_TRACE_END(stat);
900
187
    if (err != 0) {
901
1310
      return;  // error info is in ctx
902
    }
903
904
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
905
187
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
906

374
    args.GetReturnValue().Set(arr);
907
1310
  }
908
}
909
910
19467
static void LStat(const FunctionCallbackInfo<Value>& args) {
911
19467
  Environment* env = Environment::GetCurrent(args);
912
913
19467
  const int argc = args.Length();
914
19467
  CHECK_GE(argc, 3);
915
916
19467
  BufferValue path(env->isolate(), args[0]);
917
19467
  CHECK_NOT_NULL(*path);
918
919
38934
  bool use_bigint = args[1]->IsTrue();
920
38934
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
921
19467
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
922
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
923
1112
              uv_fs_lstat, *path);
924
  } else {  // lstat(path, use_bigint, undefined, ctx)
925
18355
    CHECK_EQ(argc, 4);
926
18355
    FSReqWrapSync req_wrap_sync;
927

18355
    FS_SYNC_TRACE_BEGIN(lstat);
928
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
929
36710
                       *path);
930

18355
    FS_SYNC_TRACE_END(lstat);
931
18355
    if (err != 0) {
932
19467
      return;  // error info is in ctx
933
    }
934
935
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
936
18355
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
937

36710
    args.GetReturnValue().Set(arr);
938
19467
  }
939
}
940
941
10847
static void FStat(const FunctionCallbackInfo<Value>& args) {
942
10847
  Environment* env = Environment::GetCurrent(args);
943
944
10847
  const int argc = args.Length();
945
10847
  CHECK_GE(argc, 2);
946
947
21694
  CHECK(args[0]->IsInt32());
948
32541
  int fd = args[0].As<Int32>()->Value();
949
950
21694
  bool use_bigint = args[1]->IsTrue();
951
21694
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
952
10847
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
953
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
954
194
              uv_fs_fstat, fd);
955
  } else {  // fstat(fd, use_bigint, undefined, ctx)
956
10653
    CHECK_EQ(argc, 4);
957
10653
    FSReqWrapSync req_wrap_sync;
958

10653
    FS_SYNC_TRACE_BEGIN(fstat);
959
10653
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
960

10653
    FS_SYNC_TRACE_END(fstat);
961
10653
    if (err != 0) {
962
10847
      return;  // error info is in ctx
963
    }
964
965
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
966
10653
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
967
21306
    args.GetReturnValue().Set(arr);
968
  }
969
}
970
971
4
static void Symlink(const FunctionCallbackInfo<Value>& args) {
972
4
  Environment* env = Environment::GetCurrent(args);
973
4
  Isolate* isolate = env->isolate();
974
975
4
  int argc = args.Length();
976
4
  CHECK_GE(argc, 4);
977
978
4
  BufferValue target(isolate, args[0]);
979
4
  CHECK_NOT_NULL(*target);
980
8
  BufferValue path(isolate, args[1]);
981
4
  CHECK_NOT_NULL(*path);
982
983
8
  CHECK(args[2]->IsInt32());
984
12
  int flags = args[2].As<Int32>()->Value();
985
986
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
987
4
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
988
4
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
989
8
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
990
  } else {  // symlink(target, path, flags, undefinec, ctx)
991
    CHECK_EQ(argc, 5);
992
    FSReqWrapSync req_wrap_sync;
993
    FS_SYNC_TRACE_BEGIN(symlink);
994
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
995
             uv_fs_symlink, *target, *path, flags);
996
    FS_SYNC_TRACE_END(symlink);
997
4
  }
998
4
}
999
1000
static void Link(const FunctionCallbackInfo<Value>& args) {
1001
  Environment* env = Environment::GetCurrent(args);
1002
  Isolate* isolate = env->isolate();
1003
1004
  int argc = args.Length();
1005
  CHECK_GE(argc, 3);
1006
1007
  BufferValue src(isolate, args[0]);
1008
  CHECK_NOT_NULL(*src);
1009
1010
  BufferValue dest(isolate, args[1]);
1011
  CHECK_NOT_NULL(*dest);
1012
1013
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1014
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1015
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1016
                  AfterNoArgs, uv_fs_link, *src, *dest);
1017
  } else {  // link(src, dest)
1018
    CHECK_EQ(argc, 4);
1019
    FSReqWrapSync req_wrap_sync;
1020
    FS_SYNC_TRACE_BEGIN(link);
1021
    SyncCall(env, args[3], &req_wrap_sync, "link",
1022
             uv_fs_link, *src, *dest);
1023
    FS_SYNC_TRACE_END(link);
1024
  }
1025
}
1026
1027
5
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1028
5
  Environment* env = Environment::GetCurrent(args);
1029
5
  Isolate* isolate = env->isolate();
1030
1031
5
  int argc = args.Length();
1032
5
  CHECK_GE(argc, 3);
1033
1034
5
  BufferValue path(isolate, args[0]);
1035
5
  CHECK_NOT_NULL(*path);
1036
1037
5
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1038
1039
5
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1040
5
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1041
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1042
4
              uv_fs_readlink, *path);
1043
  } else {
1044
1
    CHECK_EQ(argc, 4);
1045
1
    FSReqWrapSync req_wrap_sync;
1046

1
    FS_SYNC_TRACE_BEGIN(readlink);
1047
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1048
2
                       uv_fs_readlink, *path);
1049

1
    FS_SYNC_TRACE_END(readlink);
1050
1
    if (err < 0) {
1051
      return;  // syscall failed, no need to continue, error info is in ctx
1052
    }
1053
1
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1054
1055
    Local<Value> error;
1056
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1057
                                               link_path,
1058
                                               encoding,
1059
1
                                               &error);
1060
1
    if (rc.IsEmpty()) {
1061
      Local<Object> ctx = args[3].As<Object>();
1062
      ctx->Set(env->context(), env->error_string(), error).FromJust();
1063
      return;
1064
    }
1065
1066

2
    args.GetReturnValue().Set(rc.ToLocalChecked());
1067
5
  }
1068
}
1069
1070
static void Rename(const FunctionCallbackInfo<Value>& args) {
1071
  Environment* env = Environment::GetCurrent(args);
1072
  Isolate* isolate = env->isolate();
1073
1074
  int argc = args.Length();
1075
  CHECK_GE(argc, 3);
1076
1077
  BufferValue old_path(isolate, args[0]);
1078
  CHECK_NOT_NULL(*old_path);
1079
  BufferValue new_path(isolate, args[1]);
1080
  CHECK_NOT_NULL(*new_path);
1081
1082
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1083
  if (req_wrap_async != nullptr) {
1084
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1085
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1086
                  *old_path, *new_path);
1087
  } else {
1088
    CHECK_EQ(argc, 4);
1089
    FSReqWrapSync req_wrap_sync;
1090
    FS_SYNC_TRACE_BEGIN(rename);
1091
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1092
             *old_path, *new_path);
1093
    FS_SYNC_TRACE_END(rename);
1094
  }
1095
}
1096
1097
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1098
  Environment* env = Environment::GetCurrent(args);
1099
1100
  const int argc = args.Length();
1101
  CHECK_GE(argc, 3);
1102
1103
  CHECK(args[0]->IsInt32());
1104
  const int fd = args[0].As<Int32>()->Value();
1105
1106
  CHECK(args[1]->IsNumber());
1107
  const int64_t len = args[1].As<Integer>()->Value();
1108
1109
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1110
  if (req_wrap_async != nullptr) {
1111
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1112
              uv_fs_ftruncate, fd, len);
1113
  } else {
1114
    CHECK_EQ(argc, 4);
1115
    FSReqWrapSync req_wrap_sync;
1116
    FS_SYNC_TRACE_BEGIN(ftruncate);
1117
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1118
             len);
1119
    FS_SYNC_TRACE_END(ftruncate);
1120
  }
1121
}
1122
1123
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1124
  Environment* env = Environment::GetCurrent(args);
1125
1126
  const int argc = args.Length();
1127
  CHECK_GE(argc, 2);
1128
1129
  CHECK(args[0]->IsInt32());
1130
  const int fd = args[0].As<Int32>()->Value();
1131
1132
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1133
  if (req_wrap_async != nullptr) {
1134
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1135
              uv_fs_fdatasync, fd);
1136
  } else {
1137
    CHECK_EQ(argc, 3);
1138
    FSReqWrapSync req_wrap_sync;
1139
    FS_SYNC_TRACE_BEGIN(fdatasync);
1140
    SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1141
    FS_SYNC_TRACE_END(fdatasync);
1142
  }
1143
}
1144
1145
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1146
  Environment* env = Environment::GetCurrent(args);
1147
1148
  const int argc = args.Length();
1149
  CHECK_GE(argc, 2);
1150
1151
  CHECK(args[0]->IsInt32());
1152
  const int fd = args[0].As<Int32>()->Value();
1153
1154
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1155
  if (req_wrap_async != nullptr) {
1156
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1157
              uv_fs_fsync, fd);
1158
  } else {
1159
    CHECK_EQ(argc, 3);
1160
    FSReqWrapSync req_wrap_sync;
1161
    FS_SYNC_TRACE_BEGIN(fsync);
1162
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1163
    FS_SYNC_TRACE_END(fsync);
1164
  }
1165
}
1166
1167
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1168
  Environment* env = Environment::GetCurrent(args);
1169
1170
  const int argc = args.Length();
1171
  CHECK_GE(argc, 2);
1172
1173
  BufferValue path(env->isolate(), args[0]);
1174
  CHECK_NOT_NULL(*path);
1175
1176
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1177
  if (req_wrap_async != nullptr) {
1178
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1179
              uv_fs_unlink, *path);
1180
  } else {
1181
    CHECK_EQ(argc, 3);
1182
    FSReqWrapSync req_wrap_sync;
1183
    FS_SYNC_TRACE_BEGIN(unlink);
1184
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1185
    FS_SYNC_TRACE_END(unlink);
1186
  }
1187
}
1188
1189
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1190
  Environment* env = Environment::GetCurrent(args);
1191
1192
  const int argc = args.Length();
1193
  CHECK_GE(argc, 2);
1194
1195
  BufferValue path(env->isolate(), args[0]);
1196
  CHECK_NOT_NULL(*path);
1197
1198
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1199
  if (req_wrap_async != nullptr) {
1200
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1201
              uv_fs_rmdir, *path);
1202
  } else {  // rmdir(path, undefined, ctx)
1203
    CHECK_EQ(argc, 3);
1204
    FSReqWrapSync req_wrap_sync;
1205
    FS_SYNC_TRACE_BEGIN(rmdir);
1206
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1207
             uv_fs_rmdir, *path);
1208
    FS_SYNC_TRACE_END(rmdir);
1209
  }
1210
}
1211
1212
163
int MKDirpSync(uv_loop_t* loop, uv_fs_t* req, const std::string& path, int mode,
1213
               uv_fs_cb cb = nullptr) {
1214
163
  FSContinuationData continuation_data(req, mode, cb);
1215
163
  continuation_data.PushPath(std::move(path));
1216
1217
163
  while (continuation_data.paths.size() > 0) {
1218
167
    std::string next_path = continuation_data.PopPath();
1219
167
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1220
    while (true) {
1221

167
      switch (err) {
1222
        case 0:
1223
4
          if (continuation_data.paths.size() == 0) {
1224
2
            return 0;
1225
          }
1226
2
          break;
1227
        case UV_ENOENT: {
1228
          std::string dirname = next_path.substr(0,
1229
2
                                        next_path.find_last_of(kPathSeparator));
1230
2
          if (dirname != next_path) {
1231
2
            continuation_data.PushPath(std::move(next_path));
1232
2
            continuation_data.PushPath(std::move(dirname));
1233
          } else if (continuation_data.paths.size() == 0) {
1234
            err = UV_EEXIST;
1235
            continue;
1236
          }
1237
2
          break;
1238
        }
1239
        case UV_EPERM: {
1240
          return err;
1241
        }
1242
        default:
1243
161
          uv_fs_req_cleanup(req);
1244
161
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1245

161
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) return UV_EEXIST;
1246
161
          if (err < 0) return err;
1247
161
          break;
1248
      }
1249
165
      break;
1250
    }
1251
165
    uv_fs_req_cleanup(req);
1252
165
  }
1253
1254
161
  return 0;
1255
}
1256
1257
int MKDirpAsync(uv_loop_t* loop,
1258
                uv_fs_t* req,
1259
                const char* path,
1260
                int mode,
1261
                uv_fs_cb cb) {
1262
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1263
  // on the first iteration of algorithm, stash state information.
1264
  if (req_wrap->continuation_data == nullptr) {
1265
    req_wrap->continuation_data = std::unique_ptr<FSContinuationData>{
1266
      new FSContinuationData(req, mode, cb)};
1267
    req_wrap->continuation_data->PushPath(std::move(path));
1268
  }
1269
1270
  // on each iteration of algorithm, mkdir directory on top of stack.
1271
  std::string next_path = req_wrap->continuation_data->PopPath();
1272
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1273
                        uv_fs_callback_t{[](uv_fs_t* req) {
1274
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1275
    Environment* env = req_wrap->env();
1276
    uv_loop_t* loop = env->event_loop();
1277
    std::string path = req->path;
1278
    int err = req->result;
1279
1280
    while (true) {
1281
      switch (err) {
1282
        case 0: {
1283
          if (req_wrap->continuation_data->paths.size() == 0) {
1284
            req_wrap->continuation_data->Done(0);
1285
          } else {
1286
            uv_fs_req_cleanup(req);
1287
            MKDirpAsync(loop, req, path.c_str(),
1288
                        req_wrap->continuation_data->mode, nullptr);
1289
          }
1290
          break;
1291
        }
1292
        case UV_ENOENT: {
1293
          std::string dirname = path.substr(0,
1294
                                            path.find_last_of(kPathSeparator));
1295
          if (dirname != path) {
1296
            req_wrap->continuation_data->PushPath(std::move(path));
1297
            req_wrap->continuation_data->PushPath(std::move(dirname));
1298
          } else if (req_wrap->continuation_data->paths.size() == 0) {
1299
            err = UV_EEXIST;
1300
            continue;
1301
          }
1302
          uv_fs_req_cleanup(req);
1303
          MKDirpAsync(loop, req, path.c_str(),
1304
                      req_wrap->continuation_data->mode, nullptr);
1305
          break;
1306
        }
1307
        case UV_EPERM: {
1308
          req_wrap->continuation_data->Done(err);
1309
          break;
1310
        }
1311
        default:
1312
          if (err == UV_EEXIST &&
1313
              req_wrap->continuation_data->paths.size() > 0) {
1314
            uv_fs_req_cleanup(req);
1315
            MKDirpAsync(loop, req, path.c_str(),
1316
                        req_wrap->continuation_data->mode, nullptr);
1317
          } else {
1318
            // verify that the path pointed to is actually a directory.
1319
            uv_fs_req_cleanup(req);
1320
            int err = uv_fs_stat(loop, req, path.c_str(),
1321
                                 uv_fs_callback_t{[](uv_fs_t* req) {
1322
              FSReqBase* req_wrap = FSReqBase::from_req(req);
1323
              int err = req->result;
1324
              if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1325
              req_wrap->continuation_data->Done(err);
1326
            }});
1327
            if (err < 0) req_wrap->continuation_data->Done(err);
1328
          }
1329
          break;
1330
      }
1331
      break;
1332
    }
1333
  }});
1334
1335
  return err;
1336
}
1337
1338
543
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1339
543
  Environment* env = Environment::GetCurrent(args);
1340
1341
543
  const int argc = args.Length();
1342
543
  CHECK_GE(argc, 4);
1343
1344
543
  BufferValue path(env->isolate(), args[0]);
1345
543
  CHECK_NOT_NULL(*path);
1346
1347
1086
  CHECK(args[1]->IsInt32());
1348
1629
  const int mode = args[1].As<Int32>()->Value();
1349
1350
1086
  CHECK(args[2]->IsBoolean());
1351
1086
  bool mkdirp = args[2]->IsTrue();
1352
1353
543
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1354
543
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1355
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1356
267
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1357
  } else {  // mkdir(path, mode, undefined, ctx)
1358
276
    CHECK_EQ(argc, 5);
1359
276
    FSReqWrapSync req_wrap_sync;
1360

276
    FS_SYNC_TRACE_BEGIN(mkdir);
1361
276
    if (mkdirp) {
1362
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1363
326
               MKDirpSync, *path, mode);
1364
    } else {
1365
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1366
226
               uv_fs_mkdir, *path, mode);
1367
    }
1368

276
    FS_SYNC_TRACE_END(mkdir);
1369
543
  }
1370
543
}
1371
1372
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1373
  Environment* env = Environment::GetCurrent(args);
1374
  Isolate* isolate = env->isolate();
1375
1376
  const int argc = args.Length();
1377
  CHECK_GE(argc, 3);
1378
1379
  BufferValue path(isolate, args[0]);
1380
  CHECK_NOT_NULL(*path);
1381
1382
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1383
1384
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1385
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1386
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1387
              uv_fs_realpath, *path);
1388
  } else {  // realpath(path, encoding, undefined, ctx)
1389
    CHECK_EQ(argc, 4);
1390
    FSReqWrapSync req_wrap_sync;
1391
    FS_SYNC_TRACE_BEGIN(realpath);
1392
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1393
                       uv_fs_realpath, *path);
1394
    FS_SYNC_TRACE_END(realpath);
1395
    if (err < 0) {
1396
      return;  // syscall failed, no need to continue, error info is in ctx
1397
    }
1398
1399
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1400
1401
    Local<Value> error;
1402
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1403
                                               link_path,
1404
                                               encoding,
1405
                                               &error);
1406
    if (rc.IsEmpty()) {
1407
      Local<Object> ctx = args[3].As<Object>();
1408
      ctx->Set(env->context(), env->error_string(), error).FromJust();
1409
      return;
1410
    }
1411
1412
    args.GetReturnValue().Set(rc.ToLocalChecked());
1413
  }
1414
}
1415
1416
12
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1417
12
  Environment* env = Environment::GetCurrent(args);
1418
12
  Isolate* isolate = env->isolate();
1419
1420
12
  const int argc = args.Length();
1421
12
  CHECK_GE(argc, 3);
1422
1423
12
  BufferValue path(isolate, args[0]);
1424
12
  CHECK_NOT_NULL(*path);
1425
1426
12
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1427
1428
24
  bool with_types = args[2]->IsTrue();
1429
1430
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1431
12
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1432
9
    if (with_types) {
1433
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1434
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1435
    } else {
1436
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1437
9
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1438
    }
1439
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1440
3
    CHECK_EQ(argc, 5);
1441
3
    FSReqWrapSync req_wrap_sync;
1442

3
    FS_SYNC_TRACE_BEGIN(readdir);
1443
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1444
6
                       uv_fs_scandir, *path, 0 /*flags*/);
1445

3
    FS_SYNC_TRACE_END(readdir);
1446
3
    if (err < 0) {
1447
      return;  // syscall failed, no need to continue, error info is in ctx
1448
    }
1449
1450
3
    CHECK_GE(req_wrap_sync.req.result, 0);
1451
    int r;
1452
6
    std::vector<Local<Value>> name_v;
1453
6
    std::vector<Local<Value>> type_v;
1454
1455
164
    for (int i = 0; ; i++) {
1456
      uv_dirent_t ent;
1457
1458
164
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1459
164
      if (r == UV_EOF)
1460
3
        break;
1461
161
      if (r != 0) {
1462
        Local<Object> ctx = args[4].As<Object>();
1463
        ctx->Set(env->context(), env->errno_string(),
1464
                 Integer::New(isolate, r)).FromJust();
1465
        ctx->Set(env->context(), env->syscall_string(),
1466
                 OneByteString(isolate, "readdir")).FromJust();
1467
        return;
1468
      }
1469
1470
      Local<Value> error;
1471
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1472
                                                       ent.name,
1473
                                                       encoding,
1474
161
                                                       &error);
1475
1476
161
      if (filename.IsEmpty()) {
1477
        Local<Object> ctx = args[4].As<Object>();
1478
        ctx->Set(env->context(), env->error_string(), error).FromJust();
1479
        return;
1480
      }
1481
1482
161
      name_v.push_back(filename.ToLocalChecked());
1483
1484
161
      if (with_types) {
1485
        type_v.push_back(Integer::New(isolate, ent.type));
1486
      }
1487
161
    }
1488
1489
1490
3
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1491
3
    if (with_types) {
1492
      Local<Array> result = Array::New(isolate, 2);
1493
      result->Set(env->context(), 0, names).FromJust();
1494
      result->Set(env->context(),
1495
                  1,
1496
                  Array::New(isolate, type_v.data(),
1497
                             type_v.size())).FromJust();
1498
      args.GetReturnValue().Set(result);
1499
    } else {
1500
6
      args.GetReturnValue().Set(names);
1501
3
    }
1502
12
  }
1503
}
1504
1505
12114
static void Open(const FunctionCallbackInfo<Value>& args) {
1506
12114
  Environment* env = Environment::GetCurrent(args);
1507
1508
12114
  const int argc = args.Length();
1509
12114
  CHECK_GE(argc, 3);
1510
1511
12114
  BufferValue path(env->isolate(), args[0]);
1512
12114
  CHECK_NOT_NULL(*path);
1513
1514
24228
  CHECK(args[1]->IsInt32());
1515
36342
  const int flags = args[1].As<Int32>()->Value();
1516
1517
24228
  CHECK(args[2]->IsInt32());
1518
36342
  const int mode = args[2].As<Int32>()->Value();
1519
1520
12114
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1521
12114
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1522
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1523
1130
              uv_fs_open, *path, flags, mode);
1524
  } else {  // open(path, flags, mode, undefined, ctx)
1525
10984
    CHECK_EQ(argc, 5);
1526
10984
    FSReqWrapSync req_wrap_sync;
1527

10984
    FS_SYNC_TRACE_BEGIN(open);
1528
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1529
21968
                          uv_fs_open, *path, flags, mode);
1530

10984
    FS_SYNC_TRACE_END(open);
1531
21968
    args.GetReturnValue().Set(result);
1532
12114
  }
1533
12114
}
1534
1535
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1536
  Environment* env = Environment::GetCurrent(args);
1537
  Isolate* isolate = env->isolate();
1538
1539
  const int argc = args.Length();
1540
  CHECK_GE(argc, 3);
1541
1542
  BufferValue path(isolate, args[0]);
1543
  CHECK_NOT_NULL(*path);
1544
1545
  CHECK(args[1]->IsInt32());
1546
  const int flags = args[1].As<Int32>()->Value();
1547
1548
  CHECK(args[2]->IsInt32());
1549
  const int mode = args[2].As<Int32>()->Value();
1550
1551
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1552
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1553
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1554
              uv_fs_open, *path, flags, mode);
1555
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1556
    CHECK_EQ(argc, 5);
1557
    FSReqWrapSync req_wrap_sync;
1558
    FS_SYNC_TRACE_BEGIN(open);
1559
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1560
                          uv_fs_open, *path, flags, mode);
1561
    FS_SYNC_TRACE_END(open);
1562
    if (result < 0) {
1563
      return;  // syscall failed, no need to continue, error info is in ctx
1564
    }
1565
    HandleScope scope(isolate);
1566
    FileHandle* fd = new FileHandle(env, result);
1567
    args.GetReturnValue().Set(fd->object());
1568
  }
1569
}
1570
1571
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1572
  Environment* env = Environment::GetCurrent(args);
1573
  Isolate* isolate = env->isolate();
1574
1575
  const int argc = args.Length();
1576
  CHECK_GE(argc, 3);
1577
1578
  BufferValue src(isolate, args[0]);
1579
  CHECK_NOT_NULL(*src);
1580
1581
  BufferValue dest(isolate, args[1]);
1582
  CHECK_NOT_NULL(*dest);
1583
1584
  CHECK(args[2]->IsInt32());
1585
  const int flags = args[2].As<Int32>()->Value();
1586
1587
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1588
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1589
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1590
                  *dest, dest.length(), UTF8, AfterNoArgs,
1591
                  uv_fs_copyfile, *src, *dest, flags);
1592
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1593
    CHECK_EQ(argc, 5);
1594
    FSReqWrapSync req_wrap_sync;
1595
    FS_SYNC_TRACE_BEGIN(copyfile);
1596
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1597
             uv_fs_copyfile, *src, *dest, flags);
1598
    FS_SYNC_TRACE_END(copyfile);
1599
  }
1600
}
1601
1602
1603
// Wrapper for write(2).
1604
//
1605
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1606
// 0 fd        integer. file descriptor
1607
// 1 buffer    the data to write
1608
// 2 offset    where in the buffer to start from
1609
// 3 length    how much to write
1610
// 4 position  if integer, position to write at in the file.
1611
//             if null, write from the current position
1612
1153
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1613
1153
  Environment* env = Environment::GetCurrent(args);
1614
1615
1153
  const int argc = args.Length();
1616
1153
  CHECK_GE(argc, 4);
1617
1618
2306
  CHECK(args[0]->IsInt32());
1619
3459
  const int fd = args[0].As<Int32>()->Value();
1620
1621
1153
  CHECK(Buffer::HasInstance(args[1]));
1622
2306
  Local<Object> buffer_obj = args[1].As<Object>();
1623
1153
  char* buffer_data = Buffer::Data(buffer_obj);
1624
1153
  size_t buffer_length = Buffer::Length(buffer_obj);
1625
1626
2306
  CHECK(args[2]->IsInt32());
1627
3459
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1628
1153
  CHECK_LE(off, buffer_length);
1629
1630
2306
  CHECK(args[3]->IsInt32());
1631
3459
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1632
1153
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1633
1153
  CHECK_LE(len, buffer_length);
1634
1153
  CHECK_GE(off + len, off);
1635
1636

3149
  const int64_t pos = GET_OFFSET(args[4]);
1637
1638
1153
  char* buf = buffer_data + off;
1639
1153
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1640
1641
1153
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1642
1153
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1643
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1644
972
              uv_fs_write, fd, &uvbuf, 1, pos);
1645
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1646
181
    CHECK_EQ(argc, 7);
1647
181
    FSReqWrapSync req_wrap_sync;
1648

181
    FS_SYNC_TRACE_BEGIN(write);
1649
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1650
181
                                uv_fs_write, fd, &uvbuf, 1, pos);
1651

181
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1652
543
    args.GetReturnValue().Set(bytesWritten);
1653
  }
1654
1153
}
1655
1656
1657
// Wrapper for writev(2).
1658
//
1659
// bytesWritten = writev(fd, chunks, position, callback)
1660
// 0 fd        integer. file descriptor
1661
// 1 chunks    array of buffers to write
1662
// 2 position  if integer, position to write at in the file.
1663
//             if null, write from the current position
1664
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1665
  Environment* env = Environment::GetCurrent(args);
1666
1667
  const int argc = args.Length();
1668
  CHECK_GE(argc, 3);
1669
1670
  CHECK(args[0]->IsInt32());
1671
  const int fd = args[0].As<Int32>()->Value();
1672
1673
  CHECK(args[1]->IsArray());
1674
  Local<Array> chunks = args[1].As<Array>();
1675
1676
  int64_t pos = GET_OFFSET(args[2]);
1677
1678
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1679
1680
  for (uint32_t i = 0; i < iovs.length(); i++) {
1681
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1682
    CHECK(Buffer::HasInstance(chunk));
1683
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1684
  }
1685
1686
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1687
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1688
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1689
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1690
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1691
    CHECK_EQ(argc, 5);
1692
    FSReqWrapSync req_wrap_sync;
1693
    FS_SYNC_TRACE_BEGIN(write);
1694
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1695
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1696
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1697
    args.GetReturnValue().Set(bytesWritten);
1698
  }
1699
}
1700
1701
1702
// Wrapper for write(2).
1703
//
1704
// bytesWritten = write(fd, string, position, enc, callback)
1705
// 0 fd        integer. file descriptor
1706
// 1 string    non-buffer values are converted to strings
1707
// 2 position  if integer, position to write at in the file.
1708
//             if null, write from the current position
1709
// 3 enc       encoding of string
1710
615
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1711
615
  Environment* env = Environment::GetCurrent(args);
1712
615
  Isolate* isolate = env->isolate();
1713
1714
615
  const int argc = args.Length();
1715
615
  CHECK_GE(argc, 4);
1716
1717
1230
  CHECK(args[0]->IsInt32());
1718
1845
  const int fd = args[0].As<Int32>()->Value();
1719
1720

1230
  const int64_t pos = GET_OFFSET(args[2]);
1721
1722
615
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1723
1724
615
  Local<Value> value = args[1];
1725
615
  char* buf = nullptr;
1726
  size_t len;
1727
1728
615
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1729
615
  const bool is_async = req_wrap_async != nullptr;
1730
1731
  // Avoid copying the string when it is externalized but only when:
1732
  // 1. The target encoding is compatible with the string's encoding, and
1733
  // 2. The write is synchronous, otherwise the string might get neutered
1734
  //    while the request is in flight, and
1735
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1736
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1737
  // The const_casts are conceptually sound: memory is read but not written.
1738

1845
  if (!is_async && value->IsString()) {
1739
615
    auto string = value.As<String>();
1740


615
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1741
      auto ext = string->GetExternalOneByteStringResource();
1742
      buf = const_cast<char*>(ext->data());
1743
      len = ext->length();
1744


615
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1745
      auto ext = string->GetExternalStringResource();
1746
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1747
      len = ext->length() * sizeof(*ext->data());
1748
    }
1749
  }
1750
1751
615
  if (is_async) {  // write(fd, string, pos, enc, req)
1752
    CHECK_NOT_NULL(req_wrap_async);
1753
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1754
    FSReqBase::FSReqBuffer& stack_buffer =
1755
        req_wrap_async->Init("write", len, enc);
1756
    // StorageSize may return too large a char, so correct the actual length
1757
    // by the write size
1758
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1759
    stack_buffer.SetLengthAndZeroTerminate(len);
1760
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1761
    int err = req_wrap_async->Dispatch(uv_fs_write,
1762
                                       fd,
1763
                                       &uvbuf,
1764
                                       1,
1765
                                       pos,
1766
                                       AfterInteger);
1767
    if (err < 0) {
1768
      uv_fs_t* uv_req = req_wrap_async->req();
1769
      uv_req->result = err;
1770
      uv_req->path = nullptr;
1771
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1772
                             // an error
1773
    } else {
1774
      req_wrap_async->SetReturnValue(args);
1775
    }
1776
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1777
615
    CHECK_EQ(argc, 6);
1778
615
    FSReqWrapSync req_wrap_sync;
1779
1230
    FSReqBase::FSReqBuffer stack_buffer;
1780
615
    if (buf == nullptr) {
1781
1230
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1782
        return;
1783
615
      stack_buffer.AllocateSufficientStorage(len + 1);
1784
      // StorageSize may return too large a char, so correct the actual length
1785
      // by the write size
1786
      len = StringBytes::Write(isolate, *stack_buffer,
1787
615
                               len, args[1], enc);
1788
615
      stack_buffer.SetLengthAndZeroTerminate(len);
1789
615
      buf = *stack_buffer;
1790
    }
1791
615
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1792

615
    FS_SYNC_TRACE_BEGIN(write);
1793
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1794
615
                                uv_fs_write, fd, &uvbuf, 1, pos);
1795

615
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1796
2460
    args.GetReturnValue().Set(bytesWritten);
1797
  }
1798
}
1799
1800
1801
/*
1802
 * Wrapper for read(2).
1803
 *
1804
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1805
 *
1806
 * 0 fd        int32. file descriptor
1807
 * 1 buffer    instance of Buffer
1808
 * 2 offset    int32. offset to start reading into inside buffer
1809
 * 3 length    int32. length to read
1810
 * 4 position  int64. file position - -1 for current position
1811
 */
1812
11123
static void Read(const FunctionCallbackInfo<Value>& args) {
1813
11123
  Environment* env = Environment::GetCurrent(args);
1814
1815
11123
  const int argc = args.Length();
1816
11123
  CHECK_GE(argc, 5);
1817
1818
22246
  CHECK(args[0]->IsInt32());
1819
33369
  const int fd = args[0].As<Int32>()->Value();
1820
1821
11123
  CHECK(Buffer::HasInstance(args[1]));
1822
22246
  Local<Object> buffer_obj = args[1].As<Object>();
1823
11123
  char* buffer_data = Buffer::Data(buffer_obj);
1824
11123
  size_t buffer_length = Buffer::Length(buffer_obj);
1825
1826
22246
  CHECK(args[2]->IsInt32());
1827
33369
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1828
11123
  CHECK_LT(off, buffer_length);
1829
1830
22246
  CHECK(args[3]->IsInt32());
1831
33369
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1832
11123
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1833
1834
22246
  CHECK(args[4]->IsNumber());
1835
33369
  const int64_t pos = args[4].As<Integer>()->Value();
1836
1837
11123
  char* buf = buffer_data + off;
1838
11123
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1839
1840
11123
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1841
11123
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1842
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1843
416
              uv_fs_read, fd, &uvbuf, 1, pos);
1844
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1845
10707
    CHECK_EQ(argc, 7);
1846
10707
    FSReqWrapSync req_wrap_sync;
1847

10707
    FS_SYNC_TRACE_BEGIN(read);
1848
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1849
10707
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1850

10707
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1851
32121
    args.GetReturnValue().Set(bytesRead);
1852
  }
1853
11123
}
1854
1855
1856
/* fs.chmod(path, mode);
1857
 * Wrapper for chmod(1) / EIO_CHMOD
1858
 */
1859
4
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1860
4
  Environment* env = Environment::GetCurrent(args);
1861
1862
4
  const int argc = args.Length();
1863
4
  CHECK_GE(argc, 2);
1864
1865
4
  BufferValue path(env->isolate(), args[0]);
1866
4
  CHECK_NOT_NULL(*path);
1867
1868
8
  CHECK(args[1]->IsInt32());
1869
12
  int mode = args[1].As<Int32>()->Value();
1870
1871
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1872
4
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1873
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1874
4
              uv_fs_chmod, *path, mode);
1875
  } else {  // chmod(path, mode, undefined, ctx)
1876
    CHECK_EQ(argc, 4);
1877
    FSReqWrapSync req_wrap_sync;
1878
    FS_SYNC_TRACE_BEGIN(chmod);
1879
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1880
             uv_fs_chmod, *path, mode);
1881
    FS_SYNC_TRACE_END(chmod);
1882
4
  }
1883
4
}
1884
1885
1886
/* fs.fchmod(fd, mode);
1887
 * Wrapper for fchmod(1) / EIO_FCHMOD
1888
 */
1889
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1890
  Environment* env = Environment::GetCurrent(args);
1891
1892
  const int argc = args.Length();
1893
  CHECK_GE(argc, 2);
1894
1895
  CHECK(args[0]->IsInt32());
1896
  const int fd = args[0].As<Int32>()->Value();
1897
1898
  CHECK(args[1]->IsInt32());
1899
  const int mode = args[1].As<Int32>()->Value();
1900
1901
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1902
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1903
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1904
              uv_fs_fchmod, fd, mode);
1905
  } else {  // fchmod(fd, mode, undefined, ctx)
1906
    CHECK_EQ(argc, 4);
1907
    FSReqWrapSync req_wrap_sync;
1908
    FS_SYNC_TRACE_BEGIN(fchmod);
1909
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1910
             uv_fs_fchmod, fd, mode);
1911
    FS_SYNC_TRACE_END(fchmod);
1912
  }
1913
}
1914
1915
1916
/* fs.chown(path, uid, gid);
1917
 * Wrapper for chown(1) / EIO_CHOWN
1918
 */
1919
static void Chown(const FunctionCallbackInfo<Value>& args) {
1920
  Environment* env = Environment::GetCurrent(args);
1921
1922
  const int argc = args.Length();
1923
  CHECK_GE(argc, 3);
1924
1925
  BufferValue path(env->isolate(), args[0]);
1926
  CHECK_NOT_NULL(*path);
1927
1928
  CHECK(args[1]->IsUint32());
1929
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1930
1931
  CHECK(args[2]->IsUint32());
1932
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1933
1934
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1935
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1936
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1937
              uv_fs_chown, *path, uid, gid);
1938
  } else {  // chown(path, uid, gid, undefined, ctx)
1939
    CHECK_EQ(argc, 5);
1940
    FSReqWrapSync req_wrap_sync;
1941
    FS_SYNC_TRACE_BEGIN(chown);
1942
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1943
             uv_fs_chown, *path, uid, gid);
1944
    FS_SYNC_TRACE_END(chown);
1945
  }
1946
}
1947
1948
1949
/* fs.fchown(fd, uid, gid);
1950
 * Wrapper for fchown(1) / EIO_FCHOWN
1951
 */
1952
static void FChown(const FunctionCallbackInfo<Value>& args) {
1953
  Environment* env = Environment::GetCurrent(args);
1954
1955
  const int argc = args.Length();
1956
  CHECK_GE(argc, 3);
1957
1958
  CHECK(args[0]->IsInt32());
1959
  const int fd = args[0].As<Int32>()->Value();
1960
1961
  CHECK(args[1]->IsUint32());
1962
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1963
1964
  CHECK(args[2]->IsUint32());
1965
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1966
1967
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1968
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
1969
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
1970
              uv_fs_fchown, fd, uid, gid);
1971
  } else {  // fchown(fd, uid, gid, undefined, ctx)
1972
    CHECK_EQ(argc, 5);
1973
    FSReqWrapSync req_wrap_sync;
1974
    FS_SYNC_TRACE_BEGIN(fchown);
1975
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
1976
             uv_fs_fchown, fd, uid, gid);
1977
    FS_SYNC_TRACE_END(fchown);
1978
  }
1979
}
1980
1981
1982
static void LChown(const FunctionCallbackInfo<Value>& args) {
1983
  Environment* env = Environment::GetCurrent(args);
1984
1985
  const int argc = args.Length();
1986
  CHECK_GE(argc, 3);
1987
1988
  BufferValue path(env->isolate(), args[0]);
1989
  CHECK_NOT_NULL(*path);
1990
1991
  CHECK(args[1]->IsUint32());
1992
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1993
1994
  CHECK(args[2]->IsUint32());
1995
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1996
1997
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1998
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
1999
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2000
              uv_fs_lchown, *path, uid, gid);
2001
  } else {  // lchown(path, uid, gid, undefined, ctx)
2002
    CHECK_EQ(argc, 5);
2003
    FSReqWrapSync req_wrap_sync;
2004
    FS_SYNC_TRACE_BEGIN(lchown);
2005
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2006
             uv_fs_lchown, *path, uid, gid);
2007
    FS_SYNC_TRACE_END(lchown);
2008
  }
2009
}
2010
2011
2012
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2013
  Environment* env = Environment::GetCurrent(args);
2014
2015
  const int argc = args.Length();
2016
  CHECK_GE(argc, 3);
2017
2018
  BufferValue path(env->isolate(), args[0]);
2019
  CHECK_NOT_NULL(*path);
2020
2021
  CHECK(args[1]->IsNumber());
2022
  const double atime = args[1].As<Number>()->Value();
2023
2024
  CHECK(args[2]->IsNumber());
2025
  const double mtime = args[2].As<Number>()->Value();
2026
2027
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2028
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2029
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2030
              uv_fs_utime, *path, atime, mtime);
2031
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2032
    CHECK_EQ(argc, 5);
2033
    FSReqWrapSync req_wrap_sync;
2034
    FS_SYNC_TRACE_BEGIN(utimes);
2035
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2036
             uv_fs_utime, *path, atime, mtime);
2037
    FS_SYNC_TRACE_END(utimes);
2038
  }
2039
}
2040
2041
709
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2042
709
  Environment* env = Environment::GetCurrent(args);
2043
2044
709
  const int argc = args.Length();
2045
709
  CHECK_GE(argc, 3);
2046
2047
1418
  CHECK(args[0]->IsInt32());
2048
2127
  const int fd = args[0].As<Int32>()->Value();
2049
2050
1418
  CHECK(args[1]->IsNumber());
2051
2127
  const double atime = args[1].As<Number>()->Value();
2052
2053
1418
  CHECK(args[2]->IsNumber());
2054
2127
  const double mtime = args[2].As<Number>()->Value();
2055
2056
709
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2057
709
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2058
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2059
709
              uv_fs_futime, fd, atime, mtime);
2060
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2061
    CHECK_EQ(argc, 5);
2062
    FSReqWrapSync req_wrap_sync;
2063
    FS_SYNC_TRACE_BEGIN(futimes);
2064
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2065
             uv_fs_futime, fd, atime, mtime);
2066
    FS_SYNC_TRACE_END(futimes);
2067
  }
2068
709
}
2069
2070
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2071
  Environment* env = Environment::GetCurrent(args);
2072
  Isolate* isolate = env->isolate();
2073
2074
  const int argc = args.Length();
2075
  CHECK_GE(argc, 2);
2076
2077
  BufferValue tmpl(isolate, args[0]);
2078
  CHECK_NOT_NULL(*tmpl);
2079
2080
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2081
2082
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2083
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2084
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2085
              uv_fs_mkdtemp, *tmpl);
2086
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2087
    CHECK_EQ(argc, 4);
2088
    FSReqWrapSync req_wrap_sync;
2089
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2090
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2091
             uv_fs_mkdtemp, *tmpl);
2092
    FS_SYNC_TRACE_END(mkdtemp);
2093
    const char* path = static_cast<const char*>(req_wrap_sync.req.path);
2094
2095
    Local<Value> error;
2096
    MaybeLocal<Value> rc =
2097
        StringBytes::Encode(isolate, path, encoding, &error);
2098
    if (rc.IsEmpty()) {
2099
      Local<Object> ctx = args[3].As<Object>();
2100
      ctx->Set(env->context(), env->error_string(), error).FromJust();
2101
      return;
2102
    }
2103
    args.GetReturnValue().Set(rc.ToLocalChecked());
2104
  }
2105
}
2106
2107
164
void Initialize(Local<Object> target,
2108
                Local<Value> unused,
2109
                Local<Context> context,
2110
                void* priv) {
2111
164
  Environment* env = Environment::GetCurrent(context);
2112
164
  Isolate* isolate = env->isolate();
2113
2114
164
  env->SetMethod(target, "access", Access);
2115
164
  env->SetMethod(target, "close", Close);
2116
164
  env->SetMethod(target, "open", Open);
2117
164
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2118
164
  env->SetMethod(target, "read", Read);
2119
164
  env->SetMethod(target, "fdatasync", Fdatasync);
2120
164
  env->SetMethod(target, "fsync", Fsync);
2121
164
  env->SetMethod(target, "rename", Rename);
2122
164
  env->SetMethod(target, "ftruncate", FTruncate);
2123
164
  env->SetMethod(target, "rmdir", RMDir);
2124
164
  env->SetMethod(target, "mkdir", MKDir);
2125
164
  env->SetMethod(target, "readdir", ReadDir);
2126
164
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2127
164
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2128
164
  env->SetMethod(target, "stat", Stat);
2129
164
  env->SetMethod(target, "lstat", LStat);
2130
164
  env->SetMethod(target, "fstat", FStat);
2131
164
  env->SetMethod(target, "link", Link);
2132
164
  env->SetMethod(target, "symlink", Symlink);
2133
164
  env->SetMethod(target, "readlink", ReadLink);
2134
164
  env->SetMethod(target, "unlink", Unlink);
2135
164
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2136
164
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2137
164
  env->SetMethod(target, "writeString", WriteString);
2138
164
  env->SetMethod(target, "realpath", RealPath);
2139
164
  env->SetMethod(target, "copyFile", CopyFile);
2140
2141
164
  env->SetMethod(target, "chmod", Chmod);
2142
164
  env->SetMethod(target, "fchmod", FChmod);
2143
  // env->SetMethod(target, "lchmod", LChmod);
2144
2145
164
  env->SetMethod(target, "chown", Chown);
2146
164
  env->SetMethod(target, "fchown", FChown);
2147
164
  env->SetMethod(target, "lchown", LChown);
2148
2149
164
  env->SetMethod(target, "utimes", UTimes);
2150
164
  env->SetMethod(target, "futimes", FUTimes);
2151
2152
164
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2153
2154
  target->Set(context,
2155
              FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2156
656
              Integer::New(isolate, kFsStatsFieldsNumber))
2157
328
        .FromJust();
2158
2159
  target->Set(context,
2160
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2161
656
              env->fs_stats_field_array()->GetJSArray()).FromJust();
2162
2163
  target->Set(context,
2164
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2165
656
              env->fs_stats_field_bigint_array()->GetJSArray()).FromJust();
2166
2167
164
  StatWatcher::Initialize(env, target);
2168
2169
  // Create FunctionTemplate for FSReqCallback
2170
164
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2171
328
  fst->InstanceTemplate()->SetInternalFieldCount(1);
2172
328
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2173
  Local<String> wrapString =
2174
164
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2175
164
  fst->SetClassName(wrapString);
2176
  target
2177
      ->Set(context, wrapString,
2178
656
            fst->GetFunction(env->context()).ToLocalChecked())
2179
328
      .FromJust();
2180
2181
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2182
  // to do anything in the constructor, so we only store the instance template.
2183
164
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2184
328
  fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2185
328
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2186
  Local<String> fhWrapString =
2187
164
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2188
164
  fh_rw->SetClassName(fhWrapString);
2189
  env->set_filehandlereadwrap_template(
2190
164
      fst->InstanceTemplate());
2191
2192
  // Create Function Template for FSReqPromise
2193
164
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2194
328
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2195
  Local<String> promiseString =
2196
164
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2197
164
  fpt->SetClassName(promiseString);
2198
164
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2199
164
  fpo->SetInternalFieldCount(1);
2200
164
  env->set_fsreqpromise_constructor_template(fpo);
2201
2202
  // Create FunctionTemplate for FileHandle
2203
164
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2204
328
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2205
164
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2206
164
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2207
164
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2208
164
  fdt->SetInternalFieldCount(1);
2209
  Local<String> handleString =
2210
164
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2211
164
  fd->SetClassName(handleString);
2212
164
  StreamBase::AddMethods<FileHandle>(env, fd);
2213
  target
2214
      ->Set(context, handleString,
2215
656
            fd->GetFunction(env->context()).ToLocalChecked())
2216
328
      .FromJust();
2217
164
  env->set_fd_constructor_template(fdt);
2218
2219
  // Create FunctionTemplate for FileHandle::CloseReq
2220
164
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2221
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2222
328
                        "FileHandleCloseReq"));
2223
328
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2224
164
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2225
164
  fdcloset->SetInternalFieldCount(1);
2226
164
  env->set_fdclose_constructor_template(fdcloset);
2227
2228
  Local<Symbol> use_promises_symbol =
2229
    Symbol::New(isolate,
2230
164
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2231
164
  env->set_fs_use_promises_symbol(use_promises_symbol);
2232
  target->Set(context,
2233
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2234
492
              use_promises_symbol).FromJust();
2235
164
}
2236
2237
}  // namespace fs
2238
2239
}  // end namespace node
2240
2241
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)