GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_file.cc Lines: 1204 1279 94.1 %
Date: 2019-01-07 12:15:22 Branches: 776 1164 66.7 %

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 "aliased_buffer.h"
23
#include "node_buffer.h"
24
#include "node_internals.h"
25
#include "node_stat_watcher.h"
26
#include "node_file.h"
27
#include "tracing/trace_event.h"
28
29
#include "req_wrap-inl.h"
30
#include "stream_base-inl.h"
31
#include "string_bytes.h"
32
#include "string_search.h"
33
34
#include <fcntl.h>
35
#include <sys/types.h>
36
#include <sys/stat.h>
37
#include <string.h>
38
#include <errno.h>
39
#include <limits.h>
40
41
#if defined(__MINGW32__) || defined(_MSC_VER)
42
# include <io.h>
43
#endif
44
45
#include <memory>
46
47
namespace node {
48
49
namespace fs {
50
51
using v8::Array;
52
using v8::BigUint64Array;
53
using v8::Context;
54
using v8::EscapableHandleScope;
55
using v8::Float64Array;
56
using v8::Function;
57
using v8::FunctionCallbackInfo;
58
using v8::FunctionTemplate;
59
using v8::HandleScope;
60
using v8::Int32;
61
using v8::Integer;
62
using v8::Isolate;
63
using v8::Local;
64
using v8::MaybeLocal;
65
using v8::Number;
66
using v8::Object;
67
using v8::ObjectTemplate;
68
using v8::Promise;
69
using v8::String;
70
using v8::Symbol;
71
using v8::Uint32;
72
using v8::Undefined;
73
using v8::Value;
74
75
#ifndef MIN
76
# define MIN(a, b) ((a) < (b) ? (a) : (b))
77
#endif
78
79
#ifndef S_ISDIR
80
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
81
#endif
82
83
#ifdef __POSIX__
84
constexpr char kPathSeparator = '/';
85
#else
86
const char* const kPathSeparator = "\\/";
87
#endif
88
89
#define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
90
#define TRACE_NAME(name) "fs.sync." #name
91
#define GET_TRACE_ENABLED                                                  \
92
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
93
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
94
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
95
  if (GET_TRACE_ENABLED)                                                   \
96
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
97
  ##__VA_ARGS__);
98
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
99
  if (GET_TRACE_ENABLED)                                                   \
100
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
101
  ##__VA_ARGS__);
102
103
// We sometimes need to convert a C++ lambda function to a raw C-style function.
104
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
105
// functions, and thus does not wrap them properly.
106
typedef void(*uv_fs_callback_t)(uv_fs_t*);
107
108
// The FileHandle object wraps a file descriptor and will close it on garbage
109
// collection if necessary. If that happens, a process warning will be
110
// emitted (or a fatal exception will occur if the fd cannot be closed.)
111
74
FileHandle::FileHandle(Environment* env, int fd, Local<Object> obj)
112
    : AsyncWrap(env,
113
74
                obj.IsEmpty() ? env->fd_constructor_template()
114

257
                    ->NewInstance(env->context()).ToLocalChecked() : obj,
115
                AsyncWrap::PROVIDER_FILEHANDLE),
116
      StreamBase(env),
117
235
      fd_(fd) {
118
74
  MakeWeak();
119
  v8::PropertyAttribute attr =
120
74
      static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
121
74
  object()->DefineOwnProperty(env->context(),
122
                              FIXED_ONE_BYTE_STRING(env->isolate(), "fd"),
123
                              Integer::New(env->isolate(), fd),
124
444
                              attr).FromJust();
125
74
}
126
127
13
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
128
13
  Environment* env = Environment::GetCurrent(args);
129
13
  CHECK(args.IsConstructCall());
130
26
  CHECK(args[0]->IsInt32());
131
132
  FileHandle* handle =
133
52
      new FileHandle(env, args[0].As<Int32>()->Value(), args.This());
134
26
  if (args[1]->IsNumber())
135
52
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
136
26
  if (args[2]->IsNumber())
137
52
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
138
13
}
139
140
222
FileHandle::~FileHandle() {
141
74
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
142
74
  Close();           // Close synchronously and emit warning
143
74
  CHECK(closed_);    // We have to be closed at the point
144
148
}
145
146
147
// Close the file descriptor if it hasn't already been closed. A process
148
// warning will be emitted using a SetImmediate to avoid calling back to
149
// JS during GC. If closing the fd fails at this point, a fatal exception
150
// will crash the process immediately.
151
74
inline void FileHandle::Close() {
152
119
  if (closed_) return;
153
  uv_fs_t req;
154
29
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
155
29
  uv_fs_req_cleanup(&req);
156
29
  AfterClose();
157
158
  struct err_detail { int ret; int fd; };
159
160
29
  err_detail* detail = new err_detail { ret, fd_ };
161
162
29
  if (ret < 0) {
163
    // Do not unref this
164
    env()->SetImmediate([](Environment* env, void* data) {
165
      char msg[70];
166
      std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
167
      snprintf(msg, arraysize(msg),
168
              "Closing file descriptor %d on garbage collection failed",
169
              detail->fd);
170
      // This exception will end up being fatal for the process because
171
      // it is being thrown from within the SetImmediate handler and
172
      // there is no JS stack to bubble it to. In other words, tearing
173
      // down the process is the only reasonable thing we can do here.
174
      HandleScope handle_scope(env->isolate());
175
      env->ThrowUVException(detail->ret, "close", msg);
176
    }, detail);
177
    return;
178
  }
179
180
  // If the close was successful, we still want to emit a process warning
181
  // to notify that the file descriptor was gc'd. We want to be noisy about
182
  // this because not explicitly closing the FileHandle is a bug.
183
31
  env()->SetUnrefImmediate([](Environment* env, void* data) {
184
1
    std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
185
    ProcessEmitWarning(env,
186
                       "Closing file descriptor %d on garbage collection",
187
1
                       detail->fd);
188
60
  }, detail);
189
}
190
191
39
void FileHandle::CloseReq::Resolve() {
192
39
  Isolate* isolate = env()->isolate();
193
39
  HandleScope scope(isolate);
194
78
  InternalCallbackScope callback_scope(this);
195
78
  Local<Promise> promise = promise_.Get(isolate);
196
39
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
197
156
  resolver->Resolve(env()->context(), Undefined(isolate)).FromJust();
198
39
}
199
200
void FileHandle::CloseReq::Reject(Local<Value> reason) {
201
  Isolate* isolate = env()->isolate();
202
  HandleScope scope(isolate);
203
  InternalCallbackScope callback_scope(this);
204
  Local<Promise> promise = promise_.Get(isolate);
205
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
206
  resolver->Reject(env()->context(), reason).FromJust();
207
}
208
209
39
FileHandle* FileHandle::CloseReq::file_handle() {
210
39
  Isolate* isolate = env()->isolate();
211
39
  HandleScope scope(isolate);
212
78
  Local<Value> val = ref_.Get(isolate);
213
39
  Local<Object> obj = val.As<Object>();
214
39
  return Unwrap<FileHandle>(obj);
215
}
216
217
// Closes this FileHandle asynchronously and returns a Promise that will be
218
// resolved when the callback is invoked, or rejects with a UVException if
219
// there was a problem closing the fd. This is the preferred mechanism for
220
// closing the FD object even tho the object will attempt to close
221
// automatically on gc.
222
39
inline MaybeLocal<Promise> FileHandle::ClosePromise() {
223
39
  Isolate* isolate = env()->isolate();
224
39
  EscapableHandleScope scope(isolate);
225
39
  Local<Context> context = env()->context();
226
39
  auto maybe_resolver = Promise::Resolver::New(context);
227
39
  CHECK(!maybe_resolver.IsEmpty());
228
39
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
229
39
  Local<Promise> promise = resolver.As<Promise>();
230
39
  CHECK(!reading_);
231

39
  if (!closed_ && !closing_) {
232
39
    closing_ = true;
233
78
    CloseReq* req = new CloseReq(env(), promise, object());
234
117
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
235
39
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
236
39
      CHECK_NOT_NULL(close);
237
39
      close->file_handle()->AfterClose();
238
39
      Isolate* isolate = close->env()->isolate();
239
39
      if (req->result < 0) {
240
        close->Reject(UVException(isolate, req->result, "close"));
241
      } else {
242
39
        close->Resolve();
243
      }
244
156
    }};
245
39
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
246
39
    if (ret < 0) {
247
      req->Reject(UVException(isolate, ret, "close"));
248
      delete req;
249
39
    }
250
  } else {
251
    // Already closed. Just reject the promise immediately
252
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
253
        .FromJust();
254
  }
255
78
  return scope.Escape(promise);
256
}
257
258
39
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
259
  FileHandle* fd;
260
78
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
261
117
  args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked());
262
}
263
264
265
6
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
266
  FileHandle* fd;
267
12
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
268
  // Just act as if this FileHandle has been closed.
269
6
  fd->AfterClose();
270
}
271
272
273
74
void FileHandle::AfterClose() {
274
74
  closing_ = false;
275
74
  closed_ = true;
276

74
  if (reading_ && !persistent().IsEmpty())
277
    EmitRead(UV_EOF);
278
74
}
279
280
2
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
281
2
  tracker->TrackField("buffer", buffer_);
282
2
  tracker->TrackField("file_handle", this->file_handle_);
283
2
}
284
285
13
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
286
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
287
13
    file_handle_(handle) {}
288
289
214
int FileHandle::ReadStart() {
290

214
  if (!IsAlive() || IsClosing())
291
    return UV_EOF;
292
293
214
  reading_ = true;
294
295
214
  if (current_read_)
296
    return 0;
297
298
214
  std::unique_ptr<FileHandleReadWrap> read_wrap;
299
300
214
  if (read_length_ == 0) {
301
6
    EmitRead(UV_EOF);
302
6
    return 0;
303
  }
304
305
  {
306
    // Create a new FileHandleReadWrap or re-use one.
307
    // Either way, we need these two scopes for AsyncReset() or otherwise
308
    // for creating the new instance.
309
208
    HandleScope handle_scope(env()->isolate());
310
416
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
311
312
208
    auto& freelist = env()->file_handle_read_wrap_freelist();
313
208
    if (freelist.size() > 0) {
314
195
      read_wrap = std::move(freelist.back());
315
195
      freelist.pop_back();
316
195
      read_wrap->AsyncReset();
317
195
      read_wrap->file_handle_ = this;
318
    } else {
319
13
      Local<Object> wrap_obj = env()->filehandlereadwrap_template()
320
52
          ->NewInstance(env()->context()).ToLocalChecked();
321
13
      read_wrap.reset(new FileHandleReadWrap(this, wrap_obj));
322
208
    }
323
  }
324
208
  int64_t recommended_read = 65536;
325

208
  if (read_length_ >= 0 && read_length_ <= recommended_read)
326
10
    recommended_read = read_length_;
327
328
208
  read_wrap->buffer_ = EmitAlloc(recommended_read);
329
330
208
  current_read_ = std::move(read_wrap);
331
332
208
  current_read_->Dispatch(uv_fs_read,
333
                          fd_,
334
208
                          &current_read_->buffer_,
335
                          1,
336
                          read_offset_,
337
624
                          uv_fs_callback_t{[](uv_fs_t* req) {
338
    FileHandle* handle;
339
    {
340
208
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
341
208
      handle = req_wrap->file_handle_;
342
208
      CHECK_EQ(handle->current_read_.get(), req_wrap);
343
    }
344
345
    // ReadStart() checks whether current_read_ is set to determine whether
346
    // a read is in progress. Moving it into a local variable makes sure that
347
    // the ReadStart() call below doesn't think we're still actively reading.
348
    std::unique_ptr<FileHandleReadWrap> read_wrap =
349
208
        std::move(handle->current_read_);
350
351
208
    int result = req->result;
352
208
    uv_buf_t buffer = read_wrap->buffer_;
353
354
208
    uv_fs_req_cleanup(req);
355
356
    // Push the read wrap back to the freelist, or let it be destroyed
357
    // once we’re exiting the current scope.
358
208
    constexpr size_t wanted_freelist_fill = 100;
359
208
    auto& freelist = handle->env()->file_handle_read_wrap_freelist();
360
208
    if (freelist.size() < wanted_freelist_fill) {
361
208
      read_wrap->Reset();
362
208
      freelist.emplace_back(std::move(read_wrap));
363
    }
364
365
208
    if (result >= 0) {
366
      // Read at most as many bytes as we originally planned to.
367

207
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
368
        result = handle->read_length_;
369
370
      // If we read data and we have an expected length, decrease it by
371
      // how much we have read.
372
207
      if (handle->read_length_ >= 0)
373
14
        handle->read_length_ -= result;
374
375
      // If we have an offset, increase it by how much we have read.
376
207
      if (handle->read_offset_ >= 0)
377
205
        handle->read_offset_ += result;
378
    }
379
380
    // Reading 0 bytes from a file always means EOF, or that we reached
381
    // the end of the requested range.
382
208
    if (result == 0)
383
5
      result = UV_EOF;
384
385
208
    handle->EmitRead(result, buffer);
386
387
    // Start over, if EmitRead() didn’t tell us to stop.
388
208
    if (handle->reading_)
389
      handle->ReadStart();
390
1248
  }});
391
392
208
  return 0;
393
}
394
395
227
int FileHandle::ReadStop() {
396
227
  reading_ = false;
397
227
  return 0;
398
}
399
400
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
401
402
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
403
  return new FileHandleCloseWrap(this, object);
404
}
405
406
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
407
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
408
  closing_ = true;
409
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
410
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
411
        FileHandleCloseWrap::from_req(req));
412
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
413
    handle->AfterClose();
414
415
    int result = req->result;
416
    uv_fs_req_cleanup(req);
417
    wrap->Done(result);
418
  }});
419
420
  return 0;
421
}
422
423
424
1872
void FSReqCallback::Reject(Local<Value> reject) {
425
1872
  MakeCallback(env()->oncomplete_string(), 1, &reject);
426
1872
}
427
428
1407
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
429
1407
  Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
430
1407
}
431
432
156705
void FSReqCallback::Resolve(Local<Value> value) {
433
  Local<Value> argv[2] {
434
    Null(env()->isolate()),
435
    value
436
313410
  };
437
  MakeCallback(env()->oncomplete_string(),
438
466449
               value->IsUndefined() ? 1 : arraysize(argv),
439
309744
               argv);
440
156698
}
441
442
158576
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
443
317152
  args.GetReturnValue().SetUndefined();
444
158576
}
445
446
158595
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
447
158595
  CHECK(args.IsConstructCall());
448
158595
  Environment* env = Environment::GetCurrent(args);
449
475785
  new FSReqCallback(env, args.This(), args[0]->IsTrue());
450
158595
}
451
452
158912
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
453
    : wrap_(wrap),
454
      req_(req),
455
      handle_scope_(wrap->env()->isolate()),
456
158912
      context_scope_(wrap->env()->context()) {
457
158912
  CHECK_EQ(wrap_->req(), req);
458
158912
}
459
460
476715
FSReqAfterScope::~FSReqAfterScope() {
461
158905
  uv_fs_req_cleanup(wrap_->req());
462
158905
  delete wrap_;
463
158905
}
464
465
// TODO(joyeecheung): create a normal context object, and
466
// construct the actual errors in the JS land using the context.
467
// The context should include fds for some fs APIs, currently they are
468
// missing in the error messages. The path, dest, syscall, fd, .etc
469
// can be put into the context before the binding is even invoked,
470
// the only information that has to come from the C++ layer is the
471
// error number (and possibly the syscall for abstraction),
472
// which is also why the errors should have been constructed
473
// in JS for more flexibility.
474
1887
void FSReqAfterScope::Reject(uv_fs_t* req) {
475
  wrap_->Reject(UVException(wrap_->env()->isolate(),
476
                            req->result,
477
                            wrap_->syscall(),
478
                            nullptr,
479
                            req->path,
480
1887
                            wrap_->data()));
481
1887
}
482
483
158912
bool FSReqAfterScope::Proceed() {
484
158912
  if (req_->result < 0) {
485
1887
    Reject(req_);
486
1887
    return false;
487
  }
488
157025
  return true;
489
}
490
491
3783
void AfterNoArgs(uv_fs_t* req) {
492
3783
  FSReqBase* req_wrap = FSReqBase::from_req(req);
493
3783
  FSReqAfterScope after(req_wrap, req);
494
495
3783
  if (after.Proceed())
496
7438
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
497
3777
}
498
499
3293
void AfterStat(uv_fs_t* req) {
500
3293
  FSReqBase* req_wrap = FSReqBase::from_req(req);
501
3293
  FSReqAfterScope after(req_wrap, req);
502
503
3293
  if (after.Proceed()) {
504
1529
    req_wrap->ResolveStat(&req->statbuf);
505
3293
  }
506
3293
}
507
508
151689
void AfterInteger(uv_fs_t* req) {
509
151689
  FSReqBase* req_wrap = FSReqBase::from_req(req);
510
151689
  FSReqAfterScope after(req_wrap, req);
511
512
151689
  if (after.Proceed())
513
303286
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
514
151689
}
515
516
60
void AfterOpenFileHandle(uv_fs_t* req) {
517
60
  FSReqBase* req_wrap = FSReqBase::from_req(req);
518
60
  FSReqAfterScope after(req_wrap, req);
519
520
60
  if (after.Proceed()) {
521
120
    FileHandle* fd = new FileHandle(req_wrap->env(), req->result);
522
120
    req_wrap->Resolve(fd->object());
523
60
  }
524
60
}
525
526
5
void AfterStringPath(uv_fs_t* req) {
527
5
  FSReqBase* req_wrap = FSReqBase::from_req(req);
528
5
  FSReqAfterScope after(req_wrap, req);
529
530
  MaybeLocal<Value> link;
531
  Local<Value> error;
532
533
5
  if (after.Proceed()) {
534
    link = StringBytes::Encode(req_wrap->env()->isolate(),
535
                               static_cast<const char*>(req->path),
536
                               req_wrap->encoding(),
537
4
                               &error);
538
4
    if (link.IsEmpty())
539
      req_wrap->Reject(error);
540
    else
541
8
      req_wrap->Resolve(link.ToLocalChecked());
542
5
  }
543
5
}
544
545
51
void AfterStringPtr(uv_fs_t* req) {
546
51
  FSReqBase* req_wrap = FSReqBase::from_req(req);
547
51
  FSReqAfterScope after(req_wrap, req);
548
549
  MaybeLocal<Value> link;
550
  Local<Value> error;
551
552
51
  if (after.Proceed()) {
553
    link = StringBytes::Encode(req_wrap->env()->isolate(),
554
                               static_cast<const char*>(req->ptr),
555
                               req_wrap->encoding(),
556
43
                               &error);
557
43
    if (link.IsEmpty())
558
      req_wrap->Reject(error);
559
    else
560
86
      req_wrap->Resolve(link.ToLocalChecked());
561
50
  }
562
50
}
563
564
27
void AfterScanDir(uv_fs_t* req) {
565
27
  FSReqBase* req_wrap = FSReqBase::from_req(req);
566
27
  FSReqAfterScope after(req_wrap, req);
567
568
27
  if (!after.Proceed()) {
569
3
    return;
570
  }
571
24
  Environment* env = req_wrap->env();
572
  Local<Value> error;
573
  int r;
574
48
  std::vector<Local<Value>> name_v;
575
576
4788
  for (int i = 0; ; i++) {
577
    uv_dirent_t ent;
578
579
4788
    r = uv_fs_scandir_next(req, &ent);
580
4788
    if (r == UV_EOF)
581
24
      break;
582
4764
    if (r != 0) {
583
      return req_wrap->Reject(
584
          UVException(r, nullptr, req_wrap->syscall(),
585
            static_cast<const char*>(req->path)));
586
    }
587
588
    MaybeLocal<Value> filename =
589
      StringBytes::Encode(env->isolate(),
590
          ent.name,
591
          req_wrap->encoding(),
592
4764
          &error);
593
4764
    if (filename.IsEmpty())
594
      return req_wrap->Reject(error);
595
596
4764
    name_v.push_back(filename.ToLocalChecked());
597
4764
  }
598
599
72
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
600
}
601
602
4
void AfterScanDirWithTypes(uv_fs_t* req) {
603
4
  FSReqBase* req_wrap = FSReqBase::from_req(req);
604
4
  FSReqAfterScope after(req_wrap, req);
605
606
4
  if (!after.Proceed()) {
607
1
    return;
608
  }
609
610
3
  Environment* env = req_wrap->env();
611
3
  Isolate* isolate = env->isolate();
612
  Local<Value> error;
613
  int r;
614
615
6
  std::vector<Local<Value>> name_v;
616
6
  std::vector<Local<Value>> type_v;
617
618
18
  for (int i = 0; ; i++) {
619
    uv_dirent_t ent;
620
621
18
    r = uv_fs_scandir_next(req, &ent);
622
18
    if (r == UV_EOF)
623
3
      break;
624
15
    if (r != 0) {
625
      return req_wrap->Reject(
626
          UVException(r, nullptr, req_wrap->syscall(),
627
            static_cast<const char*>(req->path)));
628
    }
629
630
    MaybeLocal<Value> filename =
631
      StringBytes::Encode(isolate,
632
          ent.name,
633
          req_wrap->encoding(),
634
15
          &error);
635
15
    if (filename.IsEmpty())
636
      return req_wrap->Reject(error);
637
638
15
    name_v.push_back(filename.ToLocalChecked());
639
30
    type_v.push_back(Integer::New(isolate, ent.type));
640
15
  }
641
642
3
  Local<Array> result = Array::New(isolate, 2);
643
3
  result->Set(env->context(),
644
              0,
645
              Array::New(isolate, name_v.data(),
646
12
              name_v.size())).FromJust();
647
3
  result->Set(env->context(),
648
              1,
649
              Array::New(isolate, type_v.data(),
650
12
              type_v.size())).FromJust();
651
9
  req_wrap->Resolve(result);
652
}
653
654
655
// This class is only used on sync fs calls.
656
// For async calls FSReqCallback is used.
657
class FSReqWrapSync {
658
 public:
659
362504
  FSReqWrapSync() {}
660
362502
  ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
661
  uv_fs_t req;
662
663
 private:
664
  DISALLOW_COPY_AND_ASSIGN(FSReqWrapSync);
665
};
666
667
// Returns nullptr if the operation fails from the start.
668
template <typename Func, typename... Args>
669
158882
inline FSReqBase* AsyncDestCall(Environment* env,
670
    FSReqBase* req_wrap,
671
    const FunctionCallbackInfo<Value>& args,
672
    const char* syscall, const char* dest, size_t len,
673
    enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
674







158882
  CHECK_NOT_NULL(req_wrap);
675
158882
  req_wrap->Init(syscall, dest, len, enc);
676
158882
  int err = req_wrap->Dispatch(fn, fn_args..., after);
677







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







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

176
    FS_SYNC_TRACE_BEGIN(access);
761
352
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
762

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

53592
    FS_SYNC_TRACE_BEGIN(close);
784
53593
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
785

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

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

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

24725
    FS_SYNC_TRACE_BEGIN(stat);
896
49450
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
897

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

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

99420
    FS_SYNC_TRACE_BEGIN(lstat);
926
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
927
198841
                       *path);
928

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

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

46884
    FS_SYNC_TRACE_BEGIN(fstat);
957
46883
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
958

46883
    FS_SYNC_TRACE_END(fstat);
959
46884
    if (err != 0) {
960
47370
      return;  // error info is in ctx
961
    }
962
963
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
964
46867
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
965
93732
    args.GetReturnValue().Set(arr);
966
  }
967
}
968
969
86
static void Symlink(const FunctionCallbackInfo<Value>& args) {
970
86
  Environment* env = Environment::GetCurrent(args);
971
86
  Isolate* isolate = env->isolate();
972
973
86
  int argc = args.Length();
974
86
  CHECK_GE(argc, 4);
975
976
86
  BufferValue target(isolate, args[0]);
977
86
  CHECK_NOT_NULL(*target);
978
172
  BufferValue path(isolate, args[1]);
979
86
  CHECK_NOT_NULL(*path);
980
981
172
  CHECK(args[2]->IsInt32());
982
258
  int flags = args[2].As<Int32>()->Value();
983
984
86
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
985
86
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
986
14
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
987
28
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
988
  } else {  // symlink(target, path, flags, undefinec, ctx)
989
72
    CHECK_EQ(argc, 5);
990
72
    FSReqWrapSync req_wrap_sync;
991

72
    FS_SYNC_TRACE_BEGIN(symlink);
992
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
993
144
             uv_fs_symlink, *target, *path, flags);
994

72
    FS_SYNC_TRACE_END(symlink);
995
86
  }
996
86
}
997
998
9
static void Link(const FunctionCallbackInfo<Value>& args) {
999
9
  Environment* env = Environment::GetCurrent(args);
1000
9
  Isolate* isolate = env->isolate();
1001
1002
9
  int argc = args.Length();
1003
9
  CHECK_GE(argc, 3);
1004
1005
9
  BufferValue src(isolate, args[0]);
1006
9
  CHECK_NOT_NULL(*src);
1007
1008
18
  BufferValue dest(isolate, args[1]);
1009
9
  CHECK_NOT_NULL(*dest);
1010
1011
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1012
9
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1013
4
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1014
8
                  AfterNoArgs, uv_fs_link, *src, *dest);
1015
  } else {  // link(src, dest)
1016
5
    CHECK_EQ(argc, 4);
1017
5
    FSReqWrapSync req_wrap_sync;
1018

5
    FS_SYNC_TRACE_BEGIN(link);
1019
    SyncCall(env, args[3], &req_wrap_sync, "link",
1020
10
             uv_fs_link, *src, *dest);
1021

5
    FS_SYNC_TRACE_END(link);
1022
9
  }
1023
9
}
1024
1025
72
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1026
72
  Environment* env = Environment::GetCurrent(args);
1027
72
  Isolate* isolate = env->isolate();
1028
1029
72
  int argc = args.Length();
1030
72
  CHECK_GE(argc, 3);
1031
1032
72
  BufferValue path(isolate, args[0]);
1033
72
  CHECK_NOT_NULL(*path);
1034
1035
72
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1036
1037
72
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1038
72
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1039
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1040
33
              uv_fs_readlink, *path);
1041
  } else {
1042
39
    CHECK_EQ(argc, 4);
1043
39
    FSReqWrapSync req_wrap_sync;
1044

39
    FS_SYNC_TRACE_BEGIN(readlink);
1045
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1046
78
                       uv_fs_readlink, *path);
1047

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

76
    args.GetReturnValue().Set(rc.ToLocalChecked());
1065
71
  }
1066
}
1067
1068
8
static void Rename(const FunctionCallbackInfo<Value>& args) {
1069
8
  Environment* env = Environment::GetCurrent(args);
1070
8
  Isolate* isolate = env->isolate();
1071
1072
8
  int argc = args.Length();
1073
8
  CHECK_GE(argc, 3);
1074
1075
8
  BufferValue old_path(isolate, args[0]);
1076
8
  CHECK_NOT_NULL(*old_path);
1077
16
  BufferValue new_path(isolate, args[1]);
1078
8
  CHECK_NOT_NULL(*new_path);
1079
1080
8
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1081
8
  if (req_wrap_async != nullptr) {
1082
5
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1083
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1084
10
                  *old_path, *new_path);
1085
  } else {
1086
3
    CHECK_EQ(argc, 4);
1087
3
    FSReqWrapSync req_wrap_sync;
1088

3
    FS_SYNC_TRACE_BEGIN(rename);
1089
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1090
6
             *old_path, *new_path);
1091

3
    FS_SYNC_TRACE_END(rename);
1092
8
  }
1093
8
}
1094
1095
41
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1096
41
  Environment* env = Environment::GetCurrent(args);
1097
1098
41
  const int argc = args.Length();
1099
41
  CHECK_GE(argc, 3);
1100
1101
82
  CHECK(args[0]->IsInt32());
1102
123
  const int fd = args[0].As<Int32>()->Value();
1103
1104
82
  CHECK(args[1]->IsNumber());
1105
123
  const int64_t len = args[1].As<Integer>()->Value();
1106
1107
41
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1108
41
  if (req_wrap_async != nullptr) {
1109
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1110
28
              uv_fs_ftruncate, fd, len);
1111
  } else {
1112
13
    CHECK_EQ(argc, 4);
1113
13
    FSReqWrapSync req_wrap_sync;
1114

13
    FS_SYNC_TRACE_BEGIN(ftruncate);
1115
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1116
13
             len);
1117

13
    FS_SYNC_TRACE_END(ftruncate);
1118
  }
1119
41
}
1120
1121
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1122
7
  Environment* env = Environment::GetCurrent(args);
1123
1124
7
  const int argc = args.Length();
1125
7
  CHECK_GE(argc, 2);
1126
1127
14
  CHECK(args[0]->IsInt32());
1128
21
  const int fd = args[0].As<Int32>()->Value();
1129
1130
7
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1131
7
  if (req_wrap_async != nullptr) {
1132
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1133
4
              uv_fs_fdatasync, fd);
1134
  } else {
1135
3
    CHECK_EQ(argc, 3);
1136
3
    FSReqWrapSync req_wrap_sync;
1137

3
    FS_SYNC_TRACE_BEGIN(fdatasync);
1138
3
    SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1139

3
    FS_SYNC_TRACE_END(fdatasync);
1140
  }
1141
7
}
1142
1143
11
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1144
11
  Environment* env = Environment::GetCurrent(args);
1145
1146
11
  const int argc = args.Length();
1147
11
  CHECK_GE(argc, 2);
1148
1149
22
  CHECK(args[0]->IsInt32());
1150
33
  const int fd = args[0].As<Int32>()->Value();
1151
1152
11
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1153
11
  if (req_wrap_async != nullptr) {
1154
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1155
6
              uv_fs_fsync, fd);
1156
  } else {
1157
5
    CHECK_EQ(argc, 3);
1158
5
    FSReqWrapSync req_wrap_sync;
1159

5
    FS_SYNC_TRACE_BEGIN(fsync);
1160
5
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1161

5
    FS_SYNC_TRACE_END(fsync);
1162
  }
1163
11
}
1164
1165
445
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1166
445
  Environment* env = Environment::GetCurrent(args);
1167
1168
445
  const int argc = args.Length();
1169
445
  CHECK_GE(argc, 2);
1170
1171
445
  BufferValue path(env->isolate(), args[0]);
1172
445
  CHECK_NOT_NULL(*path);
1173
1174
445
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1175
445
  if (req_wrap_async != nullptr) {
1176
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1177
7
              uv_fs_unlink, *path);
1178
  } else {
1179
438
    CHECK_EQ(argc, 3);
1180
438
    FSReqWrapSync req_wrap_sync;
1181

438
    FS_SYNC_TRACE_BEGIN(unlink);
1182
876
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1183

438
    FS_SYNC_TRACE_END(unlink);
1184
445
  }
1185
445
}
1186
1187
637
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1188
637
  Environment* env = Environment::GetCurrent(args);
1189
1190
637
  const int argc = args.Length();
1191
637
  CHECK_GE(argc, 2);
1192
1193
637
  BufferValue path(env->isolate(), args[0]);
1194
637
  CHECK_NOT_NULL(*path);
1195
1196
637
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1197
637
  if (req_wrap_async != nullptr) {
1198
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1199
4
              uv_fs_rmdir, *path);
1200
  } else {  // rmdir(path, undefined, ctx)
1201
633
    CHECK_EQ(argc, 3);
1202
633
    FSReqWrapSync req_wrap_sync;
1203

633
    FS_SYNC_TRACE_BEGIN(rmdir);
1204
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1205
1266
             uv_fs_rmdir, *path);
1206

633
    FS_SYNC_TRACE_END(rmdir);
1207
637
  }
1208
637
}
1209
1210
15
int MKDirpSync(uv_loop_t* loop, uv_fs_t* req, const std::string& path, int mode,
1211
               uv_fs_cb cb = nullptr) {
1212
15
  FSContinuationData continuation_data(req, mode, cb);
1213
15
  continuation_data.PushPath(std::move(path));
1214
1215
15
  while (continuation_data.paths.size() > 0) {
1216
25
    std::string next_path = continuation_data.PopPath();
1217
25
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1218
    while (true) {
1219

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

6
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) return UV_EEXIST;
1244
5
          if (err < 0) return err;
1245
4
          break;
1246
      }
1247
13
      break;
1248
    }
1249
13
    uv_fs_req_cleanup(req);
1250
13
  }
1251
1252
3
  return 0;
1253
}
1254
1255
13
int MKDirpAsync(uv_loop_t* loop,
1256
                uv_fs_t* req,
1257
                const char* path,
1258
                int mode,
1259
                uv_fs_cb cb) {
1260
13
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1261
  // on the first iteration of algorithm, stash state information.
1262
13
  if (req_wrap->continuation_data == nullptr) {
1263
21
    req_wrap->continuation_data = std::unique_ptr<FSContinuationData>{
1264
14
      new FSContinuationData(req, mode, cb)};
1265
7
    req_wrap->continuation_data->PushPath(std::move(path));
1266
  }
1267
1268
  // on each iteration of algorithm, mkdir directory on top of stack.
1269
13
  std::string next_path = req_wrap->continuation_data->PopPath();
1270
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1271
39
                        uv_fs_callback_t{[](uv_fs_t* req) {
1272
13
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1273
13
    Environment* env = req_wrap->env();
1274
13
    uv_loop_t* loop = env->event_loop();
1275
13
    std::string path = req->path;
1276
13
    int err = req->result;
1277
1278
    while (true) {
1279

14
      switch (err) {
1280
        case 0: {
1281
7
          if (req_wrap->continuation_data->paths.size() == 0) {
1282
4
            req_wrap->continuation_data->Done(0);
1283
          } else {
1284
3
            uv_fs_req_cleanup(req);
1285
            MKDirpAsync(loop, req, path.c_str(),
1286
3
                        req_wrap->continuation_data->mode, nullptr);
1287
          }
1288
7
          break;
1289
        }
1290
        case UV_ENOENT: {
1291
          std::string dirname = path.substr(0,
1292
4
                                            path.find_last_of(kPathSeparator));
1293
4
          if (dirname != path) {
1294
3
            req_wrap->continuation_data->PushPath(std::move(path));
1295
3
            req_wrap->continuation_data->PushPath(std::move(dirname));
1296
1
          } else if (req_wrap->continuation_data->paths.size() == 0) {
1297
1
            err = UV_EEXIST;
1298
1
            continue;
1299
          }
1300
3
          uv_fs_req_cleanup(req);
1301
          MKDirpAsync(loop, req, path.c_str(),
1302
3
                      req_wrap->continuation_data->mode, nullptr);
1303
3
          break;
1304
        }
1305
        case UV_EPERM: {
1306
          req_wrap->continuation_data->Done(err);
1307
          break;
1308
        }
1309
        default:
1310

6
          if (err == UV_EEXIST &&
1311
3
              req_wrap->continuation_data->paths.size() > 0) {
1312
            uv_fs_req_cleanup(req);
1313
            MKDirpAsync(loop, req, path.c_str(),
1314
                        req_wrap->continuation_data->mode, nullptr);
1315
          } else {
1316
            // verify that the path pointed to is actually a directory.
1317
3
            uv_fs_req_cleanup(req);
1318
            int err = uv_fs_stat(loop, req, path.c_str(),
1319
9
                                 uv_fs_callback_t{[](uv_fs_t* req) {
1320
3
              FSReqBase* req_wrap = FSReqBase::from_req(req);
1321
3
              int err = req->result;
1322

3
              if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1323
3
              req_wrap->continuation_data->Done(err);
1324
12
            }});
1325
3
            if (err < 0) req_wrap->continuation_data->Done(err);
1326
          }
1327
3
          break;
1328
      }
1329
13
      break;
1330
    }
1331
52
  }});
1332
1333
13
  return err;
1334
}
1335
1336
4478
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1337
4478
  Environment* env = Environment::GetCurrent(args);
1338
1339
4478
  const int argc = args.Length();
1340
4478
  CHECK_GE(argc, 4);
1341
1342
4478
  BufferValue path(env->isolate(), args[0]);
1343
4478
  CHECK_NOT_NULL(*path);
1344
1345
8956
  CHECK(args[1]->IsInt32());
1346
13434
  const int mode = args[1].As<Int32>()->Value();
1347
1348
8956
  CHECK(args[2]->IsBoolean());
1349
8956
  bool mkdirp = args[2]->IsTrue();
1350
1351
4478
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1352
4478
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1353
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1354
296
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1355
  } else {  // mkdir(path, mode, undefined, ctx)
1356
4182
    CHECK_EQ(argc, 5);
1357
4182
    FSReqWrapSync req_wrap_sync;
1358

4182
    FS_SYNC_TRACE_BEGIN(mkdir);
1359
4182
    if (mkdirp) {
1360
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1361
30
               MKDirpSync, *path, mode);
1362
    } else {
1363
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1364
8334
               uv_fs_mkdir, *path, mode);
1365
    }
1366

4182
    FS_SYNC_TRACE_END(mkdir);
1367
4478
  }
1368
4478
}
1369
1370
36
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1371
36
  Environment* env = Environment::GetCurrent(args);
1372
36
  Isolate* isolate = env->isolate();
1373
1374
36
  const int argc = args.Length();
1375
36
  CHECK_GE(argc, 3);
1376
1377
36
  BufferValue path(isolate, args[0]);
1378
36
  CHECK_NOT_NULL(*path);
1379
1380
36
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1381
1382
36
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1383
36
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1384
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1385
18
              uv_fs_realpath, *path);
1386
  } else {  // realpath(path, encoding, undefined, ctx)
1387
18
    CHECK_EQ(argc, 4);
1388
18
    FSReqWrapSync req_wrap_sync;
1389

18
    FS_SYNC_TRACE_BEGIN(realpath);
1390
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1391
36
                       uv_fs_realpath, *path);
1392

18
    FS_SYNC_TRACE_END(realpath);
1393
18
    if (err < 0) {
1394
2
      return;  // syscall failed, no need to continue, error info is in ctx
1395
    }
1396
1397
16
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1398
1399
    Local<Value> error;
1400
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1401
                                               link_path,
1402
                                               encoding,
1403
16
                                               &error);
1404
16
    if (rc.IsEmpty()) {
1405
      Local<Object> ctx = args[3].As<Object>();
1406
      ctx->Set(env->context(), env->error_string(), error).FromJust();
1407
      return;
1408
    }
1409
1410

32
    args.GetReturnValue().Set(rc.ToLocalChecked());
1411
34
  }
1412
}
1413
1414
10454
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1415
10454
  Environment* env = Environment::GetCurrent(args);
1416
10454
  Isolate* isolate = env->isolate();
1417
1418
10454
  const int argc = args.Length();
1419
10454
  CHECK_GE(argc, 3);
1420
1421
10454
  BufferValue path(isolate, args[0]);
1422
10454
  CHECK_NOT_NULL(*path);
1423
1424
10454
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1425
1426
20908
  bool with_types = args[2]->IsTrue();
1427
1428
10454
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1429
10454
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1430
31
    if (with_types) {
1431
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1432
4
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1433
    } else {
1434
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1435
27
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1436
    }
1437
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1438
10423
    CHECK_EQ(argc, 5);
1439
10423
    FSReqWrapSync req_wrap_sync;
1440

10423
    FS_SYNC_TRACE_BEGIN(readdir);
1441
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1442
20846
                       uv_fs_scandir, *path, 0 /*flags*/);
1443

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

53916
    FS_SYNC_TRACE_BEGIN(open);
1526
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1527
107831
                          uv_fs_open, *path, flags, mode);
1528

53916
    FS_SYNC_TRACE_END(open);
1529
107830
    args.GetReturnValue().Set(result);
1530
56651
  }
1531
56651
}
1532
1533
61
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1534
61
  Environment* env = Environment::GetCurrent(args);
1535
61
  Isolate* isolate = env->isolate();
1536
1537
61
  const int argc = args.Length();
1538
61
  CHECK_GE(argc, 3);
1539
1540
61
  BufferValue path(isolate, args[0]);
1541
61
  CHECK_NOT_NULL(*path);
1542
1543
122
  CHECK(args[1]->IsInt32());
1544
183
  const int flags = args[1].As<Int32>()->Value();
1545
1546
122
  CHECK(args[2]->IsInt32());
1547
183
  const int mode = args[2].As<Int32>()->Value();
1548
1549
61
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1550
61
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1551
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1552
60
              uv_fs_open, *path, flags, mode);
1553
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1554
1
    CHECK_EQ(argc, 5);
1555
1
    FSReqWrapSync req_wrap_sync;
1556

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

1
    FS_SYNC_TRACE_END(open);
1560
1
    if (result < 0) {
1561
61
      return;  // syscall failed, no need to continue, error info is in ctx
1562
    }
1563
2
    HandleScope scope(isolate);
1564
1
    FileHandle* fd = new FileHandle(env, result);
1565
4
    args.GetReturnValue().Set(fd->object());
1566
61
  }
1567
}
1568
1569
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1570
33
  Environment* env = Environment::GetCurrent(args);
1571
33
  Isolate* isolate = env->isolate();
1572
1573
33
  const int argc = args.Length();
1574
33
  CHECK_GE(argc, 3);
1575
1576
33
  BufferValue src(isolate, args[0]);
1577
33
  CHECK_NOT_NULL(*src);
1578
1579
66
  BufferValue dest(isolate, args[1]);
1580
33
  CHECK_NOT_NULL(*dest);
1581
1582
66
  CHECK(args[2]->IsInt32());
1583
99
  const int flags = args[2].As<Int32>()->Value();
1584
1585
33
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1586
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1587
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1588
13
                  *dest, dest.length(), UTF8, AfterNoArgs,
1589
26
                  uv_fs_copyfile, *src, *dest, flags);
1590
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1591
20
    CHECK_EQ(argc, 5);
1592
20
    FSReqWrapSync req_wrap_sync;
1593

20
    FS_SYNC_TRACE_BEGIN(copyfile);
1594
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1595
40
             uv_fs_copyfile, *src, *dest, flags);
1596

20
    FS_SYNC_TRACE_END(copyfile);
1597
33
  }
1598
33
}
1599
1600
1601
// Wrapper for write(2).
1602
//
1603
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1604
// 0 fd        integer. file descriptor
1605
// 1 buffer    the data to write
1606
// 2 offset    where in the buffer to start from
1607
// 3 length    how much to write
1608
// 4 position  if integer, position to write at in the file.
1609
//             if null, write from the current position
1610
28516
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1611
28516
  Environment* env = Environment::GetCurrent(args);
1612
1613
28516
  const int argc = args.Length();
1614
28516
  CHECK_GE(argc, 4);
1615
1616
57032
  CHECK(args[0]->IsInt32());
1617
85548
  const int fd = args[0].As<Int32>()->Value();
1618
1619
28516
  CHECK(Buffer::HasInstance(args[1]));
1620
57032
  Local<Object> buffer_obj = args[1].As<Object>();
1621
28516
  char* buffer_data = Buffer::Data(buffer_obj);
1622
28516
  size_t buffer_length = Buffer::Length(buffer_obj);
1623
1624
57032
  CHECK(args[2]->IsInt32());
1625
85548
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1626
28516
  CHECK_LE(off, buffer_length);
1627
1628
57032
  CHECK(args[3]->IsInt32());
1629
85548
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1630
28516
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1631
28516
  CHECK_LE(len, buffer_length);
1632
28516
  CHECK_GE(off + len, off);
1633
1634

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

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

17183
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1650
51549
    args.GetReturnValue().Set(bytesWritten);
1651
  }
1652
28516
}
1653
1654
1655
// Wrapper for writev(2).
1656
//
1657
// bytesWritten = writev(fd, chunks, position, callback)
1658
// 0 fd        integer. file descriptor
1659
// 1 chunks    array of buffers to write
1660
// 2 position  if integer, position to write at in the file.
1661
//             if null, write from the current position
1662
8
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1663
8
  Environment* env = Environment::GetCurrent(args);
1664
1665
8
  const int argc = args.Length();
1666
8
  CHECK_GE(argc, 3);
1667
1668
16
  CHECK(args[0]->IsInt32());
1669
24
  const int fd = args[0].As<Int32>()->Value();
1670
1671
16
  CHECK(args[1]->IsArray());
1672
16
  Local<Array> chunks = args[1].As<Array>();
1673
1674

16
  int64_t pos = GET_OFFSET(args[2]);
1675
1676
8
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1677
1678
238
  for (uint32_t i = 0; i < iovs.length(); i++) {
1679
690
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1680
230
    CHECK(Buffer::HasInstance(chunk));
1681
230
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1682
  }
1683
1684
8
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1685
8
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1686
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1687
8
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1688
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1689
    CHECK_EQ(argc, 5);
1690
    FSReqWrapSync req_wrap_sync;
1691
    FS_SYNC_TRACE_BEGIN(write);
1692
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1693
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1694
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1695
    args.GetReturnValue().Set(bytesWritten);
1696
8
  }
1697
8
}
1698
1699
1700
// Wrapper for write(2).
1701
//
1702
// bytesWritten = write(fd, string, position, enc, callback)
1703
// 0 fd        integer. file descriptor
1704
// 1 string    non-buffer values are converted to strings
1705
// 2 position  if integer, position to write at in the file.
1706
//             if null, write from the current position
1707
// 3 enc       encoding of string
1708
1143
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1709
1143
  Environment* env = Environment::GetCurrent(args);
1710
1143
  Isolate* isolate = env->isolate();
1711
1712
1143
  const int argc = args.Length();
1713
1143
  CHECK_GE(argc, 4);
1714
1715
2286
  CHECK(args[0]->IsInt32());
1716
3429
  const int fd = args[0].As<Int32>()->Value();
1717
1718

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

3369
  if (!is_async && value->IsString()) {
1737
1113
    auto string = value.As<String>();
1738


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


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

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

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

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

49603
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1849
148809
    args.GetReturnValue().Set(bytesRead);
1850
  }
1851
187186
}
1852
1853
1854
/* fs.chmod(path, mode);
1855
 * Wrapper for chmod(1) / EIO_CHMOD
1856
 */
1857
21
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1858
21
  Environment* env = Environment::GetCurrent(args);
1859
1860
21
  const int argc = args.Length();
1861
21
  CHECK_GE(argc, 2);
1862
1863
21
  BufferValue path(env->isolate(), args[0]);
1864
21
  CHECK_NOT_NULL(*path);
1865
1866
42
  CHECK(args[1]->IsInt32());
1867
63
  int mode = args[1].As<Int32>()->Value();
1868
1869
21
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1870
21
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1871
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1872
11
              uv_fs_chmod, *path, mode);
1873
  } else {  // chmod(path, mode, undefined, ctx)
1874
10
    CHECK_EQ(argc, 4);
1875
10
    FSReqWrapSync req_wrap_sync;
1876

10
    FS_SYNC_TRACE_BEGIN(chmod);
1877
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1878
20
             uv_fs_chmod, *path, mode);
1879

10
    FS_SYNC_TRACE_END(chmod);
1880
21
  }
1881
21
}
1882
1883
1884
/* fs.fchmod(fd, mode);
1885
 * Wrapper for fchmod(1) / EIO_FCHMOD
1886
 */
1887
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1888
12
  Environment* env = Environment::GetCurrent(args);
1889
1890
12
  const int argc = args.Length();
1891
12
  CHECK_GE(argc, 2);
1892
1893
24
  CHECK(args[0]->IsInt32());
1894
36
  const int fd = args[0].As<Int32>()->Value();
1895
1896
24
  CHECK(args[1]->IsInt32());
1897
36
  const int mode = args[1].As<Int32>()->Value();
1898
1899
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1900
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1901
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1902
7
              uv_fs_fchmod, fd, mode);
1903
  } else {  // fchmod(fd, mode, undefined, ctx)
1904
5
    CHECK_EQ(argc, 4);
1905
5
    FSReqWrapSync req_wrap_sync;
1906

5
    FS_SYNC_TRACE_BEGIN(fchmod);
1907
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1908
5
             uv_fs_fchmod, fd, mode);
1909

5
    FS_SYNC_TRACE_END(fchmod);
1910
  }
1911
12
}
1912
1913
1914
/* fs.chown(path, uid, gid);
1915
 * Wrapper for chown(1) / EIO_CHOWN
1916
 */
1917
8
static void Chown(const FunctionCallbackInfo<Value>& args) {
1918
8
  Environment* env = Environment::GetCurrent(args);
1919
1920
8
  const int argc = args.Length();
1921
8
  CHECK_GE(argc, 3);
1922
1923
8
  BufferValue path(env->isolate(), args[0]);
1924
8
  CHECK_NOT_NULL(*path);
1925
1926
16
  CHECK(args[1]->IsUint32());
1927
24
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1928
1929
16
  CHECK(args[2]->IsUint32());
1930
24
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1931
1932
8
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1933
8
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1934
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1935
6
              uv_fs_chown, *path, uid, gid);
1936
  } else {  // chown(path, uid, gid, undefined, ctx)
1937
2
    CHECK_EQ(argc, 5);
1938
2
    FSReqWrapSync req_wrap_sync;
1939

2
    FS_SYNC_TRACE_BEGIN(chown);
1940
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1941
4
             uv_fs_chown, *path, uid, gid);
1942

2
    FS_SYNC_TRACE_END(chown);
1943
8
  }
1944
8
}
1945
1946
1947
/* fs.fchown(fd, uid, gid);
1948
 * Wrapper for fchown(1) / EIO_FCHOWN
1949
 */
1950
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
1951
4
  Environment* env = Environment::GetCurrent(args);
1952
1953
4
  const int argc = args.Length();
1954
4
  CHECK_GE(argc, 3);
1955
1956
8
  CHECK(args[0]->IsInt32());
1957
12
  const int fd = args[0].As<Int32>()->Value();
1958
1959
8
  CHECK(args[1]->IsUint32());
1960
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1961
1962
8
  CHECK(args[2]->IsUint32());
1963
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1964
1965
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1966
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
1967
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
1968
2
              uv_fs_fchown, fd, uid, gid);
1969
  } else {  // fchown(fd, uid, gid, undefined, ctx)
1970
2
    CHECK_EQ(argc, 5);
1971
2
    FSReqWrapSync req_wrap_sync;
1972

2
    FS_SYNC_TRACE_BEGIN(fchown);
1973
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
1974
2
             uv_fs_fchown, fd, uid, gid);
1975

2
    FS_SYNC_TRACE_END(fchown);
1976
  }
1977
4
}
1978
1979
1980
5
static void LChown(const FunctionCallbackInfo<Value>& args) {
1981
5
  Environment* env = Environment::GetCurrent(args);
1982
1983
5
  const int argc = args.Length();
1984
5
  CHECK_GE(argc, 3);
1985
1986
5
  BufferValue path(env->isolate(), args[0]);
1987
5
  CHECK_NOT_NULL(*path);
1988
1989
10
  CHECK(args[1]->IsUint32());
1990
15
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1991
1992
10
  CHECK(args[2]->IsUint32());
1993
15
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1994
1995
5
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1996
5
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
1997
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
1998
3
              uv_fs_lchown, *path, uid, gid);
1999
  } else {  // lchown(path, uid, gid, undefined, ctx)
2000
2
    CHECK_EQ(argc, 5);
2001
2
    FSReqWrapSync req_wrap_sync;
2002

2
    FS_SYNC_TRACE_BEGIN(lchown);
2003
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2004
4
             uv_fs_lchown, *path, uid, gid);
2005

2
    FS_SYNC_TRACE_END(lchown);
2006
5
  }
2007
5
}
2008
2009
2010
9
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2011
9
  Environment* env = Environment::GetCurrent(args);
2012
2013
9
  const int argc = args.Length();
2014
9
  CHECK_GE(argc, 3);
2015
2016
9
  BufferValue path(env->isolate(), args[0]);
2017
9
  CHECK_NOT_NULL(*path);
2018
2019
18
  CHECK(args[1]->IsNumber());
2020
27
  const double atime = args[1].As<Number>()->Value();
2021
2022
18
  CHECK(args[2]->IsNumber());
2023
27
  const double mtime = args[2].As<Number>()->Value();
2024
2025
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2026
9
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2027
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2028
4
              uv_fs_utime, *path, atime, mtime);
2029
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2030
5
    CHECK_EQ(argc, 5);
2031
5
    FSReqWrapSync req_wrap_sync;
2032

5
    FS_SYNC_TRACE_BEGIN(utimes);
2033
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2034
10
             uv_fs_utime, *path, atime, mtime);
2035

5
    FS_SYNC_TRACE_END(utimes);
2036
9
  }
2037
9
}
2038
2039
715
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2040
715
  Environment* env = Environment::GetCurrent(args);
2041
2042
715
  const int argc = args.Length();
2043
715
  CHECK_GE(argc, 3);
2044
2045
1430
  CHECK(args[0]->IsInt32());
2046
2145
  const int fd = args[0].As<Int32>()->Value();
2047
2048
1430
  CHECK(args[1]->IsNumber());
2049
2145
  const double atime = args[1].As<Number>()->Value();
2050
2051
1430
  CHECK(args[2]->IsNumber());
2052
2145
  const double mtime = args[2].As<Number>()->Value();
2053
2054
715
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2055
715
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2056
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2057
712
              uv_fs_futime, fd, atime, mtime);
2058
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2059
3
    CHECK_EQ(argc, 5);
2060
3
    FSReqWrapSync req_wrap_sync;
2061

3
    FS_SYNC_TRACE_BEGIN(futimes);
2062
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2063
3
             uv_fs_futime, fd, atime, mtime);
2064

3
    FS_SYNC_TRACE_END(futimes);
2065
  }
2066
715
}
2067
2068
12
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2069
12
  Environment* env = Environment::GetCurrent(args);
2070
12
  Isolate* isolate = env->isolate();
2071
2072
12
  const int argc = args.Length();
2073
12
  CHECK_GE(argc, 2);
2074
2075
12
  BufferValue tmpl(isolate, args[0]);
2076
12
  CHECK_NOT_NULL(*tmpl);
2077
2078
12
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2079
2080
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2081
12
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2082
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2083
5
              uv_fs_mkdtemp, *tmpl);
2084
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2085
7
    CHECK_EQ(argc, 4);
2086
7
    FSReqWrapSync req_wrap_sync;
2087

7
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2088
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2089
14
             uv_fs_mkdtemp, *tmpl);
2090

7
    FS_SYNC_TRACE_END(mkdtemp);
2091
7
    const char* path = static_cast<const char*>(req_wrap_sync.req.path);
2092
2093
    Local<Value> error;
2094
    MaybeLocal<Value> rc =
2095
7
        StringBytes::Encode(isolate, path, encoding, &error);
2096
7
    if (rc.IsEmpty()) {
2097
      Local<Object> ctx = args[3].As<Object>();
2098
      ctx->Set(env->context(), env->error_string(), error).FromJust();
2099
12
      return;
2100
    }
2101

14
    args.GetReturnValue().Set(rc.ToLocalChecked());
2102
12
  }
2103
}
2104
2105
3661
void Initialize(Local<Object> target,
2106
                Local<Value> unused,
2107
                Local<Context> context,
2108
                void* priv) {
2109
3661
  Environment* env = Environment::GetCurrent(context);
2110
3661
  Isolate* isolate = env->isolate();
2111
2112
3661
  env->SetMethod(target, "access", Access);
2113
3661
  env->SetMethod(target, "close", Close);
2114
3661
  env->SetMethod(target, "open", Open);
2115
3661
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2116
3661
  env->SetMethod(target, "read", Read);
2117
3661
  env->SetMethod(target, "fdatasync", Fdatasync);
2118
3661
  env->SetMethod(target, "fsync", Fsync);
2119
3661
  env->SetMethod(target, "rename", Rename);
2120
3661
  env->SetMethod(target, "ftruncate", FTruncate);
2121
3661
  env->SetMethod(target, "rmdir", RMDir);
2122
3661
  env->SetMethod(target, "mkdir", MKDir);
2123
3661
  env->SetMethod(target, "readdir", ReadDir);
2124
3661
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2125
3661
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2126
3661
  env->SetMethod(target, "stat", Stat);
2127
3661
  env->SetMethod(target, "lstat", LStat);
2128
3661
  env->SetMethod(target, "fstat", FStat);
2129
3661
  env->SetMethod(target, "link", Link);
2130
3661
  env->SetMethod(target, "symlink", Symlink);
2131
3661
  env->SetMethod(target, "readlink", ReadLink);
2132
3661
  env->SetMethod(target, "unlink", Unlink);
2133
3661
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2134
3661
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2135
3661
  env->SetMethod(target, "writeString", WriteString);
2136
3661
  env->SetMethod(target, "realpath", RealPath);
2137
3661
  env->SetMethod(target, "copyFile", CopyFile);
2138
2139
3661
  env->SetMethod(target, "chmod", Chmod);
2140
3661
  env->SetMethod(target, "fchmod", FChmod);
2141
  // env->SetMethod(target, "lchmod", LChmod);
2142
2143
3661
  env->SetMethod(target, "chown", Chown);
2144
3661
  env->SetMethod(target, "fchown", FChown);
2145
3661
  env->SetMethod(target, "lchown", LChown);
2146
2147
3661
  env->SetMethod(target, "utimes", UTimes);
2148
3661
  env->SetMethod(target, "futimes", FUTimes);
2149
2150
3661
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2151
2152
  target->Set(context,
2153
              FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2154
14644
              Integer::New(isolate, kFsStatsFieldsNumber))
2155
7322
        .FromJust();
2156
2157
  target->Set(context,
2158
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2159
14644
              env->fs_stats_field_array()->GetJSArray()).FromJust();
2160
2161
  target->Set(context,
2162
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2163
14644
              env->fs_stats_field_bigint_array()->GetJSArray()).FromJust();
2164
2165
3661
  StatWatcher::Initialize(env, target);
2166
2167
  // Create FunctionTemplate for FSReqCallback
2168
3661
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2169
7322
  fst->InstanceTemplate()->SetInternalFieldCount(1);
2170
7322
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2171
  Local<String> wrapString =
2172
3661
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2173
3661
  fst->SetClassName(wrapString);
2174
  target
2175
      ->Set(context, wrapString,
2176
14644
            fst->GetFunction(env->context()).ToLocalChecked())
2177
7322
      .FromJust();
2178
2179
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2180
  // to do anything in the constructor, so we only store the instance template.
2181
3661
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2182
7322
  fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2183
7322
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2184
  Local<String> fhWrapString =
2185
3661
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2186
3661
  fh_rw->SetClassName(fhWrapString);
2187
  env->set_filehandlereadwrap_template(
2188
3661
      fst->InstanceTemplate());
2189
2190
  // Create Function Template for FSReqPromise
2191
3661
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2192
7322
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2193
  Local<String> promiseString =
2194
3661
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2195
3661
  fpt->SetClassName(promiseString);
2196
3661
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2197
3661
  fpo->SetInternalFieldCount(1);
2198
3661
  env->set_fsreqpromise_constructor_template(fpo);
2199
2200
  // Create FunctionTemplate for FileHandle
2201
3661
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2202
7322
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2203
3661
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2204
3661
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2205
3661
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2206
3661
  fdt->SetInternalFieldCount(1);
2207
  Local<String> handleString =
2208
3661
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2209
3661
  fd->SetClassName(handleString);
2210
3661
  StreamBase::AddMethods<FileHandle>(env, fd);
2211
  target
2212
      ->Set(context, handleString,
2213
14644
            fd->GetFunction(env->context()).ToLocalChecked())
2214
7322
      .FromJust();
2215
3661
  env->set_fd_constructor_template(fdt);
2216
2217
  // Create FunctionTemplate for FileHandle::CloseReq
2218
3661
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2219
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2220
7322
                        "FileHandleCloseReq"));
2221
7322
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2222
3661
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2223
3661
  fdcloset->SetInternalFieldCount(1);
2224
3661
  env->set_fdclose_constructor_template(fdcloset);
2225
2226
  Local<Symbol> use_promises_symbol =
2227
    Symbol::New(isolate,
2228
3661
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2229
3661
  env->set_fs_use_promises_symbol(use_promises_symbol);
2230
  target->Set(context,
2231
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2232
10983
              use_promises_symbol).FromJust();
2233
3661
}
2234
2235
}  // namespace fs
2236
2237
}  // end namespace node
2238
2239
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)