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: 1214 1294 93.8 %
Date: 2019-03-02 22:23:06 Branches: 788 1188 66.3 %

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 <cstring>
40
#include <cerrno>
41
#include <climits>
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 S_ISDIR
78
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
79
#endif
80
81
#ifdef __POSIX__
82
constexpr char kPathSeparator = '/';
83
#else
84
const char* const kPathSeparator = "\\/";
85
#endif
86
87
#define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
88
#define TRACE_NAME(name) "fs.sync." #name
89
#define GET_TRACE_ENABLED                                                  \
90
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
91
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
92
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
93
  if (GET_TRACE_ENABLED)                                                   \
94
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
95
  ##__VA_ARGS__);
96
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
97
  if (GET_TRACE_ENABLED)                                                   \
98
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
99
  ##__VA_ARGS__);
100
101
// We sometimes need to convert a C++ lambda function to a raw C-style function.
102
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
103
// functions, and thus does not wrap them properly.
104
typedef void(*uv_fs_callback_t)(uv_fs_t*);
105
106
// The FileHandle object wraps a file descriptor and will close it on garbage
107
// collection if necessary. If that happens, a process warning will be
108
// emitted (or a fatal exception will occur if the fd cannot be closed.)
109
78
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
110
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
111
      StreamBase(env),
112
78
      fd_(fd) {
113
78
  MakeWeak();
114
78
}
115
116
78
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
117

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

41
  if (!closed_ && !closing_) {
240
41
    closing_ = true;
241
    Local<Object> close_req_obj;
242
82
    if (!env()
243
41
             ->fdclose_constructor_template()
244
164
             ->NewInstance(env()->context())
245
123
             .ToLocal(&close_req_obj)) {
246
      return MaybeLocal<Promise>();
247
    }
248
82
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
249
123
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
250
41
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
251
41
      CHECK_NOT_NULL(close);
252
41
      close->file_handle()->AfterClose();
253
41
      Isolate* isolate = close->env()->isolate();
254
41
      if (req->result < 0) {
255
        close->Reject(UVException(isolate, req->result, "close"));
256
      } else {
257
41
        close->Resolve();
258
      }
259
164
    }};
260
41
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
261
41
    if (ret < 0) {
262
      req->Reject(UVException(isolate, ret, "close"));
263
      delete req;
264
41
    }
265
  } else {
266
    // Already closed. Just reject the promise immediately
267
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
268
        .FromJust();
269
  }
270
41
  return scope.Escape(promise);
271
}
272
273
41
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
274
  FileHandle* fd;
275
41
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
276
  Local<Promise> ret;
277
82
  if (!fd->ClosePromise().ToLocal(&ret)) return;
278
82
  args.GetReturnValue().Set(ret);
279
}
280
281
282
7
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
283
  FileHandle* fd;
284
14
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
285
  // Just act as if this FileHandle has been closed.
286
7
  fd->AfterClose();
287
}
288
289
290
78
void FileHandle::AfterClose() {
291
78
  closing_ = false;
292
78
  closed_ = true;
293

78
  if (reading_ && !persistent().IsEmpty())
294
    EmitRead(UV_EOF);
295
78
}
296
297
2
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
298
2
  tracker->TrackField("buffer", buffer_);
299
2
  tracker->TrackField("file_handle", this->file_handle_);
300
2
}
301
302
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
303
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
304
15
    file_handle_(handle) {}
305
306
226
int FileHandle::ReadStart() {
307

226
  if (!IsAlive() || IsClosing())
308
    return UV_EOF;
309
310
226
  reading_ = true;
311
312
226
  if (current_read_)
313
    return 0;
314
315
226
  std::unique_ptr<FileHandleReadWrap> read_wrap;
316
317
226
  if (read_length_ == 0) {
318
6
    EmitRead(UV_EOF);
319
6
    return 0;
320
  }
321
322
  {
323
    // Create a new FileHandleReadWrap or re-use one.
324
    // Either way, we need these two scopes for AsyncReset() or otherwise
325
    // for creating the new instance.
326
220
    HandleScope handle_scope(env()->isolate());
327
440
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
328
329
220
    auto& freelist = env()->file_handle_read_wrap_freelist();
330
220
    if (freelist.size() > 0) {
331
205
      read_wrap = std::move(freelist.back());
332
205
      freelist.pop_back();
333
205
      read_wrap->AsyncReset();
334
205
      read_wrap->file_handle_ = this;
335
    } else {
336
      Local<Object> wrap_obj;
337
30
      if (!env()
338
15
               ->filehandlereadwrap_template()
339
60
               ->NewInstance(env()->context())
340
45
               .ToLocal(&wrap_obj)) {
341
        return UV_EBUSY;
342
      }
343
15
      read_wrap.reset(new FileHandleReadWrap(this, wrap_obj));
344
220
    }
345
  }
346
220
  int64_t recommended_read = 65536;
347

220
  if (read_length_ >= 0 && read_length_ <= recommended_read)
348
10
    recommended_read = read_length_;
349
350
220
  read_wrap->buffer_ = EmitAlloc(recommended_read);
351
352
220
  current_read_ = std::move(read_wrap);
353
354
220
  current_read_->Dispatch(uv_fs_read,
355
                          fd_,
356
220
                          &current_read_->buffer_,
357
                          1,
358
                          read_offset_,
359
660
                          uv_fs_callback_t{[](uv_fs_t* req) {
360
    FileHandle* handle;
361
    {
362
220
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
363
220
      handle = req_wrap->file_handle_;
364
220
      CHECK_EQ(handle->current_read_.get(), req_wrap);
365
    }
366
367
    // ReadStart() checks whether current_read_ is set to determine whether
368
    // a read is in progress. Moving it into a local variable makes sure that
369
    // the ReadStart() call below doesn't think we're still actively reading.
370
    std::unique_ptr<FileHandleReadWrap> read_wrap =
371
220
        std::move(handle->current_read_);
372
373
220
    int result = req->result;
374
220
    uv_buf_t buffer = read_wrap->buffer_;
375
376
220
    uv_fs_req_cleanup(req);
377
378
    // Push the read wrap back to the freelist, or let it be destroyed
379
    // once we’re exiting the current scope.
380
220
    constexpr size_t wanted_freelist_fill = 100;
381
220
    auto& freelist = handle->env()->file_handle_read_wrap_freelist();
382
220
    if (freelist.size() < wanted_freelist_fill) {
383
220
      read_wrap->Reset();
384
220
      freelist.emplace_back(std::move(read_wrap));
385
    }
386
387
220
    if (result >= 0) {
388
      // Read at most as many bytes as we originally planned to.
389

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







171630
  CHECK_NOT_NULL(req_wrap);
696
171630
  req_wrap->Init(syscall, dest, len, enc);
697
171630
  int err = req_wrap->Dispatch(fn, fn_args..., after);
698







171630
  if (err < 0) {
699
1
    uv_fs_t* uv_req = req_wrap->req();
700
1
    uv_req->result = err;
701
1
    uv_req->path = nullptr;
702
1
    after(uv_req);  // after may delete req_wrap if there is an error
703
1
    req_wrap = nullptr;
704
  } else {
705
171629
    req_wrap->SetReturnValue(args);
706
  }
707
708
171630
  return req_wrap;
709
}
710
711
// Returns nullptr if the operation fails from the start.
712
template <typename Func, typename... Args>
713
171594
inline FSReqBase* AsyncCall(Environment* env,
714
    FSReqBase* req_wrap,
715
    const FunctionCallbackInfo<Value>& args,
716
    const char* syscall, enum encoding enc,
717
    uv_fs_cb after, Func fn, Args... fn_args) {
718
  return AsyncDestCall(env, req_wrap, args,
719
                       syscall, nullptr, 0, enc,
720
171594
                       after, fn, fn_args...);
721
}
722
723
// Template counterpart of SYNC_CALL, except that it only puts
724
// the error number and the syscall in the context instead of
725
// creating an error in the C++ land.
726
// ctx must be checked using value->IsObject() before being passed.
727
template <typename Func, typename... Args>
728
509836
inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap,
729
    const char* syscall, Func fn, Args... args) {
730
509836
  env->PrintSyncTrace();
731
509837
  int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
732







509837
  if (err < 0) {
733
717
    Local<Context> context = env->context();
734
717
    Local<Object> ctx_obj = ctx.As<Object>();
735
717
    Isolate* isolate = env->isolate();
736
    ctx_obj->Set(context,
737
             env->errno_string(),
738
2868
             Integer::New(isolate, err)).FromJust();
739
    ctx_obj->Set(context,
740
             env->syscall_string(),
741
2868
             OneByteString(isolate, syscall)).FromJust();
742
  }
743
509837
  return err;
744
}
745
746
// TODO(addaleax): Currently, callers check the return value and assume
747
// that nullptr indicates a synchronous call, rather than a failure.
748
// Failure conditions should be disambiguated and handled appropriately.
749
681505
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
750
                             bool use_bigint = false) {
751
681505
  if (value->IsObject()) {
752
171325
    return Unwrap<FSReqBase>(value.As<Object>());
753
1020360
  } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
754
343
    if (use_bigint) {
755
3
      return FSReqPromise<uint64_t, BigUint64Array>::New(env, use_bigint);
756
    } else {
757
340
      return FSReqPromise<double, Float64Array>::New(env, use_bigint);
758
    }
759
  }
760
509837
  return nullptr;
761
}
762
763
1067
void Access(const FunctionCallbackInfo<Value>& args) {
764
1067
  Environment* env = Environment::GetCurrent(args);
765
1067
  Isolate* isolate = env->isolate();
766
1067
  HandleScope scope(isolate);
767
768
1067
  const int argc = args.Length();
769
1067
  CHECK_GE(argc, 2);
770
771
2134
  CHECK(args[1]->IsInt32());
772
3201
  int mode = args[1].As<Int32>()->Value();
773
774
2134
  BufferValue path(isolate, args[0]);
775
1067
  CHECK_NOT_NULL(*path);
776
777
1067
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
778
1067
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
779
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
780
44
              uv_fs_access, *path, mode);
781
  } else {  // access(path, mode, undefined, ctx)
782
1023
    CHECK_EQ(argc, 4);
783
1023
    FSReqWrapSync req_wrap_sync;
784

1025
    FS_SYNC_TRACE_BEGIN(access);
785
2046
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
786

1025
    FS_SYNC_TRACE_END(access);
787
1067
  }
788
1067
}
789
790
791
62152
void Close(const FunctionCallbackInfo<Value>& args) {
792
62152
  Environment* env = Environment::GetCurrent(args);
793
794
62152
  const int argc = args.Length();
795
62152
  CHECK_GE(argc, 2);
796
797
124304
  CHECK(args[0]->IsInt32());
798
186456
  int fd = args[0].As<Int32>()->Value();
799
800
62152
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
801
62152
  if (req_wrap_async != nullptr) {  // close(fd, req)
802
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
803
5370
              uv_fs_close, fd);
804
  } else {  // close(fd, undefined, ctx)
805
56782
    CHECK_EQ(argc, 3);
806
56782
    FSReqWrapSync req_wrap_sync;
807

56916
    FS_SYNC_TRACE_BEGIN(close);
808
56782
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
809

56916
    FS_SYNC_TRACE_END(close);
810
  }
811
62152
}
812
813
814
// Used to speed up module loading.  Returns the contents of the file as
815
// a string or undefined when the file cannot be opened or "main" is not found
816
// in the file.
817
15717
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
818
15717
  Environment* env = Environment::GetCurrent(args);
819
15717
  Isolate* isolate = env->isolate();
820
15717
  uv_loop_t* loop = env->event_loop();
821
822
47151
  CHECK(args[0]->IsString());
823
15717
  node::Utf8Value path(isolate, args[0]);
824
825
15717
  if (strlen(*path) != path.length())
826
1
    return;  // Contains a nul byte.
827
828
  uv_fs_t open_req;
829
15716
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
830
15716
  uv_fs_req_cleanup(&open_req);
831
832
15716
  if (fd < 0) {
833
3884
    return;
834
  }
835
836
11832
  std::shared_ptr<void> defer_close(nullptr, [fd, loop] (...) {
837
    uv_fs_t close_req;
838
11832
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
839
11832
    uv_fs_req_cleanup(&close_req);
840
29099
  });
841
842
11832
  const size_t kBlockSize = 32 << 10;
843
17267
  std::vector<char> chars;
844
11832
  int64_t offset = 0;
845
  ssize_t numchars;
846
11831
  do {
847
11832
    const size_t start = chars.size();
848
11832
    chars.resize(start + kBlockSize);
849
850
    uv_buf_t buf;
851
11832
    buf.base = &chars[start];
852
11832
    buf.len = kBlockSize;
853
854
    uv_fs_t read_req;
855
11832
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
856
11832
    uv_fs_req_cleanup(&read_req);
857
858
11832
    if (numchars < 0)
859
1
      return;
860
861
11831
    offset += numchars;
862
  } while (static_cast<size_t>(numchars) == kBlockSize);
863
864
11831
  size_t start = 0;
865

11831
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
866
1
    start = 3;  // Skip UTF-8 BOM.
867
  }
868
869
11831
  const size_t size = offset - start;
870

11831
  if (size == 0 || size == SearchString(&chars[start], size, "\"main\"")) {
871
6396
    return;
872
  } else {
873
    Local<String> chars_string =
874
        String::NewFromUtf8(isolate,
875
5435
                            &chars[start],
876
                            v8::NewStringType::kNormal,
877
16305
                            size).ToLocalChecked();
878
10870
    args.GetReturnValue().Set(chars_string);
879
5435
  }
880
}
881
882
// Used to speed up module loading.  Returns 0 if the path refers to
883
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
884
// The speedup comes from not creating thousands of Stat and Error objects.
885
141104
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
886
141104
  Environment* env = Environment::GetCurrent(args);
887
888
423312
  CHECK(args[0]->IsString());
889
141104
  node::Utf8Value path(env->isolate(), args[0]);
890
891
  uv_fs_t req;
892
141104
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
893
141104
  if (rc == 0) {
894
62693
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
895
62693
    rc = !!(s->st_mode & S_IFDIR);
896
  }
897
141104
  uv_fs_req_cleanup(&req);
898
899
282208
  args.GetReturnValue().Set(rc);
900
141104
}
901
902
33291
static void Stat(const FunctionCallbackInfo<Value>& args) {
903
33291
  Environment* env = Environment::GetCurrent(args);
904
905
33291
  const int argc = args.Length();
906
33291
  CHECK_GE(argc, 2);
907
908
33291
  BufferValue path(env->isolate(), args[0]);
909
33291
  CHECK_NOT_NULL(*path);
910
911
66582
  bool use_bigint = args[1]->IsTrue();
912
66582
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
913
33291
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
914
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
915
1225
              uv_fs_stat, *path);
916
  } else {  // stat(path, use_bigint, undefined, ctx)
917
32066
    CHECK_EQ(argc, 4);
918
32066
    FSReqWrapSync req_wrap_sync;
919

32068
    FS_SYNC_TRACE_BEGIN(stat);
920
64132
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
921

32068
    FS_SYNC_TRACE_END(stat);
922
32066
    if (err != 0) {
923
33293
      return;  // error info is in ctx
924
    }
925
926
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
927
32064
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
928

64128
    args.GetReturnValue().Set(arr);
929
33289
  }
930
}
931
932
107771
static void LStat(const FunctionCallbackInfo<Value>& args) {
933
107771
  Environment* env = Environment::GetCurrent(args);
934
935
107771
  const int argc = args.Length();
936
107771
  CHECK_GE(argc, 3);
937
938
107771
  BufferValue path(env->isolate(), args[0]);
939
107771
  CHECK_NOT_NULL(*path);
940
941
215542
  bool use_bigint = args[1]->IsTrue();
942
215542
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
943
107771
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
944
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
945
1661
              uv_fs_lstat, *path);
946
  } else {  // lstat(path, use_bigint, undefined, ctx)
947
106110
    CHECK_EQ(argc, 4);
948
106110
    FSReqWrapSync req_wrap_sync;
949

106144
    FS_SYNC_TRACE_BEGIN(lstat);
950
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
951
212220
                       *path);
952

106144
    FS_SYNC_TRACE_END(lstat);
953
106110
    if (err != 0) {
954
107773
      return;  // error info is in ctx
955
    }
956
957
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
958
106108
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
959

212216
    args.GetReturnValue().Set(arr);
960
107769
  }
961
}
962
963
51042
static void FStat(const FunctionCallbackInfo<Value>& args) {
964
51042
  Environment* env = Environment::GetCurrent(args);
965
966
51042
  const int argc = args.Length();
967
51042
  CHECK_GE(argc, 2);
968
969
102084
  CHECK(args[0]->IsInt32());
970
153126
  int fd = args[0].As<Int32>()->Value();
971
972
102084
  bool use_bigint = args[1]->IsTrue();
973
102084
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
974
51042
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
975
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
976
2213
              uv_fs_fstat, fd);
977
  } else {  // fstat(fd, use_bigint, undefined, ctx)
978
48829
    CHECK_EQ(argc, 4);
979
48829
    FSReqWrapSync req_wrap_sync;
980

48839
    FS_SYNC_TRACE_BEGIN(fstat);
981
48829
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
982

48839
    FS_SYNC_TRACE_END(fstat);
983
48829
    if (err != 0) {
984
51059
      return;  // error info is in ctx
985
    }
986
987
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
988
48812
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
989
97624
    args.GetReturnValue().Set(arr);
990
  }
991
}
992
993
87
static void Symlink(const FunctionCallbackInfo<Value>& args) {
994
87
  Environment* env = Environment::GetCurrent(args);
995
87
  Isolate* isolate = env->isolate();
996
997
87
  int argc = args.Length();
998
87
  CHECK_GE(argc, 4);
999
1000
87
  BufferValue target(isolate, args[0]);
1001
87
  CHECK_NOT_NULL(*target);
1002
174
  BufferValue path(isolate, args[1]);
1003
87
  CHECK_NOT_NULL(*path);
1004
1005
174
  CHECK(args[2]->IsInt32());
1006
261
  int flags = args[2].As<Int32>()->Value();
1007
1008
87
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1009
87
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1010
14
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1011
28
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1012
  } else {  // symlink(target, path, flags, undefinec, ctx)
1013
73
    CHECK_EQ(argc, 5);
1014
73
    FSReqWrapSync req_wrap_sync;
1015

77
    FS_SYNC_TRACE_BEGIN(symlink);
1016
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1017
146
             uv_fs_symlink, *target, *path, flags);
1018

77
    FS_SYNC_TRACE_END(symlink);
1019
87
  }
1020
87
}
1021
1022
9
static void Link(const FunctionCallbackInfo<Value>& args) {
1023
9
  Environment* env = Environment::GetCurrent(args);
1024
9
  Isolate* isolate = env->isolate();
1025
1026
9
  int argc = args.Length();
1027
9
  CHECK_GE(argc, 3);
1028
1029
9
  BufferValue src(isolate, args[0]);
1030
9
  CHECK_NOT_NULL(*src);
1031
1032
18
  BufferValue dest(isolate, args[1]);
1033
9
  CHECK_NOT_NULL(*dest);
1034
1035
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1036
9
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1037
4
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1038
8
                  AfterNoArgs, uv_fs_link, *src, *dest);
1039
  } else {  // link(src, dest)
1040
5
    CHECK_EQ(argc, 4);
1041
5
    FSReqWrapSync req_wrap_sync;
1042

11
    FS_SYNC_TRACE_BEGIN(link);
1043
    SyncCall(env, args[3], &req_wrap_sync, "link",
1044
10
             uv_fs_link, *src, *dest);
1045

11
    FS_SYNC_TRACE_END(link);
1046
9
  }
1047
9
}
1048
1049
71
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1050
71
  Environment* env = Environment::GetCurrent(args);
1051
71
  Isolate* isolate = env->isolate();
1052
1053
71
  int argc = args.Length();
1054
71
  CHECK_GE(argc, 3);
1055
1056
71
  BufferValue path(isolate, args[0]);
1057
71
  CHECK_NOT_NULL(*path);
1058
1059
71
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1060
1061
71
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1062
71
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1063
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1064
33
              uv_fs_readlink, *path);
1065
  } else {
1066
38
    CHECK_EQ(argc, 4);
1067
38
    FSReqWrapSync req_wrap_sync;
1068

40
    FS_SYNC_TRACE_BEGIN(readlink);
1069
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1070
76
                       uv_fs_readlink, *path);
1071

40
    FS_SYNC_TRACE_END(readlink);
1072
38
    if (err < 0) {
1073
1
      return;  // syscall failed, no need to continue, error info is in ctx
1074
    }
1075
37
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1076
1077
    Local<Value> error;
1078
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1079
                                               link_path,
1080
                                               encoding,
1081
37
                                               &error);
1082
37
    if (rc.IsEmpty()) {
1083
      Local<Object> ctx = args[3].As<Object>();
1084
      ctx->Set(env->context(), env->error_string(), error).FromJust();
1085
      return;
1086
    }
1087
1088

74
    args.GetReturnValue().Set(rc.ToLocalChecked());
1089
70
  }
1090
}
1091
1092
8
static void Rename(const FunctionCallbackInfo<Value>& args) {
1093
8
  Environment* env = Environment::GetCurrent(args);
1094
8
  Isolate* isolate = env->isolate();
1095
1096
8
  int argc = args.Length();
1097
8
  CHECK_GE(argc, 3);
1098
1099
8
  BufferValue old_path(isolate, args[0]);
1100
8
  CHECK_NOT_NULL(*old_path);
1101
16
  BufferValue new_path(isolate, args[1]);
1102
8
  CHECK_NOT_NULL(*new_path);
1103
1104
8
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1105
8
  if (req_wrap_async != nullptr) {
1106
5
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1107
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1108
10
                  *old_path, *new_path);
1109
  } else {
1110
3
    CHECK_EQ(argc, 4);
1111
3
    FSReqWrapSync req_wrap_sync;
1112

5
    FS_SYNC_TRACE_BEGIN(rename);
1113
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1114
6
             *old_path, *new_path);
1115

5
    FS_SYNC_TRACE_END(rename);
1116
8
  }
1117
8
}
1118
1119
48
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1120
48
  Environment* env = Environment::GetCurrent(args);
1121
1122
48
  const int argc = args.Length();
1123
48
  CHECK_GE(argc, 3);
1124
1125
96
  CHECK(args[0]->IsInt32());
1126
144
  const int fd = args[0].As<Int32>()->Value();
1127
1128
96
  CHECK(args[1]->IsNumber());
1129
144
  const int64_t len = args[1].As<Integer>()->Value();
1130
1131
48
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1132
48
  if (req_wrap_async != nullptr) {
1133
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1134
34
              uv_fs_ftruncate, fd, len);
1135
  } else {
1136
14
    CHECK_EQ(argc, 4);
1137
14
    FSReqWrapSync req_wrap_sync;
1138

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1139
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1140
14
             len);
1141

16
    FS_SYNC_TRACE_END(ftruncate);
1142
  }
1143
48
}
1144
1145
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1146
7
  Environment* env = Environment::GetCurrent(args);
1147
1148
7
  const int argc = args.Length();
1149
7
  CHECK_GE(argc, 2);
1150
1151
14
  CHECK(args[0]->IsInt32());
1152
21
  const int fd = args[0].As<Int32>()->Value();
1153
1154
7
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1155
7
  if (req_wrap_async != nullptr) {
1156
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1157
4
              uv_fs_fdatasync, fd);
1158
  } else {
1159
3
    CHECK_EQ(argc, 3);
1160
3
    FSReqWrapSync req_wrap_sync;
1161

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

5
    FS_SYNC_TRACE_END(fdatasync);
1164
  }
1165
7
}
1166
1167
21
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1168
21
  Environment* env = Environment::GetCurrent(args);
1169
1170
21
  const int argc = args.Length();
1171
21
  CHECK_GE(argc, 2);
1172
1173
42
  CHECK(args[0]->IsInt32());
1174
63
  const int fd = args[0].As<Int32>()->Value();
1175
1176
21
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1177
21
  if (req_wrap_async != nullptr) {
1178
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1179
6
              uv_fs_fsync, fd);
1180
  } else {
1181
15
    CHECK_EQ(argc, 3);
1182
15
    FSReqWrapSync req_wrap_sync;
1183

17
    FS_SYNC_TRACE_BEGIN(fsync);
1184
15
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1185

17
    FS_SYNC_TRACE_END(fsync);
1186
  }
1187
21
}
1188
1189
504
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1190
504
  Environment* env = Environment::GetCurrent(args);
1191
1192
504
  const int argc = args.Length();
1193
504
  CHECK_GE(argc, 2);
1194
1195
504
  BufferValue path(env->isolate(), args[0]);
1196
504
  CHECK_NOT_NULL(*path);
1197
1198
504
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1199
504
  if (req_wrap_async != nullptr) {
1200
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1201
7
              uv_fs_unlink, *path);
1202
  } else {
1203
497
    CHECK_EQ(argc, 3);
1204
497
    FSReqWrapSync req_wrap_sync;
1205

557
    FS_SYNC_TRACE_BEGIN(unlink);
1206
994
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1207

557
    FS_SYNC_TRACE_END(unlink);
1208
504
  }
1209
504
}
1210
1211
707
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1212
707
  Environment* env = Environment::GetCurrent(args);
1213
1214
707
  const int argc = args.Length();
1215
707
  CHECK_GE(argc, 2);
1216
1217
707
  BufferValue path(env->isolate(), args[0]);
1218
707
  CHECK_NOT_NULL(*path);
1219
1220
707
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1221
707
  if (req_wrap_async != nullptr) {
1222
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1223
4
              uv_fs_rmdir, *path);
1224
  } else {  // rmdir(path, undefined, ctx)
1225
703
    CHECK_EQ(argc, 3);
1226
703
    FSReqWrapSync req_wrap_sync;
1227

709
    FS_SYNC_TRACE_BEGIN(rmdir);
1228
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1229
1406
             uv_fs_rmdir, *path);
1230

709
    FS_SYNC_TRACE_END(rmdir);
1231
707
  }
1232
707
}
1233
1234
4667
int MKDirpSync(uv_loop_t* loop, uv_fs_t* req, const std::string& path, int mode,
1235
               uv_fs_cb cb = nullptr) {
1236
4667
  FSContinuationData continuation_data(req, mode, cb);
1237
4667
  continuation_data.PushPath(std::move(path));
1238
1239
4667
  while (continuation_data.paths.size() > 0) {
1240
4681
    std::string next_path = continuation_data.PopPath();
1241
4681
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1242
    while (true) {
1243

4682
      switch (err) {
1244
        case 0:
1245
18
          if (continuation_data.paths.size() == 0) {
1246
12
            return 0;
1247
          }
1248
6
          break;
1249
        case UV_ENOENT: {
1250
          std::string dirname = next_path.substr(0,
1251
8
                                        next_path.find_last_of(kPathSeparator));
1252
8
          if (dirname != next_path) {
1253
7
            continuation_data.PushPath(std::move(next_path));
1254
7
            continuation_data.PushPath(std::move(dirname));
1255
1
          } else if (continuation_data.paths.size() == 0) {
1256
1
            err = UV_EEXIST;
1257
1
            continue;
1258
          }
1259
7
          break;
1260
        }
1261
        case UV_EPERM: {
1262
          return err;
1263
        }
1264
        default:
1265
4656
          uv_fs_req_cleanup(req);
1266
4656
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1267

4656
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) return UV_EEXIST;
1268
4655
          if (err < 0) return err;
1269
4654
          break;
1270
      }
1271
4667
      break;
1272
    }
1273
4667
    uv_fs_req_cleanup(req);
1274
4667
  }
1275
1276
4653
  return 0;
1277
}
1278
1279
20
int MKDirpAsync(uv_loop_t* loop,
1280
                uv_fs_t* req,
1281
                const char* path,
1282
                int mode,
1283
                uv_fs_cb cb) {
1284
20
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1285
  // on the first iteration of algorithm, stash state information.
1286
20
  if (req_wrap->continuation_data == nullptr) {
1287
24
    req_wrap->continuation_data = std::unique_ptr<FSContinuationData>{
1288
16
      new FSContinuationData(req, mode, cb)};
1289
8
    req_wrap->continuation_data->PushPath(std::move(path));
1290
  }
1291
1292
  // on each iteration of algorithm, mkdir directory on top of stack.
1293
20
  std::string next_path = req_wrap->continuation_data->PopPath();
1294
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1295
60
                        uv_fs_callback_t{[](uv_fs_t* req) {
1296
20
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1297
20
    Environment* env = req_wrap->env();
1298
20
    uv_loop_t* loop = env->event_loop();
1299
20
    std::string path = req->path;
1300
20
    int err = req->result;
1301
1302
    while (true) {
1303

21
      switch (err) {
1304
        case 0: {
1305
11
          if (req_wrap->continuation_data->paths.size() == 0) {
1306
5
            req_wrap->continuation_data->Done(0);
1307
          } else {
1308
6
            uv_fs_req_cleanup(req);
1309
            MKDirpAsync(loop, req, path.c_str(),
1310
6
                        req_wrap->continuation_data->mode, nullptr);
1311
          }
1312
11
          break;
1313
        }
1314
        case UV_ENOENT: {
1315
          std::string dirname = path.substr(0,
1316
7
                                            path.find_last_of(kPathSeparator));
1317
7
          if (dirname != path) {
1318
6
            req_wrap->continuation_data->PushPath(std::move(path));
1319
6
            req_wrap->continuation_data->PushPath(std::move(dirname));
1320
1
          } else if (req_wrap->continuation_data->paths.size() == 0) {
1321
1
            err = UV_EEXIST;
1322
1
            continue;
1323
          }
1324
6
          uv_fs_req_cleanup(req);
1325
          MKDirpAsync(loop, req, path.c_str(),
1326
6
                      req_wrap->continuation_data->mode, nullptr);
1327
6
          break;
1328
        }
1329
        case UV_EPERM: {
1330
          req_wrap->continuation_data->Done(err);
1331
          break;
1332
        }
1333
        default:
1334

6
          if (err == UV_EEXIST &&
1335
3
              req_wrap->continuation_data->paths.size() > 0) {
1336
            uv_fs_req_cleanup(req);
1337
            MKDirpAsync(loop, req, path.c_str(),
1338
                        req_wrap->continuation_data->mode, nullptr);
1339
          } else {
1340
            // verify that the path pointed to is actually a directory.
1341
3
            uv_fs_req_cleanup(req);
1342
            int err = uv_fs_stat(loop, req, path.c_str(),
1343
9
                                 uv_fs_callback_t{[](uv_fs_t* req) {
1344
3
              FSReqBase* req_wrap = FSReqBase::from_req(req);
1345
3
              int err = req->result;
1346

3
              if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1347
3
              req_wrap->continuation_data->Done(err);
1348
12
            }});
1349
3
            if (err < 0) req_wrap->continuation_data->Done(err);
1350
          }
1351
3
          break;
1352
      }
1353
20
      break;
1354
    }
1355
80
  }});
1356
1357
20
  return err;
1358
}
1359
1360
5560
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1361
5560
  Environment* env = Environment::GetCurrent(args);
1362
1363
5560
  const int argc = args.Length();
1364
5560
  CHECK_GE(argc, 4);
1365
1366
5560
  BufferValue path(env->isolate(), args[0]);
1367
5560
  CHECK_NOT_NULL(*path);
1368
1369
11120
  CHECK(args[1]->IsInt32());
1370
16680
  const int mode = args[1].As<Int32>()->Value();
1371
1372
11120
  CHECK(args[2]->IsBoolean());
1373
11120
  bool mkdirp = args[2]->IsTrue();
1374
1375
5560
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1376
5560
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1377
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1378
323
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1379
  } else {  // mkdir(path, mode, undefined, ctx)
1380
5237
    CHECK_EQ(argc, 5);
1381
5237
    FSReqWrapSync req_wrap_sync;
1382

5315
    FS_SYNC_TRACE_BEGIN(mkdir);
1383
5237
    if (mkdirp) {
1384
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1385
9334
               MKDirpSync, *path, mode);
1386
    } else {
1387
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1388
1140
               uv_fs_mkdir, *path, mode);
1389
    }
1390

5315
    FS_SYNC_TRACE_END(mkdir);
1391
5560
  }
1392
5560
}
1393
1394
36
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1395
36
  Environment* env = Environment::GetCurrent(args);
1396
36
  Isolate* isolate = env->isolate();
1397
1398
36
  const int argc = args.Length();
1399
36
  CHECK_GE(argc, 3);
1400
1401
36
  BufferValue path(isolate, args[0]);
1402
36
  CHECK_NOT_NULL(*path);
1403
1404
36
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1405
1406
36
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1407
36
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1408
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1409
18
              uv_fs_realpath, *path);
1410
  } else {  // realpath(path, encoding, undefined, ctx)
1411
18
    CHECK_EQ(argc, 4);
1412
18
    FSReqWrapSync req_wrap_sync;
1413

20
    FS_SYNC_TRACE_BEGIN(realpath);
1414
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1415
36
                       uv_fs_realpath, *path);
1416

20
    FS_SYNC_TRACE_END(realpath);
1417
18
    if (err < 0) {
1418
2
      return;  // syscall failed, no need to continue, error info is in ctx
1419
    }
1420
1421
16
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1422
1423
    Local<Value> error;
1424
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1425
                                               link_path,
1426
                                               encoding,
1427
16
                                               &error);
1428
16
    if (rc.IsEmpty()) {
1429
      Local<Object> ctx = args[3].As<Object>();
1430
      ctx->Set(env->context(), env->error_string(), error).FromJust();
1431
      return;
1432
    }
1433
1434

32
    args.GetReturnValue().Set(rc.ToLocalChecked());
1435
34
  }
1436
}
1437
1438
14358
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1439
14358
  Environment* env = Environment::GetCurrent(args);
1440
14358
  Isolate* isolate = env->isolate();
1441
1442
14358
  const int argc = args.Length();
1443
14358
  CHECK_GE(argc, 3);
1444
1445
14358
  BufferValue path(isolate, args[0]);
1446
14358
  CHECK_NOT_NULL(*path);
1447
1448
14358
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1449
1450
28716
  bool with_types = args[2]->IsTrue();
1451
1452
14358
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1453
14358
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1454
32
    if (with_types) {
1455
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1456
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1457
    } else {
1458
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1459
25
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1460
    }
1461
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1462
14326
    CHECK_EQ(argc, 5);
1463
14326
    FSReqWrapSync req_wrap_sync;
1464

14328
    FS_SYNC_TRACE_BEGIN(readdir);
1465
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1466
28652
                       uv_fs_scandir, *path, 0 /*flags*/);
1467

14328
    FS_SYNC_TRACE_END(readdir);
1468
14326
    if (err < 0) {
1469
39
      return;  // syscall failed, no need to continue, error info is in ctx
1470
    }
1471
1472
14287
    CHECK_GE(req_wrap_sync.req.result, 0);
1473
    int r;
1474
28574
    std::vector<Local<Value>> name_v;
1475
28574
    std::vector<Local<Value>> type_v;
1476
1477
652792
    for (int i = 0; ; i++) {
1478
      uv_dirent_t ent;
1479
1480
652792
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1481
652792
      if (r == UV_EOF)
1482
14287
        break;
1483
638505
      if (r != 0) {
1484
        Local<Object> ctx = args[4].As<Object>();
1485
        ctx->Set(env->context(), env->errno_string(),
1486
                 Integer::New(isolate, r)).FromJust();
1487
        ctx->Set(env->context(), env->syscall_string(),
1488
                 OneByteString(isolate, "readdir")).FromJust();
1489
        return;
1490
      }
1491
1492
      Local<Value> error;
1493
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1494
                                                       ent.name,
1495
                                                       encoding,
1496
638505
                                                       &error);
1497
1498
638505
      if (filename.IsEmpty()) {
1499
        Local<Object> ctx = args[4].As<Object>();
1500
        ctx->Set(env->context(), env->error_string(), error).FromJust();
1501
        return;
1502
      }
1503
1504
638505
      name_v.push_back(filename.ToLocalChecked());
1505
1506
638505
      if (with_types) {
1507
20
        type_v.push_back(Integer::New(isolate, ent.type));
1508
      }
1509
638505
    }
1510
1511
1512
14287
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1513
14287
    if (with_types) {
1514
2
      Local<Array> result = Array::New(isolate, 2);
1515
6
      result->Set(env->context(), 0, names).FromJust();
1516
2
      result->Set(env->context(),
1517
                  1,
1518
                  Array::New(isolate, type_v.data(),
1519
8
                             type_v.size())).FromJust();
1520
4
      args.GetReturnValue().Set(result);
1521
    } else {
1522
28570
      args.GetReturnValue().Set(names);
1523
14287
    }
1524
14319
  }
1525
}
1526
1527
62676
static void Open(const FunctionCallbackInfo<Value>& args) {
1528
62676
  Environment* env = Environment::GetCurrent(args);
1529
1530
62676
  const int argc = args.Length();
1531
62676
  CHECK_GE(argc, 3);
1532
1533
62676
  BufferValue path(env->isolate(), args[0]);
1534
62676
  CHECK_NOT_NULL(*path);
1535
1536
125352
  CHECK(args[1]->IsInt32());
1537
188028
  const int flags = args[1].As<Int32>()->Value();
1538
1539
125352
  CHECK(args[2]->IsInt32());
1540
188028
  const int mode = args[2].As<Int32>()->Value();
1541
1542
62676
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1543
62676
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1544
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1545
5501
              uv_fs_open, *path, flags, mode);
1546
  } else {  // open(path, flags, mode, undefined, ctx)
1547
57175
    CHECK_EQ(argc, 5);
1548
57175
    FSReqWrapSync req_wrap_sync;
1549

57321
    FS_SYNC_TRACE_BEGIN(open);
1550
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1551
114350
                          uv_fs_open, *path, flags, mode);
1552

57321
    FS_SYNC_TRACE_END(open);
1553
114350
    args.GetReturnValue().Set(result);
1554
62676
  }
1555
62676
}
1556
1557
63
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1558
63
  Environment* env = Environment::GetCurrent(args);
1559
63
  Isolate* isolate = env->isolate();
1560
1561
63
  const int argc = args.Length();
1562
63
  CHECK_GE(argc, 3);
1563
1564
63
  BufferValue path(isolate, args[0]);
1565
63
  CHECK_NOT_NULL(*path);
1566
1567
126
  CHECK(args[1]->IsInt32());
1568
189
  const int flags = args[1].As<Int32>()->Value();
1569
1570
126
  CHECK(args[2]->IsInt32());
1571
189
  const int mode = args[2].As<Int32>()->Value();
1572
1573
63
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1574
63
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1575
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1576
62
              uv_fs_open, *path, flags, mode);
1577
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1578
1
    CHECK_EQ(argc, 5);
1579
1
    FSReqWrapSync req_wrap_sync;
1580

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

1
    FS_SYNC_TRACE_END(open);
1584
1
    if (result < 0) {
1585
      return;  // syscall failed, no need to continue, error info is in ctx
1586
    }
1587
1
    FileHandle* fd = FileHandle::New(env, result);
1588
1
    if (fd == nullptr) return;
1589

3
    args.GetReturnValue().Set(fd->object());
1590
63
  }
1591
}
1592
1593
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1594
33
  Environment* env = Environment::GetCurrent(args);
1595
33
  Isolate* isolate = env->isolate();
1596
1597
33
  const int argc = args.Length();
1598
33
  CHECK_GE(argc, 3);
1599
1600
33
  BufferValue src(isolate, args[0]);
1601
33
  CHECK_NOT_NULL(*src);
1602
1603
66
  BufferValue dest(isolate, args[1]);
1604
33
  CHECK_NOT_NULL(*dest);
1605
1606
66
  CHECK(args[2]->IsInt32());
1607
99
  const int flags = args[2].As<Int32>()->Value();
1608
1609
33
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1610
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1611
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1612
13
                  *dest, dest.length(), UTF8, AfterNoArgs,
1613
26
                  uv_fs_copyfile, *src, *dest, flags);
1614
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1615
20
    CHECK_EQ(argc, 5);
1616
20
    FSReqWrapSync req_wrap_sync;
1617

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1618
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1619
40
             uv_fs_copyfile, *src, *dest, flags);
1620

22
    FS_SYNC_TRACE_END(copyfile);
1621
33
  }
1622
33
}
1623
1624
1625
// Wrapper for write(2).
1626
//
1627
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1628
// 0 fd        integer. file descriptor
1629
// 1 buffer    the data to write
1630
// 2 offset    where in the buffer to start from
1631
// 3 length    how much to write
1632
// 4 position  if integer, position to write at in the file.
1633
//             if null, write from the current position
1634
145531
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1635
145531
  Environment* env = Environment::GetCurrent(args);
1636
1637
145531
  const int argc = args.Length();
1638
145531
  CHECK_GE(argc, 4);
1639
1640
291062
  CHECK(args[0]->IsInt32());
1641
436593
  const int fd = args[0].As<Int32>()->Value();
1642
1643
145531
  CHECK(Buffer::HasInstance(args[1]));
1644
291062
  Local<Object> buffer_obj = args[1].As<Object>();
1645
145531
  char* buffer_data = Buffer::Data(buffer_obj);
1646
145531
  size_t buffer_length = Buffer::Length(buffer_obj);
1647
1648
291062
  CHECK(args[2]->IsInt32());
1649
436593
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1650
145531
  CHECK_LE(off, buffer_length);
1651
1652
291062
  CHECK(args[3]->IsInt32());
1653
436593
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1654
145531
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1655
145531
  CHECK_LE(len, buffer_length);
1656
145531
  CHECK_GE(off + len, off);
1657
1658

308924
  const int64_t pos = GET_OFFSET(args[4]);
1659
1660
145531
  char* buf = buffer_data + off;
1661
145531
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1662
1663
145531
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1664
145531
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1665
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1666
12155
              uv_fs_write, fd, &uvbuf, 1, pos);
1667
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1668
133376
    CHECK_EQ(argc, 7);
1669
133376
    FSReqWrapSync req_wrap_sync;
1670

133500
    FS_SYNC_TRACE_BEGIN(write);
1671
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1672
133376
                                uv_fs_write, fd, &uvbuf, 1, pos);
1673

133500
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1674
400128
    args.GetReturnValue().Set(bytesWritten);
1675
  }
1676
145531
}
1677
1678
1679
// Wrapper for writev(2).
1680
//
1681
// bytesWritten = writev(fd, chunks, position, callback)
1682
// 0 fd        integer. file descriptor
1683
// 1 chunks    array of buffers to write
1684
// 2 position  if integer, position to write at in the file.
1685
//             if null, write from the current position
1686
12
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1687
12
  Environment* env = Environment::GetCurrent(args);
1688
1689
12
  const int argc = args.Length();
1690
12
  CHECK_GE(argc, 3);
1691
1692
24
  CHECK(args[0]->IsInt32());
1693
36
  const int fd = args[0].As<Int32>()->Value();
1694
1695
24
  CHECK(args[1]->IsArray());
1696
24
  Local<Array> chunks = args[1].As<Array>();
1697
1698

24
  int64_t pos = GET_OFFSET(args[2]);
1699
1700
12
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1701
1702
50414
  for (uint32_t i = 0; i < iovs.length(); i++) {
1703
151206
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1704
50402
    CHECK(Buffer::HasInstance(chunk));
1705
50402
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1706
  }
1707
1708
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1709
12
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1710
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1711
12
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1712
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1713
    CHECK_EQ(argc, 5);
1714
    FSReqWrapSync req_wrap_sync;
1715
    FS_SYNC_TRACE_BEGIN(write);
1716
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1717
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1718
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1719
    args.GetReturnValue().Set(bytesWritten);
1720
12
  }
1721
12
}
1722
1723
1724
// Wrapper for write(2).
1725
//
1726
// bytesWritten = write(fd, string, position, enc, callback)
1727
// 0 fd        integer. file descriptor
1728
// 1 string    non-buffer values are converted to strings
1729
// 2 position  if integer, position to write at in the file.
1730
//             if null, write from the current position
1731
// 3 enc       encoding of string
1732
1256
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1733
1256
  Environment* env = Environment::GetCurrent(args);
1734
1256
  Isolate* isolate = env->isolate();
1735
1736
1256
  const int argc = args.Length();
1737
1256
  CHECK_GE(argc, 4);
1738
1739
2512
  CHECK(args[0]->IsInt32());
1740
3768
  const int fd = args[0].As<Int32>()->Value();
1741
1742

2626
  const int64_t pos = GET_OFFSET(args[2]);
1743
1744
1256
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1745
1746
1256
  Local<Value> value = args[1];
1747
1256
  char* buf = nullptr;
1748
  size_t len;
1749
1750
1256
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1751
1256
  const bool is_async = req_wrap_async != nullptr;
1752
1753
  // Avoid copying the string when it is externalized but only when:
1754
  // 1. The target encoding is compatible with the string's encoding, and
1755
  // 2. The write is synchronous, otherwise the string might get neutered
1756
  //    while the request is in flight, and
1757
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1758
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1759
  // The const_casts are conceptually sound: memory is read but not written.
1760

3692
  if (!is_async && value->IsString()) {
1761
1218
    auto string = value.As<String>();
1762


1219
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1763
1
      auto ext = string->GetExternalOneByteStringResource();
1764
1
      buf = const_cast<char*>(ext->data());
1765
1
      len = ext->length();
1766


1218
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1767
2
      auto ext = string->GetExternalStringResource();
1768
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1769
1
      len = ext->length() * sizeof(*ext->data());
1770
    }
1771
  }
1772
1773
1256
  if (is_async) {  // write(fd, string, pos, enc, req)
1774
38
    CHECK_NOT_NULL(req_wrap_async);
1775
76
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1776
    FSReqBase::FSReqBuffer& stack_buffer =
1777
38
        req_wrap_async->Init("write", len, enc);
1778
    // StorageSize may return too large a char, so correct the actual length
1779
    // by the write size
1780
38
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1781
38
    stack_buffer.SetLengthAndZeroTerminate(len);
1782
38
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1783
    int err = req_wrap_async->Dispatch(uv_fs_write,
1784
                                       fd,
1785
                                       &uvbuf,
1786
                                       1,
1787
                                       pos,
1788
38
                                       AfterInteger);
1789
38
    if (err < 0) {
1790
      uv_fs_t* uv_req = req_wrap_async->req();
1791
      uv_req->result = err;
1792
      uv_req->path = nullptr;
1793
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1794
                             // an error
1795
    } else {
1796
38
      req_wrap_async->SetReturnValue(args);
1797
    }
1798
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1799
1218
    CHECK_EQ(argc, 6);
1800
1218
    FSReqWrapSync req_wrap_sync;
1801
2436
    FSReqBase::FSReqBuffer stack_buffer;
1802
1218
    if (buf == nullptr) {
1803
2432
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1804
        return;
1805
1216
      stack_buffer.AllocateSufficientStorage(len + 1);
1806
      // StorageSize may return too large a char, so correct the actual length
1807
      // by the write size
1808
      len = StringBytes::Write(isolate, *stack_buffer,
1809
1216
                               len, args[1], enc);
1810
1216
      stack_buffer.SetLengthAndZeroTerminate(len);
1811
1216
      buf = *stack_buffer;
1812
    }
1813
1218
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1814

1218
    FS_SYNC_TRACE_BEGIN(write);
1815
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1816
1218
                                uv_fs_write, fd, &uvbuf, 1, pos);
1817

1218
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1818
4872
    args.GetReturnValue().Set(bytesWritten);
1819
  }
1820
}
1821
1822
1823
/*
1824
 * Wrapper for read(2).
1825
 *
1826
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1827
 *
1828
 * 0 fd        int32. file descriptor
1829
 * 1 buffer    instance of Buffer
1830
 * 2 offset    int32. offset to start reading into inside buffer
1831
 * 3 length    int32. length to read
1832
 * 4 position  int64. file position - -1 for current position
1833
 */
1834
194376
static void Read(const FunctionCallbackInfo<Value>& args) {
1835
194376
  Environment* env = Environment::GetCurrent(args);
1836
1837
194376
  const int argc = args.Length();
1838
194376
  CHECK_GE(argc, 5);
1839
1840
388752
  CHECK(args[0]->IsInt32());
1841
583128
  const int fd = args[0].As<Int32>()->Value();
1842
1843
194376
  CHECK(Buffer::HasInstance(args[1]));
1844
388752
  Local<Object> buffer_obj = args[1].As<Object>();
1845
194376
  char* buffer_data = Buffer::Data(buffer_obj);
1846
194376
  size_t buffer_length = Buffer::Length(buffer_obj);
1847
1848
388752
  CHECK(args[2]->IsInt32());
1849
583128
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1850
194376
  CHECK_LT(off, buffer_length);
1851
1852
388752
  CHECK(args[3]->IsInt32());
1853
583128
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1854
194376
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1855
1856
388752
  CHECK(args[4]->IsNumber());
1857
583128
  const int64_t pos = args[4].As<Integer>()->Value();
1858
1859
194376
  char* buf = buffer_data + off;
1860
194376
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1861
1862
194376
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1863
194376
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1864
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1865
142122
              uv_fs_read, fd, &uvbuf, 1, pos);
1866
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1867
52254
    CHECK_EQ(argc, 7);
1868
52254
    FSReqWrapSync req_wrap_sync;
1869

52264
    FS_SYNC_TRACE_BEGIN(read);
1870
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1871
52254
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1872

52264
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1873
156762
    args.GetReturnValue().Set(bytesRead);
1874
  }
1875
194376
}
1876
1877
1878
/* fs.chmod(path, mode);
1879
 * Wrapper for chmod(1) / EIO_CHMOD
1880
 */
1881
21
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1882
21
  Environment* env = Environment::GetCurrent(args);
1883
1884
21
  const int argc = args.Length();
1885
21
  CHECK_GE(argc, 2);
1886
1887
21
  BufferValue path(env->isolate(), args[0]);
1888
21
  CHECK_NOT_NULL(*path);
1889
1890
42
  CHECK(args[1]->IsInt32());
1891
63
  int mode = args[1].As<Int32>()->Value();
1892
1893
21
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1894
21
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1895
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1896
11
              uv_fs_chmod, *path, mode);
1897
  } else {  // chmod(path, mode, undefined, ctx)
1898
10
    CHECK_EQ(argc, 4);
1899
10
    FSReqWrapSync req_wrap_sync;
1900

12
    FS_SYNC_TRACE_BEGIN(chmod);
1901
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1902
20
             uv_fs_chmod, *path, mode);
1903

12
    FS_SYNC_TRACE_END(chmod);
1904
21
  }
1905
21
}
1906
1907
1908
/* fs.fchmod(fd, mode);
1909
 * Wrapper for fchmod(1) / EIO_FCHMOD
1910
 */
1911
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1912
12
  Environment* env = Environment::GetCurrent(args);
1913
1914
12
  const int argc = args.Length();
1915
12
  CHECK_GE(argc, 2);
1916
1917
24
  CHECK(args[0]->IsInt32());
1918
36
  const int fd = args[0].As<Int32>()->Value();
1919
1920
24
  CHECK(args[1]->IsInt32());
1921
36
  const int mode = args[1].As<Int32>()->Value();
1922
1923
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1924
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1925
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1926
7
              uv_fs_fchmod, fd, mode);
1927
  } else {  // fchmod(fd, mode, undefined, ctx)
1928
5
    CHECK_EQ(argc, 4);
1929
5
    FSReqWrapSync req_wrap_sync;
1930

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1931
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1932
5
             uv_fs_fchmod, fd, mode);
1933

7
    FS_SYNC_TRACE_END(fchmod);
1934
  }
1935
12
}
1936
1937
1938
/* fs.chown(path, uid, gid);
1939
 * Wrapper for chown(1) / EIO_CHOWN
1940
 */
1941
5
static void Chown(const FunctionCallbackInfo<Value>& args) {
1942
5
  Environment* env = Environment::GetCurrent(args);
1943
1944
5
  const int argc = args.Length();
1945
5
  CHECK_GE(argc, 3);
1946
1947
5
  BufferValue path(env->isolate(), args[0]);
1948
5
  CHECK_NOT_NULL(*path);
1949
1950
10
  CHECK(args[1]->IsUint32());
1951
15
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1952
1953
10
  CHECK(args[2]->IsUint32());
1954
15
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1955
1956
5
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1957
5
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1958
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1959
3
              uv_fs_chown, *path, uid, gid);
1960
  } else {  // chown(path, uid, gid, undefined, ctx)
1961
2
    CHECK_EQ(argc, 5);
1962
2
    FSReqWrapSync req_wrap_sync;
1963

4
    FS_SYNC_TRACE_BEGIN(chown);
1964
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1965
4
             uv_fs_chown, *path, uid, gid);
1966

4
    FS_SYNC_TRACE_END(chown);
1967
5
  }
1968
5
}
1969
1970
1971
/* fs.fchown(fd, uid, gid);
1972
 * Wrapper for fchown(1) / EIO_FCHOWN
1973
 */
1974
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
1975
4
  Environment* env = Environment::GetCurrent(args);
1976
1977
4
  const int argc = args.Length();
1978
4
  CHECK_GE(argc, 3);
1979
1980
8
  CHECK(args[0]->IsInt32());
1981
12
  const int fd = args[0].As<Int32>()->Value();
1982
1983
8
  CHECK(args[1]->IsUint32());
1984
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1985
1986
8
  CHECK(args[2]->IsUint32());
1987
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1988
1989
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1990
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
1991
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
1992
2
              uv_fs_fchown, fd, uid, gid);
1993
  } else {  // fchown(fd, uid, gid, undefined, ctx)
1994
2
    CHECK_EQ(argc, 5);
1995
2
    FSReqWrapSync req_wrap_sync;
1996

4
    FS_SYNC_TRACE_BEGIN(fchown);
1997
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
1998
2
             uv_fs_fchown, fd, uid, gid);
1999

4
    FS_SYNC_TRACE_END(fchown);
2000
  }
2001
4
}
2002
2003
2004
10
static void LChown(const FunctionCallbackInfo<Value>& args) {
2005
10
  Environment* env = Environment::GetCurrent(args);
2006
2007
10
  const int argc = args.Length();
2008
10
  CHECK_GE(argc, 3);
2009
2010
10
  BufferValue path(env->isolate(), args[0]);
2011
10
  CHECK_NOT_NULL(*path);
2012
2013
20
  CHECK(args[1]->IsUint32());
2014
30
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2015
2016
20
  CHECK(args[2]->IsUint32());
2017
30
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2018
2019
10
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2020
10
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2021
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2022
8
              uv_fs_lchown, *path, uid, gid);
2023
  } else {  // lchown(path, uid, gid, undefined, ctx)
2024
2
    CHECK_EQ(argc, 5);
2025
2
    FSReqWrapSync req_wrap_sync;
2026

4
    FS_SYNC_TRACE_BEGIN(lchown);
2027
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2028
4
             uv_fs_lchown, *path, uid, gid);
2029

4
    FS_SYNC_TRACE_END(lchown);
2030
10
  }
2031
10
}
2032
2033
2034
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2035
29
  Environment* env = Environment::GetCurrent(args);
2036
2037
29
  const int argc = args.Length();
2038
29
  CHECK_GE(argc, 3);
2039
2040
29
  BufferValue path(env->isolate(), args[0]);
2041
29
  CHECK_NOT_NULL(*path);
2042
2043
58
  CHECK(args[1]->IsNumber());
2044
87
  const double atime = args[1].As<Number>()->Value();
2045
2046
58
  CHECK(args[2]->IsNumber());
2047
87
  const double mtime = args[2].As<Number>()->Value();
2048
2049
29
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2050
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2051
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2052
14
              uv_fs_utime, *path, atime, mtime);
2053
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2054
15
    CHECK_EQ(argc, 5);
2055
15
    FSReqWrapSync req_wrap_sync;
2056

17
    FS_SYNC_TRACE_BEGIN(utimes);
2057
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2058
30
             uv_fs_utime, *path, atime, mtime);
2059

17
    FS_SYNC_TRACE_END(utimes);
2060
29
  }
2061
29
}
2062
2063
726
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2064
726
  Environment* env = Environment::GetCurrent(args);
2065
2066
726
  const int argc = args.Length();
2067
726
  CHECK_GE(argc, 3);
2068
2069
1452
  CHECK(args[0]->IsInt32());
2070
2178
  const int fd = args[0].As<Int32>()->Value();
2071
2072
1452
  CHECK(args[1]->IsNumber());
2073
2178
  const double atime = args[1].As<Number>()->Value();
2074
2075
1452
  CHECK(args[2]->IsNumber());
2076
2178
  const double mtime = args[2].As<Number>()->Value();
2077
2078
726
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2079
726
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2080
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2081
718
              uv_fs_futime, fd, atime, mtime);
2082
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2083
8
    CHECK_EQ(argc, 5);
2084
8
    FSReqWrapSync req_wrap_sync;
2085

10
    FS_SYNC_TRACE_BEGIN(futimes);
2086
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2087
8
             uv_fs_futime, fd, atime, mtime);
2088

10
    FS_SYNC_TRACE_END(futimes);
2089
  }
2090
726
}
2091
2092
12
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2093
12
  Environment* env = Environment::GetCurrent(args);
2094
12
  Isolate* isolate = env->isolate();
2095
2096
12
  const int argc = args.Length();
2097
12
  CHECK_GE(argc, 2);
2098
2099
12
  BufferValue tmpl(isolate, args[0]);
2100
12
  CHECK_NOT_NULL(*tmpl);
2101
2102
12
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2103
2104
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2105
12
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2106
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2107
5
              uv_fs_mkdtemp, *tmpl);
2108
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2109
7
    CHECK_EQ(argc, 4);
2110
7
    FSReqWrapSync req_wrap_sync;
2111

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2112
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2113
14
             uv_fs_mkdtemp, *tmpl);
2114

9
    FS_SYNC_TRACE_END(mkdtemp);
2115
7
    const char* path = static_cast<const char*>(req_wrap_sync.req.path);
2116
2117
    Local<Value> error;
2118
    MaybeLocal<Value> rc =
2119
7
        StringBytes::Encode(isolate, path, encoding, &error);
2120
7
    if (rc.IsEmpty()) {
2121
      Local<Object> ctx = args[3].As<Object>();
2122
      ctx->Set(env->context(), env->error_string(), error).FromJust();
2123
12
      return;
2124
    }
2125

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