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: 1202 1281 93.8 %
Date: 2019-10-08 22:34:21 Branches: 727 1104 65.9 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_file.h"
23
#include "aliased_buffer.h"
24
#include "memory_tracker-inl.h"
25
#include "node_buffer.h"
26
#include "node_process.h"
27
#include "node_stat_watcher.h"
28
#include "util-inl.h"
29
30
#include "tracing/trace_event.h"
31
32
#include "req_wrap-inl.h"
33
#include "stream_base-inl.h"
34
#include "string_bytes.h"
35
#include "string_search.h"
36
37
#include <fcntl.h>
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
#include <cstring>
41
#include <cerrno>
42
#include <climits>
43
44
#if defined(__MINGW32__) || defined(_MSC_VER)
45
# include <io.h>
46
#endif
47
48
#include <memory>
49
50
namespace node {
51
52
namespace fs {
53
54
using v8::Array;
55
using v8::Context;
56
using v8::DontDelete;
57
using v8::EscapableHandleScope;
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::PropertyAttribute;
72
using v8::ReadOnly;
73
using v8::String;
74
using v8::Symbol;
75
using v8::Uint32;
76
using v8::Undefined;
77
using v8::Value;
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
158409
inline int64_t GetOffset(Local<Value> value) {
90

172731
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
91
}
92
93
#define TRACE_NAME(name) "fs.sync." #name
94
#define GET_TRACE_ENABLED                                                  \
95
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
96
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
97
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
98
  if (GET_TRACE_ENABLED)                                                   \
99
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
100
  ##__VA_ARGS__);
101
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
102
  if (GET_TRACE_ENABLED)                                                   \
103
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
104
  ##__VA_ARGS__);
105
106
// We sometimes need to convert a C++ lambda function to a raw C-style function.
107
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
108
// functions, and thus does not wrap them properly.
109
typedef void(*uv_fs_callback_t)(uv_fs_t*);
110
111
// The FileHandle object wraps a file descriptor and will close it on garbage
112
// collection if necessary. If that happens, a process warning will be
113
// emitted (or a fatal exception will occur if the fd cannot be closed.)
114
270
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
115
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
116
      StreamBase(env),
117
270
      fd_(fd) {
118
270
  MakeWeak();
119
270
  StreamBase::AttachToObject(GetObject());
120
270
}
121
122
270
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
123

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

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

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

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

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

220
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
394
        result = handle->read_length_;
395
396
      // If we read data and we have an expected length, decrease it by
397
      // how much we have read.
398
220
      if (handle->read_length_ >= 0)
399
16
        handle->read_length_ -= result;
400
401
      // If we have an offset, increase it by how much we have read.
402
220
      if (handle->read_offset_ >= 0)
403
218
        handle->read_offset_ += result;
404
    }
405
406
    // Reading 0 bytes from a file always means EOF, or that we reached
407
    // the end of the requested range.
408
221
    if (result == 0)
409
6
      result = UV_EOF;
410
411
221
    handle->EmitRead(result, buffer);
412
413
    // Start over, if EmitRead() didn’t tell us to stop.
414
221
    if (handle->reading_)
415
      handle->ReadStart();
416
1326
  }});
417
418
221
  return 0;
419
}
420
421
242
int FileHandle::ReadStop() {
422
242
  reading_ = false;
423
242
  return 0;
424
}
425
426
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
427
428
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
429
  return new FileHandleCloseWrap(this, object);
430
}
431
432
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
433
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
434
  closing_ = true;
435
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
436
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
437
        FileHandleCloseWrap::from_req(req));
438
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
439
    handle->AfterClose();
440
441
    int result = req->result;
442
    uv_fs_req_cleanup(req);
443
    wrap->Done(result);
444
  }});
445
446
  return 0;
447
}
448
449
450
5014
void FSReqCallback::Reject(Local<Value> reject) {
451
5014
  MakeCallback(env()->oncomplete_string(), 1, &reject);
452
5014
}
453
454
5849
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
455
5849
  Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
456
5849
}
457
458
54889
void FSReqCallback::Resolve(Local<Value> value) {
459
  Local<Value> argv[2] {
460
    Null(env()->isolate()),
461
    value
462
109778
  };
463
  MakeCallback(env()->oncomplete_string(),
464
154073
               value->IsUndefined() ? 1 : arraysize(argv),
465
99184
               argv);
466
54880
}
467
468
59903
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
469
119806
  args.GetReturnValue().SetUndefined();
470
59903
}
471
472
59923
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
473
59923
  CHECK(args.IsConstructCall());
474
59923
  Environment* env = Environment::GetCurrent(args);
475
179769
  new FSReqCallback(env, args.This(), args[0]->IsTrue());
476
59923
}
477
478
61124
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
479
    : wrap_(wrap),
480
      req_(req),
481
      handle_scope_(wrap->env()->isolate()),
482
61124
      context_scope_(wrap->env()->context()) {
483
61124
  CHECK_EQ(wrap_->req(), req);
484
61124
}
485
486
183345
FSReqAfterScope::~FSReqAfterScope() {
487
61115
  uv_fs_req_cleanup(wrap_->req());
488
61115
  delete wrap_;
489
61115
}
490
491
// TODO(joyeecheung): create a normal context object, and
492
// construct the actual errors in the JS land using the context.
493
// The context should include fds for some fs APIs, currently they are
494
// missing in the error messages. The path, dest, syscall, fd, .etc
495
// can be put into the context before the binding is even invoked,
496
// the only information that has to come from the C++ layer is the
497
// error number (and possibly the syscall for abstraction),
498
// which is also why the errors should have been constructed
499
// in JS for more flexibility.
500
5091
void FSReqAfterScope::Reject(uv_fs_t* req) {
501
  wrap_->Reject(UVException(wrap_->env()->isolate(),
502
                            req->result,
503
                            wrap_->syscall(),
504
                            nullptr,
505
                            req->path,
506
5091
                            wrap_->data()));
507
5091
}
508
509
61124
bool FSReqAfterScope::Proceed() {
510
61124
  if (req_->result < 0) {
511
5091
    Reject(req_);
512
5091
    return false;
513
  }
514
56033
  return true;
515
}
516
517
11404
void AfterNoArgs(uv_fs_t* req) {
518
11404
  FSReqBase* req_wrap = FSReqBase::from_req(req);
519
11404
  FSReqAfterScope after(req_wrap, req);
520
521
11404
  if (after.Proceed())
522
21300
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
523
11396
}
524
525
10174
void AfterStat(uv_fs_t* req) {
526
10174
  FSReqBase* req_wrap = FSReqBase::from_req(req);
527
10174
  FSReqAfterScope after(req_wrap, req);
528
529
10174
  if (after.Proceed()) {
530
6164
    req_wrap->ResolveStat(&req->statbuf);
531
10174
  }
532
10174
}
533
534
38984
void AfterInteger(uv_fs_t* req) {
535
38984
  FSReqBase* req_wrap = FSReqBase::from_req(req);
536
38984
  FSReqAfterScope after(req_wrap, req);
537
538
38984
  if (after.Proceed())
539
77462
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
540
38984
}
541
542
307
void AfterOpenFileHandle(uv_fs_t* req) {
543
307
  FSReqBase* req_wrap = FSReqBase::from_req(req);
544
307
  FSReqAfterScope after(req_wrap, req);
545
546
307
  if (after.Proceed()) {
547
254
    FileHandle* fd = FileHandle::New(req_wrap->env(), req->result);
548
561
    if (fd == nullptr) return;
549
508
    req_wrap->Resolve(fd->object());
550
307
  }
551
}
552
553
6
void AfterStringPath(uv_fs_t* req) {
554
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
555
6
  FSReqAfterScope after(req_wrap, req);
556
557
  MaybeLocal<Value> link;
558
  Local<Value> error;
559
560
6
  if (after.Proceed()) {
561
    link = StringBytes::Encode(req_wrap->env()->isolate(),
562
                               req->path,
563
                               req_wrap->encoding(),
564
5
                               &error);
565
5
    if (link.IsEmpty())
566
      req_wrap->Reject(error);
567
    else
568
10
      req_wrap->Resolve(link.ToLocalChecked());
569
6
  }
570
6
}
571
572
65
void AfterStringPtr(uv_fs_t* req) {
573
65
  FSReqBase* req_wrap = FSReqBase::from_req(req);
574
65
  FSReqAfterScope after(req_wrap, req);
575
576
  MaybeLocal<Value> link;
577
  Local<Value> error;
578
579
65
  if (after.Proceed()) {
580
    link = StringBytes::Encode(req_wrap->env()->isolate(),
581
                               static_cast<const char*>(req->ptr),
582
                               req_wrap->encoding(),
583
50
                               &error);
584
50
    if (link.IsEmpty())
585
      req_wrap->Reject(error);
586
    else
587
100
      req_wrap->Resolve(link.ToLocalChecked());
588
64
  }
589
64
}
590
591
148
void AfterScanDir(uv_fs_t* req) {
592
148
  FSReqBase* req_wrap = FSReqBase::from_req(req);
593
148
  FSReqAfterScope after(req_wrap, req);
594
595
148
  if (!after.Proceed()) {
596
3
    return;
597
  }
598
145
  Environment* env = req_wrap->env();
599
  Local<Value> error;
600
  int r;
601
290
  std::vector<Local<Value>> name_v;
602
603
6062
  for (int i = 0; ; i++) {
604
    uv_dirent_t ent;
605
606
6062
    r = uv_fs_scandir_next(req, &ent);
607
6062
    if (r == UV_EOF)
608
145
      break;
609
5917
    if (r != 0) {
610
      return req_wrap->Reject(UVException(
611
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
612
    }
613
614
    MaybeLocal<Value> filename =
615
      StringBytes::Encode(env->isolate(),
616
          ent.name,
617
          req_wrap->encoding(),
618
5917
          &error);
619
5917
    if (filename.IsEmpty())
620
      return req_wrap->Reject(error);
621
622
5917
    name_v.push_back(filename.ToLocalChecked());
623
5917
  }
624
625
435
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
626
}
627
628
7
void AfterScanDirWithTypes(uv_fs_t* req) {
629
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
630
7
  FSReqAfterScope after(req_wrap, req);
631
632
7
  if (!after.Proceed()) {
633
1
    return;
634
  }
635
636
6
  Environment* env = req_wrap->env();
637
6
  Isolate* isolate = env->isolate();
638
  Local<Value> error;
639
  int r;
640
641
12
  std::vector<Local<Value>> name_v;
642
12
  std::vector<Local<Value>> type_v;
643
644
22
  for (int i = 0; ; i++) {
645
    uv_dirent_t ent;
646
647
22
    r = uv_fs_scandir_next(req, &ent);
648
22
    if (r == UV_EOF)
649
6
      break;
650
16
    if (r != 0) {
651
      return req_wrap->Reject(
652
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
653
    }
654
655
    MaybeLocal<Value> filename =
656
      StringBytes::Encode(isolate,
657
          ent.name,
658
          req_wrap->encoding(),
659
16
          &error);
660
16
    if (filename.IsEmpty())
661
      return req_wrap->Reject(error);
662
663
16
    name_v.push_back(filename.ToLocalChecked());
664
16
    type_v.emplace_back(Integer::New(isolate, ent.type));
665
16
  }
666
667
6
  Local<Array> result = Array::New(isolate, 2);
668
6
  result->Set(env->context(),
669
              0,
670
              Array::New(isolate, name_v.data(),
671
24
              name_v.size())).Check();
672
6
  result->Set(env->context(),
673
              1,
674
              Array::New(isolate, type_v.data(),
675
24
              type_v.size())).Check();
676
18
  req_wrap->Resolve(result);
677
}
678
679
7055
void Access(const FunctionCallbackInfo<Value>& args) {
680
7055
  Environment* env = Environment::GetCurrent(args);
681
7055
  Isolate* isolate = env->isolate();
682
7055
  HandleScope scope(isolate);
683
684
7055
  const int argc = args.Length();
685
7055
  CHECK_GE(argc, 2);
686
687
14110
  CHECK(args[1]->IsInt32());
688
21165
  int mode = args[1].As<Int32>()->Value();
689
690
14110
  BufferValue path(isolate, args[0]);
691
7055
  CHECK_NOT_NULL(*path);
692
693
7055
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
694
7055
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
695
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
696
60
              uv_fs_access, *path, mode);
697
  } else {  // access(path, mode, undefined, ctx)
698
6995
    CHECK_EQ(argc, 4);
699
6995
    FSReqWrapSync req_wrap_sync;
700

6997
    FS_SYNC_TRACE_BEGIN(access);
701
13990
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
702

6997
    FS_SYNC_TRACE_END(access);
703
7055
  }
704
7055
}
705
706
707
62730
void Close(const FunctionCallbackInfo<Value>& args) {
708
62730
  Environment* env = Environment::GetCurrent(args);
709
710
62730
  const int argc = args.Length();
711
62730
  CHECK_GE(argc, 2);
712
713
125460
  CHECK(args[0]->IsInt32());
714
188190
  int fd = args[0].As<Int32>()->Value();
715
716
62730
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
717
62730
  if (req_wrap_async != nullptr) {  // close(fd, req)
718
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
719
7495
              uv_fs_close, fd);
720
  } else {  // close(fd, undefined, ctx)
721
55235
    CHECK_EQ(argc, 3);
722
55235
    FSReqWrapSync req_wrap_sync;
723

55295
    FS_SYNC_TRACE_BEGIN(close);
724
55235
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
725

55295
    FS_SYNC_TRACE_END(close);
726
  }
727
62730
}
728
729
730
// Used to speed up module loading.  Returns the contents of the file as
731
// a string or undefined when the file cannot be opened or "main" is not found
732
// in the file.
733
15688
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
734
15688
  Environment* env = Environment::GetCurrent(args);
735
15688
  Isolate* isolate = env->isolate();
736
15688
  uv_loop_t* loop = env->event_loop();
737
738
47064
  CHECK(args[0]->IsString());
739
15688
  node::Utf8Value path(isolate, args[0]);
740
741
15688
  if (strlen(*path) != path.length())
742
1
    return;  // Contains a nul byte.
743
744
  uv_fs_t open_req;
745
15687
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
746
15687
  uv_fs_req_cleanup(&open_req);
747
748
15687
  if (fd < 0) {
749
4355
    return;
750
  }
751
752
11332
  std::shared_ptr<void> defer_close(nullptr, [fd, loop] (...) {
753
    uv_fs_t close_req;
754
11332
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
755
11332
    uv_fs_req_cleanup(&close_req);
756
31123
  });
757
758
11332
  const size_t kBlockSize = 32 << 10;
759
19791
  std::vector<char> chars;
760
11332
  int64_t offset = 0;
761
  ssize_t numchars;
762
11331
  do {
763
11332
    const size_t start = chars.size();
764
11332
    chars.resize(start + kBlockSize);
765
766
    uv_buf_t buf;
767
11332
    buf.base = &chars[start];
768
11332
    buf.len = kBlockSize;
769
770
    uv_fs_t read_req;
771
11332
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
772
11332
    uv_fs_req_cleanup(&read_req);
773
774
11332
    if (numchars < 0)
775
1
      return;
776
777
11331
    offset += numchars;
778
  } while (static_cast<size_t>(numchars) == kBlockSize);
779
780
11331
  size_t start = 0;
781

11331
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
782
1
    start = 3;  // Skip UTF-8 BOM.
783
  }
784
785
11331
  const size_t size = offset - start;
786

25532
  if (size == 0 || (
787
15748
    size == SearchString(&chars[start], size, "\"main\"") &&
788
8836
    size == SearchString(&chars[start], size, "\"exports\"") &&
789
4417
    size == SearchString(&chars[start], size, "\"type\""))) {
790
2872
    return;
791
  } else {
792
    Local<String> chars_string =
793
        String::NewFromUtf8(isolate,
794
8459
                            &chars[start],
795
                            v8::NewStringType::kNormal,
796
25377
                            size).ToLocalChecked();
797
16918
    args.GetReturnValue().Set(chars_string);
798
8459
  }
799
}
800
801
// Used to speed up module loading.  Returns 0 if the path refers to
802
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
803
// The speedup comes from not creating thousands of Stat and Error objects.
804
176520
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
805
176520
  Environment* env = Environment::GetCurrent(args);
806
807
529560
  CHECK(args[0]->IsString());
808
176520
  node::Utf8Value path(env->isolate(), args[0]);
809
810
  uv_fs_t req;
811
176520
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
812
176520
  if (rc == 0) {
813
73733
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
814
73733
    rc = !!(s->st_mode & S_IFDIR);
815
  }
816
176520
  uv_fs_req_cleanup(&req);
817
818
353040
  args.GetReturnValue().Set(rc);
819
176520
}
820
821
34872
static void Stat(const FunctionCallbackInfo<Value>& args) {
822
34872
  Environment* env = Environment::GetCurrent(args);
823
824
34872
  const int argc = args.Length();
825
34872
  CHECK_GE(argc, 2);
826
827
34872
  BufferValue path(env->isolate(), args[0]);
828
34872
  CHECK_NOT_NULL(*path);
829
830
69744
  bool use_bigint = args[1]->IsTrue();
831
69744
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
832
34872
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
833
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
834
2013
              uv_fs_stat, *path);
835
  } else {  // stat(path, use_bigint, undefined, ctx)
836
32859
    CHECK_EQ(argc, 4);
837
32859
    FSReqWrapSync req_wrap_sync;
838

32861
    FS_SYNC_TRACE_BEGIN(stat);
839
65718
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
840

32861
    FS_SYNC_TRACE_END(stat);
841
32859
    if (err != 0) {
842
34879
      return;  // error info is in ctx
843
    }
844
845
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
846
32852
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
847

65704
    args.GetReturnValue().Set(arr);
848
34865
  }
849
}
850
851
122260
static void LStat(const FunctionCallbackInfo<Value>& args) {
852
122260
  Environment* env = Environment::GetCurrent(args);
853
854
122260
  const int argc = args.Length();
855
122260
  CHECK_GE(argc, 3);
856
857
122260
  BufferValue path(env->isolate(), args[0]);
858
122260
  CHECK_NOT_NULL(*path);
859
860
244520
  bool use_bigint = args[1]->IsTrue();
861
244520
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
862
122260
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
863
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
864
5248
              uv_fs_lstat, *path);
865
  } else {  // lstat(path, use_bigint, undefined, ctx)
866
117012
    CHECK_EQ(argc, 4);
867
117012
    FSReqWrapSync req_wrap_sync;
868

117046
    FS_SYNC_TRACE_BEGIN(lstat);
869
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
870
234024
                       *path);
871

117046
    FS_SYNC_TRACE_END(lstat);
872
117012
    if (err != 0) {
873
122525
      return;  // error info is in ctx
874
    }
875
876
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
877
116747
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
878

233494
    args.GetReturnValue().Set(arr);
879
121995
  }
880
}
881
882
51531
static void FStat(const FunctionCallbackInfo<Value>& args) {
883
51531
  Environment* env = Environment::GetCurrent(args);
884
885
51531
  const int argc = args.Length();
886
51531
  CHECK_GE(argc, 2);
887
888
103062
  CHECK(args[0]->IsInt32());
889
154593
  int fd = args[0].As<Int32>()->Value();
890
891
103062
  bool use_bigint = args[1]->IsTrue();
892
103062
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
893
51531
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
894
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
895
2913
              uv_fs_fstat, fd);
896
  } else {  // fstat(fd, use_bigint, undefined, ctx)
897
48618
    CHECK_EQ(argc, 4);
898
48618
    FSReqWrapSync req_wrap_sync;
899

48628
    FS_SYNC_TRACE_BEGIN(fstat);
900
48618
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
901

48628
    FS_SYNC_TRACE_END(fstat);
902
48618
    if (err != 0) {
903
51548
      return;  // error info is in ctx
904
    }
905
906
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
907
48601
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
908
97202
    args.GetReturnValue().Set(arr);
909
  }
910
}
911
912
102
static void Symlink(const FunctionCallbackInfo<Value>& args) {
913
102
  Environment* env = Environment::GetCurrent(args);
914
102
  Isolate* isolate = env->isolate();
915
916
102
  int argc = args.Length();
917
102
  CHECK_GE(argc, 4);
918
919
102
  BufferValue target(isolate, args[0]);
920
102
  CHECK_NOT_NULL(*target);
921
204
  BufferValue path(isolate, args[1]);
922
102
  CHECK_NOT_NULL(*path);
923
924
204
  CHECK(args[2]->IsInt32());
925
306
  int flags = args[2].As<Int32>()->Value();
926
927
102
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
928
102
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
929
20
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
930
40
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
931
  } else {  // symlink(target, path, flags, undefinec, ctx)
932
82
    CHECK_EQ(argc, 5);
933
82
    FSReqWrapSync req_wrap_sync;
934

86
    FS_SYNC_TRACE_BEGIN(symlink);
935
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
936
164
             uv_fs_symlink, *target, *path, flags);
937

86
    FS_SYNC_TRACE_END(symlink);
938
102
  }
939
102
}
940
941
105
static void Link(const FunctionCallbackInfo<Value>& args) {
942
105
  Environment* env = Environment::GetCurrent(args);
943
105
  Isolate* isolate = env->isolate();
944
945
105
  int argc = args.Length();
946
105
  CHECK_GE(argc, 3);
947
948
105
  BufferValue src(isolate, args[0]);
949
105
  CHECK_NOT_NULL(*src);
950
951
210
  BufferValue dest(isolate, args[1]);
952
105
  CHECK_NOT_NULL(*dest);
953
954
105
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
955
105
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
956
100
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
957
200
                  AfterNoArgs, uv_fs_link, *src, *dest);
958
  } else {  // link(src, dest)
959
5
    CHECK_EQ(argc, 4);
960
5
    FSReqWrapSync req_wrap_sync;
961

11
    FS_SYNC_TRACE_BEGIN(link);
962
    SyncCall(env, args[3], &req_wrap_sync, "link",
963
10
             uv_fs_link, *src, *dest);
964

11
    FS_SYNC_TRACE_END(link);
965
105
  }
966
105
}
967
968
89
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
969
89
  Environment* env = Environment::GetCurrent(args);
970
89
  Isolate* isolate = env->isolate();
971
972
89
  int argc = args.Length();
973
89
  CHECK_GE(argc, 3);
974
975
89
  BufferValue path(isolate, args[0]);
976
89
  CHECK_NOT_NULL(*path);
977
978
89
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
979
980
89
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
981
89
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
982
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
983
43
              uv_fs_readlink, *path);
984
  } else {
985
46
    CHECK_EQ(argc, 4);
986
46
    FSReqWrapSync req_wrap_sync;
987

48
    FS_SYNC_TRACE_BEGIN(readlink);
988
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
989
92
                       uv_fs_readlink, *path);
990

48
    FS_SYNC_TRACE_END(readlink);
991
46
    if (err < 0) {
992
1
      return;  // syscall failed, no need to continue, error info is in ctx
993
    }
994
45
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
995
996
    Local<Value> error;
997
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
998
                                               link_path,
999
                                               encoding,
1000
45
                                               &error);
1001
45
    if (rc.IsEmpty()) {
1002
      Local<Object> ctx = args[3].As<Object>();
1003
      ctx->Set(env->context(), env->error_string(), error).Check();
1004
      return;
1005
    }
1006
1007

90
    args.GetReturnValue().Set(rc.ToLocalChecked());
1008
88
  }
1009
}
1010
1011
233
static void Rename(const FunctionCallbackInfo<Value>& args) {
1012
233
  Environment* env = Environment::GetCurrent(args);
1013
233
  Isolate* isolate = env->isolate();
1014
1015
233
  int argc = args.Length();
1016
233
  CHECK_GE(argc, 3);
1017
1018
233
  BufferValue old_path(isolate, args[0]);
1019
233
  CHECK_NOT_NULL(*old_path);
1020
466
  BufferValue new_path(isolate, args[1]);
1021
233
  CHECK_NOT_NULL(*new_path);
1022
1023
233
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1024
233
  if (req_wrap_async != nullptr) {
1025
228
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1026
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1027
456
                  *old_path, *new_path);
1028
  } else {
1029
5
    CHECK_EQ(argc, 4);
1030
5
    FSReqWrapSync req_wrap_sync;
1031

7
    FS_SYNC_TRACE_BEGIN(rename);
1032
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1033
10
             *old_path, *new_path);
1034

7
    FS_SYNC_TRACE_END(rename);
1035
233
  }
1036
233
}
1037
1038
48
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1039
48
  Environment* env = Environment::GetCurrent(args);
1040
1041
48
  const int argc = args.Length();
1042
48
  CHECK_GE(argc, 3);
1043
1044
96
  CHECK(args[0]->IsInt32());
1045
144
  const int fd = args[0].As<Int32>()->Value();
1046
1047
48
  CHECK(IsSafeJsInt(args[1]));
1048
144
  const int64_t len = args[1].As<Integer>()->Value();
1049
1050
48
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1051
48
  if (req_wrap_async != nullptr) {
1052
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1053
34
              uv_fs_ftruncate, fd, len);
1054
  } else {
1055
14
    CHECK_EQ(argc, 4);
1056
14
    FSReqWrapSync req_wrap_sync;
1057

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1058
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1059
14
             len);
1060

16
    FS_SYNC_TRACE_END(ftruncate);
1061
  }
1062
48
}
1063
1064
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1065
7
  Environment* env = Environment::GetCurrent(args);
1066
1067
7
  const int argc = args.Length();
1068
7
  CHECK_GE(argc, 2);
1069
1070
14
  CHECK(args[0]->IsInt32());
1071
21
  const int fd = args[0].As<Int32>()->Value();
1072
1073
7
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1074
7
  if (req_wrap_async != nullptr) {
1075
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1076
4
              uv_fs_fdatasync, fd);
1077
  } else {
1078
3
    CHECK_EQ(argc, 3);
1079
3
    FSReqWrapSync req_wrap_sync;
1080

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

5
    FS_SYNC_TRACE_END(fdatasync);
1083
  }
1084
7
}
1085
1086
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1087
23
  Environment* env = Environment::GetCurrent(args);
1088
1089
23
  const int argc = args.Length();
1090
23
  CHECK_GE(argc, 2);
1091
1092
46
  CHECK(args[0]->IsInt32());
1093
69
  const int fd = args[0].As<Int32>()->Value();
1094
1095
23
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1096
23
  if (req_wrap_async != nullptr) {
1097
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1098
6
              uv_fs_fsync, fd);
1099
  } else {
1100
17
    CHECK_EQ(argc, 3);
1101
17
    FSReqWrapSync req_wrap_sync;
1102

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

19
    FS_SYNC_TRACE_END(fsync);
1105
  }
1106
23
}
1107
1108
3674
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1109
3674
  Environment* env = Environment::GetCurrent(args);
1110
1111
3674
  const int argc = args.Length();
1112
3674
  CHECK_GE(argc, 2);
1113
1114
3674
  BufferValue path(env->isolate(), args[0]);
1115
3674
  CHECK_NOT_NULL(*path);
1116
1117
3674
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1118
3674
  if (req_wrap_async != nullptr) {
1119
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1120
110
              uv_fs_unlink, *path);
1121
  } else {
1122
3564
    CHECK_EQ(argc, 3);
1123
3564
    FSReqWrapSync req_wrap_sync;
1124

3624
    FS_SYNC_TRACE_BEGIN(unlink);
1125
7128
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1126

3624
    FS_SYNC_TRACE_END(unlink);
1127
3674
  }
1128
3674
}
1129
1130
3900
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1131
3900
  Environment* env = Environment::GetCurrent(args);
1132
1133
3900
  const int argc = args.Length();
1134
3900
  CHECK_GE(argc, 2);
1135
1136
3900
  BufferValue path(env->isolate(), args[0]);
1137
3900
  CHECK_NOT_NULL(*path);
1138
1139
3900
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1140
3900
  if (req_wrap_async != nullptr) {
1141
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1142
47
              uv_fs_rmdir, *path);
1143
  } else {  // rmdir(path, undefined, ctx)
1144
3853
    CHECK_EQ(argc, 3);
1145
3853
    FSReqWrapSync req_wrap_sync;
1146

3859
    FS_SYNC_TRACE_BEGIN(rmdir);
1147
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1148
7706
             uv_fs_rmdir, *path);
1149

3859
    FS_SYNC_TRACE_END(rmdir);
1150
3900
  }
1151
3900
}
1152
1153
5113
int MKDirpSync(uv_loop_t* loop,
1154
               uv_fs_t* req,
1155
               const std::string& path,
1156
               int mode,
1157
               uv_fs_cb cb) {
1158
5113
  FSContinuationData continuation_data(req, mode, cb);
1159
5113
  continuation_data.PushPath(std::move(path));
1160
1161
5113
  while (continuation_data.paths.size() > 0) {
1162
5163
    std::string next_path = continuation_data.PopPath();
1163
5163
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1164
    while (true) {
1165

5164
      switch (err) {
1166
        case 0:
1167
49
          if (continuation_data.paths.size() == 0) {
1168
25
            return 0;
1169
          }
1170
24
          break;
1171
        case UV_ENOENT: {
1172
          std::string dirname = next_path.substr(0,
1173
26
                                        next_path.find_last_of(kPathSeparator));
1174
26
          if (dirname != next_path) {
1175
25
            continuation_data.PushPath(std::move(next_path));
1176
25
            continuation_data.PushPath(std::move(dirname));
1177
1
          } else if (continuation_data.paths.size() == 0) {
1178
1
            err = UV_EEXIST;
1179
1
            continue;
1180
          }
1181
25
          break;
1182
        }
1183
        case UV_EPERM: {
1184
          return err;
1185
        }
1186
        default:
1187
5089
          uv_fs_req_cleanup(req);
1188
5089
          int orig_err = err;
1189
5089
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1190

5089
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1191
1
            uv_fs_req_cleanup(req);
1192

1
            if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
1193
              return UV_ENOTDIR;
1194
            }
1195
1
            return UV_EEXIST;
1196
          }
1197
5088
          if (err < 0) return err;
1198
5086
          break;
1199
      }
1200
5135
      break;
1201
    }
1202
5135
    uv_fs_req_cleanup(req);
1203
5135
  }
1204
1205
5085
  return 0;
1206
}
1207
1208
22
int MKDirpAsync(uv_loop_t* loop,
1209
                uv_fs_t* req,
1210
                const char* path,
1211
                int mode,
1212
                uv_fs_cb cb) {
1213
22
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1214
  // on the first iteration of algorithm, stash state information.
1215
22
  if (req_wrap->continuation_data == nullptr) {
1216
20
    req_wrap->continuation_data =
1217
10
        std::make_unique<FSContinuationData>(req, mode, cb);
1218
10
    req_wrap->continuation_data->PushPath(std::move(path));
1219
  }
1220
1221
  // on each iteration of algorithm, mkdir directory on top of stack.
1222
22
  std::string next_path = req_wrap->continuation_data->PopPath();
1223
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1224
66
                        uv_fs_callback_t{[](uv_fs_t* req) {
1225
22
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1226
22
    Environment* env = req_wrap->env();
1227
22
    uv_loop_t* loop = env->event_loop();
1228
22
    std::string path = req->path;
1229
22
    int err = req->result;
1230
1231
    while (true) {
1232

23
      switch (err) {
1233
        case 0: {
1234
11
          if (req_wrap->continuation_data->paths.size() == 0) {
1235
5
            req_wrap->continuation_data->Done(0);
1236
          } else {
1237
6
            uv_fs_req_cleanup(req);
1238
            MKDirpAsync(loop, req, path.c_str(),
1239
6
                        req_wrap->continuation_data->mode, nullptr);
1240
          }
1241
11
          break;
1242
        }
1243
        case UV_ENOENT: {
1244
          std::string dirname = path.substr(0,
1245
7
                                            path.find_last_of(kPathSeparator));
1246
7
          if (dirname != path) {
1247
6
            req_wrap->continuation_data->PushPath(std::move(path));
1248
6
            req_wrap->continuation_data->PushPath(std::move(dirname));
1249
1
          } else if (req_wrap->continuation_data->paths.size() == 0) {
1250
1
            err = UV_EEXIST;
1251
1
            continue;
1252
          }
1253
6
          uv_fs_req_cleanup(req);
1254
          MKDirpAsync(loop, req, path.c_str(),
1255
6
                      req_wrap->continuation_data->mode, nullptr);
1256
6
          break;
1257
        }
1258
        case UV_EPERM: {
1259
          req_wrap->continuation_data->Done(err);
1260
          break;
1261
        }
1262
        default:
1263
5
          uv_fs_req_cleanup(req);
1264
          // Stash err for use in the callback.
1265
5
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1266
          int err = uv_fs_stat(loop, req, path.c_str(),
1267
15
                               uv_fs_callback_t{[](uv_fs_t* req) {
1268
5
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1269
5
            int err = req->result;
1270

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1271
3
                  req_wrap->continuation_data->paths.size() > 0) {
1272
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1273
                Environment* env = req_wrap->env();
1274
                uv_loop_t* loop = env->event_loop();
1275
                std::string path = req->path;
1276
                uv_fs_req_cleanup(req);
1277
                MKDirpAsync(loop, req, path.c_str(),
1278
                            req_wrap->continuation_data->mode, nullptr);
1279
5
                return;
1280
              }
1281
              err = UV_ENOTDIR;
1282
            }
1283
            // verify that the path pointed to is actually a directory.
1284

5
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1285
5
            uv_fs_req_cleanup(req);
1286
5
            req_wrap->continuation_data->Done(err);
1287
15
          }});
1288
5
          if (err < 0) req_wrap->continuation_data->Done(err);
1289
5
          break;
1290
      }
1291
22
      break;
1292
    }
1293
88
  }});
1294
1295
22
  return err;
1296
}
1297
1298
3281
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1299
3281
  Environment* env = Environment::GetCurrent(args);
1300
1301
3281
  const int argc = args.Length();
1302
3281
  CHECK_GE(argc, 4);
1303
1304
3281
  BufferValue path(env->isolate(), args[0]);
1305
3281
  CHECK_NOT_NULL(*path);
1306
1307
6562
  CHECK(args[1]->IsInt32());
1308
9843
  const int mode = args[1].As<Int32>()->Value();
1309
1310
6562
  CHECK(args[2]->IsBoolean());
1311
6562
  bool mkdirp = args[2]->IsTrue();
1312
1313
3281
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1314
3281
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1315
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1316
1139
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1317
  } else {  // mkdir(path, mode, undefined, ctx)
1318
2142
    CHECK_EQ(argc, 5);
1319
2142
    FSReqWrapSync req_wrap_sync;
1320

2146
    FS_SYNC_TRACE_BEGIN(mkdir);
1321
2142
    if (mkdirp) {
1322
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1323
22
               MKDirpSync, *path, mode);
1324
    } else {
1325
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1326
4262
               uv_fs_mkdir, *path, mode);
1327
    }
1328

2146
    FS_SYNC_TRACE_END(mkdir);
1329
3281
  }
1330
3281
}
1331
1332
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1333
42
  Environment* env = Environment::GetCurrent(args);
1334
42
  Isolate* isolate = env->isolate();
1335
1336
42
  const int argc = args.Length();
1337
42
  CHECK_GE(argc, 3);
1338
1339
42
  BufferValue path(isolate, args[0]);
1340
42
  CHECK_NOT_NULL(*path);
1341
1342
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1343
1344
42
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1345
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1346
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1347
22
              uv_fs_realpath, *path);
1348
  } else {  // realpath(path, encoding, undefined, ctx)
1349
20
    CHECK_EQ(argc, 4);
1350
20
    FSReqWrapSync req_wrap_sync;
1351

22
    FS_SYNC_TRACE_BEGIN(realpath);
1352
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1353
40
                       uv_fs_realpath, *path);
1354

22
    FS_SYNC_TRACE_END(realpath);
1355
20
    if (err < 0) {
1356
2
      return;  // syscall failed, no need to continue, error info is in ctx
1357
    }
1358
1359
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1360
1361
    Local<Value> error;
1362
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1363
                                               link_path,
1364
                                               encoding,
1365
18
                                               &error);
1366
18
    if (rc.IsEmpty()) {
1367
      Local<Object> ctx = args[3].As<Object>();
1368
      ctx->Set(env->context(), env->error_string(), error).Check();
1369
      return;
1370
    }
1371
1372

36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1373
40
  }
1374
}
1375
1376
16109
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1377
16109
  Environment* env = Environment::GetCurrent(args);
1378
16109
  Isolate* isolate = env->isolate();
1379
1380
16109
  const int argc = args.Length();
1381
16109
  CHECK_GE(argc, 3);
1382
1383
16109
  BufferValue path(isolate, args[0]);
1384
16109
  CHECK_NOT_NULL(*path);
1385
1386
16109
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1387
1388
32218
  bool with_types = args[2]->IsTrue();
1389
1390
16109
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1391
16109
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1392
155
    if (with_types) {
1393
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1394
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1395
    } else {
1396
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1397
148
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1398
    }
1399
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1400
15954
    CHECK_EQ(argc, 5);
1401
15954
    FSReqWrapSync req_wrap_sync;
1402

15956
    FS_SYNC_TRACE_BEGIN(readdir);
1403
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1404
31908
                       uv_fs_scandir, *path, 0 /*flags*/);
1405

15956
    FS_SYNC_TRACE_END(readdir);
1406
15954
    if (err < 0) {
1407
49
      return;  // syscall failed, no need to continue, error info is in ctx
1408
    }
1409
1410
15905
    CHECK_GE(req_wrap_sync.req.result, 0);
1411
    int r;
1412
31810
    std::vector<Local<Value>> name_v;
1413
31810
    std::vector<Local<Value>> type_v;
1414
1415
703058
    for (int i = 0; ; i++) {
1416
      uv_dirent_t ent;
1417
1418
703058
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1419
703058
      if (r == UV_EOF)
1420
15905
        break;
1421
687153
      if (r != 0) {
1422
        Local<Object> ctx = args[4].As<Object>();
1423
        ctx->Set(env->context(), env->errno_string(),
1424
                 Integer::New(isolate, r)).Check();
1425
        ctx->Set(env->context(), env->syscall_string(),
1426
                 OneByteString(isolate, "readdir")).Check();
1427
        return;
1428
      }
1429
1430
      Local<Value> error;
1431
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1432
                                                       ent.name,
1433
                                                       encoding,
1434
687153
                                                       &error);
1435
1436
687153
      if (filename.IsEmpty()) {
1437
        Local<Object> ctx = args[4].As<Object>();
1438
        ctx->Set(env->context(), env->error_string(), error).Check();
1439
        return;
1440
      }
1441
1442
687153
      name_v.push_back(filename.ToLocalChecked());
1443
1444
687153
      if (with_types) {
1445
370
        type_v.emplace_back(Integer::New(isolate, ent.type));
1446
      }
1447
687153
    }
1448
1449
1450
15905
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1451
15905
    if (with_types) {
1452
10
      Local<Array> result = Array::New(isolate, 2);
1453
30
      result->Set(env->context(), 0, names).Check();
1454
10
      result->Set(env->context(),
1455
                  1,
1456
                  Array::New(isolate, type_v.data(),
1457
40
                             type_v.size())).Check();
1458
20
      args.GetReturnValue().Set(result);
1459
    } else {
1460
31790
      args.GetReturnValue().Set(names);
1461
15905
    }
1462
16060
  }
1463
}
1464
1465
63651
static void Open(const FunctionCallbackInfo<Value>& args) {
1466
63651
  Environment* env = Environment::GetCurrent(args);
1467
1468
63651
  const int argc = args.Length();
1469
63651
  CHECK_GE(argc, 3);
1470
1471
63651
  BufferValue path(env->isolate(), args[0]);
1472
63651
  CHECK_NOT_NULL(*path);
1473
1474
127302
  CHECK(args[1]->IsInt32());
1475
190953
  const int flags = args[1].As<Int32>()->Value();
1476
1477
127302
  CHECK(args[2]->IsInt32());
1478
190953
  const int mode = args[2].As<Int32>()->Value();
1479
1480
63651
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1481
63651
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1482
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1483
7801
              uv_fs_open, *path, flags, mode);
1484
  } else {  // open(path, flags, mode, undefined, ctx)
1485
55850
    CHECK_EQ(argc, 5);
1486
55850
    FSReqWrapSync req_wrap_sync;
1487

55922
    FS_SYNC_TRACE_BEGIN(open);
1488
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1489
111700
                          uv_fs_open, *path, flags, mode);
1490

55922
    FS_SYNC_TRACE_END(open);
1491
111700
    args.GetReturnValue().Set(result);
1492
63651
  }
1493
63651
}
1494
1495
308
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1496
308
  Environment* env = Environment::GetCurrent(args);
1497
308
  Isolate* isolate = env->isolate();
1498
1499
308
  const int argc = args.Length();
1500
308
  CHECK_GE(argc, 3);
1501
1502
308
  BufferValue path(isolate, args[0]);
1503
308
  CHECK_NOT_NULL(*path);
1504
1505
616
  CHECK(args[1]->IsInt32());
1506
924
  const int flags = args[1].As<Int32>()->Value();
1507
1508
616
  CHECK(args[2]->IsInt32());
1509
924
  const int mode = args[2].As<Int32>()->Value();
1510
1511
308
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1512
308
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1513
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1514
307
              uv_fs_open, *path, flags, mode);
1515
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1516
1
    CHECK_EQ(argc, 5);
1517
1
    FSReqWrapSync req_wrap_sync;
1518

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

1
    FS_SYNC_TRACE_END(open);
1522
1
    if (result < 0) {
1523
      return;  // syscall failed, no need to continue, error info is in ctx
1524
    }
1525
1
    FileHandle* fd = FileHandle::New(env, result);
1526
1
    if (fd == nullptr) return;
1527

3
    args.GetReturnValue().Set(fd->object());
1528
308
  }
1529
}
1530
1531
35
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1532
35
  Environment* env = Environment::GetCurrent(args);
1533
35
  Isolate* isolate = env->isolate();
1534
1535
35
  const int argc = args.Length();
1536
35
  CHECK_GE(argc, 3);
1537
1538
35
  BufferValue src(isolate, args[0]);
1539
35
  CHECK_NOT_NULL(*src);
1540
1541
70
  BufferValue dest(isolate, args[1]);
1542
35
  CHECK_NOT_NULL(*dest);
1543
1544
70
  CHECK(args[2]->IsInt32());
1545
105
  const int flags = args[2].As<Int32>()->Value();
1546
1547
35
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1548
35
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1549
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1550
15
                  *dest, dest.length(), UTF8, AfterNoArgs,
1551
30
                  uv_fs_copyfile, *src, *dest, flags);
1552
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1553
20
    CHECK_EQ(argc, 5);
1554
20
    FSReqWrapSync req_wrap_sync;
1555

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1556
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1557
40
             uv_fs_copyfile, *src, *dest, flags);
1558

22
    FS_SYNC_TRACE_END(copyfile);
1559
35
  }
1560
35
}
1561
1562
1563
// Wrapper for write(2).
1564
//
1565
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1566
// 0 fd        integer. file descriptor
1567
// 1 buffer    the data to write
1568
// 2 offset    where in the buffer to start from
1569
// 3 length    how much to write
1570
// 4 position  if integer, position to write at in the file.
1571
//             if null, write from the current position
1572
157000
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1573
157000
  Environment* env = Environment::GetCurrent(args);
1574
1575
157000
  const int argc = args.Length();
1576
157000
  CHECK_GE(argc, 4);
1577
1578
314000
  CHECK(args[0]->IsInt32());
1579
471000
  const int fd = args[0].As<Int32>()->Value();
1580
1581
157000
  CHECK(Buffer::HasInstance(args[1]));
1582
314000
  Local<Object> buffer_obj = args[1].As<Object>();
1583
157000
  char* buffer_data = Buffer::Data(buffer_obj);
1584
157000
  size_t buffer_length = Buffer::Length(buffer_obj);
1585
1586
157000
  CHECK(IsSafeJsInt(args[2]));
1587
471000
  const int64_t off_64 = args[2].As<Integer>()->Value();
1588
157000
  CHECK_GE(off_64, 0);
1589
157000
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1590
157000
  const size_t off = static_cast<size_t>(off_64);
1591
1592
314000
  CHECK(args[3]->IsInt32());
1593
471000
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1594
157000
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1595
157000
  CHECK_LE(len, buffer_length);
1596
157000
  CHECK_GE(off + len, off);
1597
1598
157000
  const int64_t pos = GetOffset(args[4]);
1599
1600
157000
  char* buf = buffer_data + off;
1601
157000
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1602
1603
157000
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1604
157000
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1605
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1606
16582
              uv_fs_write, fd, &uvbuf, 1, pos);
1607
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1608
140418
    CHECK_EQ(argc, 7);
1609
140418
    FSReqWrapSync req_wrap_sync;
1610

140468
    FS_SYNC_TRACE_BEGIN(write);
1611
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1612
140418
                                uv_fs_write, fd, &uvbuf, 1, pos);
1613

140468
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1614
421254
    args.GetReturnValue().Set(bytesWritten);
1615
  }
1616
157000
}
1617
1618
1619
// Wrapper for writev(2).
1620
//
1621
// bytesWritten = writev(fd, chunks, position, callback)
1622
// 0 fd        integer. file descriptor
1623
// 1 chunks    array of buffers to write
1624
// 2 position  if integer, position to write at in the file.
1625
//             if null, write from the current position
1626
25
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1627
25
  Environment* env = Environment::GetCurrent(args);
1628
1629
25
  const int argc = args.Length();
1630
25
  CHECK_GE(argc, 3);
1631
1632
50
  CHECK(args[0]->IsInt32());
1633
75
  const int fd = args[0].As<Int32>()->Value();
1634
1635
50
  CHECK(args[1]->IsArray());
1636
50
  Local<Array> chunks = args[1].As<Array>();
1637
1638
25
  int64_t pos = GetOffset(args[2]);
1639
1640
25
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1641
1642
99594
  for (uint32_t i = 0; i < iovs.length(); i++) {
1643
298707
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1644
99569
    CHECK(Buffer::HasInstance(chunk));
1645
99569
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1646
  }
1647
1648
25
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1649
25
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1650
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1651
21
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1652
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1653
4
    CHECK_EQ(argc, 5);
1654
4
    FSReqWrapSync req_wrap_sync;
1655

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1659
12
    args.GetReturnValue().Set(bytesWritten);
1660
25
  }
1661
25
}
1662
1663
1664
// Wrapper for write(2).
1665
//
1666
// bytesWritten = write(fd, string, position, enc, callback)
1667
// 0 fd        integer. file descriptor
1668
// 1 string    non-buffer values are converted to strings
1669
// 2 position  if integer, position to write at in the file.
1670
//             if null, write from the current position
1671
// 3 enc       encoding of string
1672
1384
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1673
1384
  Environment* env = Environment::GetCurrent(args);
1674
1384
  Isolate* isolate = env->isolate();
1675
1676
1384
  const int argc = args.Length();
1677
1384
  CHECK_GE(argc, 4);
1678
1679
2768
  CHECK(args[0]->IsInt32());
1680
4152
  const int fd = args[0].As<Int32>()->Value();
1681
1682
1384
  const int64_t pos = GetOffset(args[2]);
1683
1684
1384
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1685
1686
1384
  Local<Value> value = args[1];
1687
1384
  char* buf = nullptr;
1688
  size_t len;
1689
1690
1384
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1691
1384
  const bool is_async = req_wrap_async != nullptr;
1692
1693
  // Avoid copying the string when it is externalized but only when:
1694
  // 1. The target encoding is compatible with the string's encoding, and
1695
  // 2. The write is synchronous, otherwise the string might get neutered
1696
  //    while the request is in flight, and
1697
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1698
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1699
  // The const_casts are conceptually sound: memory is read but not written.
1700

3868
  if (!is_async && value->IsString()) {
1701
1242
    auto string = value.As<String>();
1702


1243
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1703
1
      auto ext = string->GetExternalOneByteStringResource();
1704
1
      buf = const_cast<char*>(ext->data());
1705
1
      len = ext->length();
1706


1242
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1707
2
      auto ext = string->GetExternalStringResource();
1708
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1709
1
      len = ext->length() * sizeof(*ext->data());
1710
    }
1711
  }
1712
1713
1384
  if (is_async) {  // write(fd, string, pos, enc, req)
1714
142
    CHECK_NOT_NULL(req_wrap_async);
1715
284
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1716
    FSReqBase::FSReqBuffer& stack_buffer =
1717
142
        req_wrap_async->Init("write", len, enc);
1718
    // StorageSize may return too large a char, so correct the actual length
1719
    // by the write size
1720
142
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1721
142
    stack_buffer.SetLengthAndZeroTerminate(len);
1722
142
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1723
    int err = req_wrap_async->Dispatch(uv_fs_write,
1724
                                       fd,
1725
                                       &uvbuf,
1726
                                       1,
1727
                                       pos,
1728
142
                                       AfterInteger);
1729
142
    if (err < 0) {
1730
      uv_fs_t* uv_req = req_wrap_async->req();
1731
      uv_req->result = err;
1732
      uv_req->path = nullptr;
1733
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1734
                             // an error
1735
    } else {
1736
142
      req_wrap_async->SetReturnValue(args);
1737
    }
1738
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1739
1242
    CHECK_EQ(argc, 6);
1740
1242
    FSReqWrapSync req_wrap_sync;
1741
2484
    FSReqBase::FSReqBuffer stack_buffer;
1742
1242
    if (buf == nullptr) {
1743
2480
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1744
        return;
1745
1240
      stack_buffer.AllocateSufficientStorage(len + 1);
1746
      // StorageSize may return too large a char, so correct the actual length
1747
      // by the write size
1748
      len = StringBytes::Write(isolate, *stack_buffer,
1749
1240
                               len, args[1], enc);
1750
1240
      stack_buffer.SetLengthAndZeroTerminate(len);
1751
1240
      buf = *stack_buffer;
1752
    }
1753
1242
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1754

1242
    FS_SYNC_TRACE_BEGIN(write);
1755
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1756
1242
                                uv_fs_write, fd, &uvbuf, 1, pos);
1757

1242
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1758
4968
    args.GetReturnValue().Set(bytesWritten);
1759
  }
1760
}
1761
1762
1763
/*
1764
 * Wrapper for read(2).
1765
 *
1766
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1767
 *
1768
 * 0 fd        int32. file descriptor
1769
 * 1 buffer    instance of Buffer
1770
 * 2 offset    int64. offset to start reading into inside buffer
1771
 * 3 length    int32. length to read
1772
 * 4 position  int64. file position - -1 for current position
1773
 */
1774
123739
static void Read(const FunctionCallbackInfo<Value>& args) {
1775
123739
  Environment* env = Environment::GetCurrent(args);
1776
1777
123739
  const int argc = args.Length();
1778
123739
  CHECK_GE(argc, 5);
1779
1780
247478
  CHECK(args[0]->IsInt32());
1781
371217
  const int fd = args[0].As<Int32>()->Value();
1782
1783
123739
  CHECK(Buffer::HasInstance(args[1]));
1784
247478
  Local<Object> buffer_obj = args[1].As<Object>();
1785
123739
  char* buffer_data = Buffer::Data(buffer_obj);
1786
123739
  size_t buffer_length = Buffer::Length(buffer_obj);
1787
1788
123739
  CHECK(IsSafeJsInt(args[2]));
1789
371217
  const int64_t off_64 = args[2].As<Integer>()->Value();
1790
123739
  CHECK_GE(off_64, 0);
1791
123739
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
1792
123739
  const size_t off = static_cast<size_t>(off_64);
1793
1794
247478
  CHECK(args[3]->IsInt32());
1795
371217
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1796
123739
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1797
1798
123739
  CHECK(IsSafeJsInt(args[4]));
1799
371217
  const int64_t pos = args[4].As<Integer>()->Value();
1800
1801
123739
  char* buf = buffer_data + off;
1802
123739
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1803
1804
123739
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1805
123739
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1806
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1807
14438
              uv_fs_read, fd, &uvbuf, 1, pos);
1808
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1809
109301
    CHECK_EQ(argc, 7);
1810
109301
    FSReqWrapSync req_wrap_sync;
1811

109311
    FS_SYNC_TRACE_BEGIN(read);
1812
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1813
109301
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1814

109311
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1815
327903
    args.GetReturnValue().Set(bytesRead);
1816
  }
1817
123739
}
1818
1819
1820
/* fs.chmod(path, mode);
1821
 * Wrapper for chmod(1) / EIO_CHMOD
1822
 */
1823
230
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1824
230
  Environment* env = Environment::GetCurrent(args);
1825
1826
230
  const int argc = args.Length();
1827
230
  CHECK_GE(argc, 2);
1828
1829
230
  BufferValue path(env->isolate(), args[0]);
1830
230
  CHECK_NOT_NULL(*path);
1831
1832
460
  CHECK(args[1]->IsInt32());
1833
690
  int mode = args[1].As<Int32>()->Value();
1834
1835
230
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1836
230
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1837
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1838
216
              uv_fs_chmod, *path, mode);
1839
  } else {  // chmod(path, mode, undefined, ctx)
1840
14
    CHECK_EQ(argc, 4);
1841
14
    FSReqWrapSync req_wrap_sync;
1842

16
    FS_SYNC_TRACE_BEGIN(chmod);
1843
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1844
28
             uv_fs_chmod, *path, mode);
1845

16
    FS_SYNC_TRACE_END(chmod);
1846
230
  }
1847
230
}
1848
1849
1850
/* fs.fchmod(fd, mode);
1851
 * Wrapper for fchmod(1) / EIO_FCHMOD
1852
 */
1853
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1854
12
  Environment* env = Environment::GetCurrent(args);
1855
1856
12
  const int argc = args.Length();
1857
12
  CHECK_GE(argc, 2);
1858
1859
24
  CHECK(args[0]->IsInt32());
1860
36
  const int fd = args[0].As<Int32>()->Value();
1861
1862
24
  CHECK(args[1]->IsInt32());
1863
36
  const int mode = args[1].As<Int32>()->Value();
1864
1865
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1866
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1867
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1868
7
              uv_fs_fchmod, fd, mode);
1869
  } else {  // fchmod(fd, mode, undefined, ctx)
1870
5
    CHECK_EQ(argc, 4);
1871
5
    FSReqWrapSync req_wrap_sync;
1872

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1873
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1874
5
             uv_fs_fchmod, fd, mode);
1875

7
    FS_SYNC_TRACE_END(fchmod);
1876
  }
1877
12
}
1878
1879
1880
/* fs.chown(path, uid, gid);
1881
 * Wrapper for chown(1) / EIO_CHOWN
1882
 */
1883
109
static void Chown(const FunctionCallbackInfo<Value>& args) {
1884
109
  Environment* env = Environment::GetCurrent(args);
1885
1886
109
  const int argc = args.Length();
1887
109
  CHECK_GE(argc, 3);
1888
1889
109
  BufferValue path(env->isolate(), args[0]);
1890
109
  CHECK_NOT_NULL(*path);
1891
1892
218
  CHECK(args[1]->IsUint32());
1893
327
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1894
1895
218
  CHECK(args[2]->IsUint32());
1896
327
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1897
1898
109
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1899
109
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1900
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1901
106
              uv_fs_chown, *path, uid, gid);
1902
  } else {  // chown(path, uid, gid, undefined, ctx)
1903
3
    CHECK_EQ(argc, 5);
1904
3
    FSReqWrapSync req_wrap_sync;
1905

5
    FS_SYNC_TRACE_BEGIN(chown);
1906
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1907
6
             uv_fs_chown, *path, uid, gid);
1908

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

4
    FS_SYNC_TRACE_BEGIN(fchown);
1939
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
1940
2
             uv_fs_fchown, fd, uid, gid);
1941

4
    FS_SYNC_TRACE_END(fchown);
1942
  }
1943
4
}
1944
1945
1946
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
1947
9
  Environment* env = Environment::GetCurrent(args);
1948
1949
9
  const int argc = args.Length();
1950
9
  CHECK_GE(argc, 3);
1951
1952
9
  BufferValue path(env->isolate(), args[0]);
1953
9
  CHECK_NOT_NULL(*path);
1954
1955
18
  CHECK(args[1]->IsUint32());
1956
27
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1957
1958
18
  CHECK(args[2]->IsUint32());
1959
27
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1960
1961
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1962
9
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
1963
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
1964
7
              uv_fs_lchown, *path, uid, gid);
1965
  } else {  // lchown(path, uid, gid, undefined, ctx)
1966
2
    CHECK_EQ(argc, 5);
1967
2
    FSReqWrapSync req_wrap_sync;
1968

4
    FS_SYNC_TRACE_BEGIN(lchown);
1969
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
1970
4
             uv_fs_lchown, *path, uid, gid);
1971

4
    FS_SYNC_TRACE_END(lchown);
1972
9
  }
1973
9
}
1974
1975
1976
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
1977
29
  Environment* env = Environment::GetCurrent(args);
1978
1979
29
  const int argc = args.Length();
1980
29
  CHECK_GE(argc, 3);
1981
1982
29
  BufferValue path(env->isolate(), args[0]);
1983
29
  CHECK_NOT_NULL(*path);
1984
1985
58
  CHECK(args[1]->IsNumber());
1986
87
  const double atime = args[1].As<Number>()->Value();
1987
1988
58
  CHECK(args[2]->IsNumber());
1989
87
  const double mtime = args[2].As<Number>()->Value();
1990
1991
29
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1992
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
1993
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
1994
14
              uv_fs_utime, *path, atime, mtime);
1995
  } else {  // utimes(path, atime, mtime, undefined, ctx)
1996
15
    CHECK_EQ(argc, 5);
1997
15
    FSReqWrapSync req_wrap_sync;
1998

17
    FS_SYNC_TRACE_BEGIN(utimes);
1999
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2000
30
             uv_fs_utime, *path, atime, mtime);
2001

17
    FS_SYNC_TRACE_END(utimes);
2002
29
  }
2003
29
}
2004
2005
1803
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2006
1803
  Environment* env = Environment::GetCurrent(args);
2007
2008
1803
  const int argc = args.Length();
2009
1803
  CHECK_GE(argc, 3);
2010
2011
3606
  CHECK(args[0]->IsInt32());
2012
5409
  const int fd = args[0].As<Int32>()->Value();
2013
2014
3606
  CHECK(args[1]->IsNumber());
2015
5409
  const double atime = args[1].As<Number>()->Value();
2016
2017
3606
  CHECK(args[2]->IsNumber());
2018
5409
  const double mtime = args[2].As<Number>()->Value();
2019
2020
1803
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2021
1803
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2022
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2023
1795
              uv_fs_futime, fd, atime, mtime);
2024
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2025
8
    CHECK_EQ(argc, 5);
2026
8
    FSReqWrapSync req_wrap_sync;
2027

10
    FS_SYNC_TRACE_BEGIN(futimes);
2028
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2029
8
             uv_fs_futime, fd, atime, mtime);
2030

10
    FS_SYNC_TRACE_END(futimes);
2031
  }
2032
1803
}
2033
2034
13
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2035
13
  Environment* env = Environment::GetCurrent(args);
2036
13
  Isolate* isolate = env->isolate();
2037
2038
13
  const int argc = args.Length();
2039
13
  CHECK_GE(argc, 2);
2040
2041
13
  BufferValue tmpl(isolate, args[0]);
2042
13
  CHECK_NOT_NULL(*tmpl);
2043
2044
13
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2045
2046
13
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2047
13
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2048
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2049
6
              uv_fs_mkdtemp, *tmpl);
2050
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2051
7
    CHECK_EQ(argc, 4);
2052
7
    FSReqWrapSync req_wrap_sync;
2053

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2054
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2055
14
             uv_fs_mkdtemp, *tmpl);
2056

9
    FS_SYNC_TRACE_END(mkdtemp);
2057
7
    const char* path = req_wrap_sync.req.path;
2058
2059
    Local<Value> error;
2060
    MaybeLocal<Value> rc =
2061
7
        StringBytes::Encode(isolate, path, encoding, &error);
2062
7
    if (rc.IsEmpty()) {
2063
      Local<Object> ctx = args[3].As<Object>();
2064
      ctx->Set(env->context(), env->error_string(), error).Check();
2065
13
      return;
2066
    }
2067

14
    args.GetReturnValue().Set(rc.ToLocalChecked());
2068
13
  }
2069
}
2070
2071
5129
void Initialize(Local<Object> target,
2072
                Local<Value> unused,
2073
                Local<Context> context,
2074
                void* priv) {
2075
5129
  Environment* env = Environment::GetCurrent(context);
2076
5129
  Isolate* isolate = env->isolate();
2077
2078
5129
  env->SetMethod(target, "access", Access);
2079
5129
  env->SetMethod(target, "close", Close);
2080
5129
  env->SetMethod(target, "open", Open);
2081
5129
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2082
5129
  env->SetMethod(target, "read", Read);
2083
5129
  env->SetMethod(target, "fdatasync", Fdatasync);
2084
5129
  env->SetMethod(target, "fsync", Fsync);
2085
5129
  env->SetMethod(target, "rename", Rename);
2086
5129
  env->SetMethod(target, "ftruncate", FTruncate);
2087
5129
  env->SetMethod(target, "rmdir", RMDir);
2088
5129
  env->SetMethod(target, "mkdir", MKDir);
2089
5129
  env->SetMethod(target, "readdir", ReadDir);
2090
5129
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2091
5129
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2092
5129
  env->SetMethod(target, "stat", Stat);
2093
5129
  env->SetMethod(target, "lstat", LStat);
2094
5129
  env->SetMethod(target, "fstat", FStat);
2095
5129
  env->SetMethod(target, "link", Link);
2096
5129
  env->SetMethod(target, "symlink", Symlink);
2097
5129
  env->SetMethod(target, "readlink", ReadLink);
2098
5129
  env->SetMethod(target, "unlink", Unlink);
2099
5129
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2100
5129
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2101
5129
  env->SetMethod(target, "writeString", WriteString);
2102
5129
  env->SetMethod(target, "realpath", RealPath);
2103
5129
  env->SetMethod(target, "copyFile", CopyFile);
2104
2105
5129
  env->SetMethod(target, "chmod", Chmod);
2106
5129
  env->SetMethod(target, "fchmod", FChmod);
2107
  // env->SetMethod(target, "lchmod", LChmod);
2108
2109
5129
  env->SetMethod(target, "chown", Chown);
2110
5129
  env->SetMethod(target, "fchown", FChown);
2111
5129
  env->SetMethod(target, "lchown", LChown);
2112
2113
5129
  env->SetMethod(target, "utimes", UTimes);
2114
5129
  env->SetMethod(target, "futimes", FUTimes);
2115
2116
5129
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2117
2118
  target
2119
      ->Set(context,
2120
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2121
            Integer::New(
2122
                isolate,
2123
20516
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2124
10258
      .Check();
2125
2126
  target->Set(context,
2127
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2128
20516
              env->fs_stats_field_array()->GetJSArray()).Check();
2129
2130
  target->Set(context,
2131
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2132
20516
              env->fs_stats_field_bigint_array()->GetJSArray()).Check();
2133
2134
5129
  StatWatcher::Initialize(env, target);
2135
2136
  // Create FunctionTemplate for FSReqCallback
2137
5129
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2138
10258
  fst->InstanceTemplate()->SetInternalFieldCount(1);
2139
10258
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2140
  Local<String> wrapString =
2141
5129
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2142
5129
  fst->SetClassName(wrapString);
2143
  target
2144
      ->Set(context, wrapString,
2145
20516
            fst->GetFunction(env->context()).ToLocalChecked())
2146
10258
      .Check();
2147
2148
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2149
  // to do anything in the constructor, so we only store the instance template.
2150
5129
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2151
10258
  fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2152
10258
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2153
  Local<String> fhWrapString =
2154
5129
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2155
5129
  fh_rw->SetClassName(fhWrapString);
2156
  env->set_filehandlereadwrap_template(
2157
5129
      fst->InstanceTemplate());
2158
2159
  // Create Function Template for FSReqPromise
2160
5129
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2161
10258
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2162
  Local<String> promiseString =
2163
5129
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2164
5129
  fpt->SetClassName(promiseString);
2165
5129
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2166
5129
  fpo->SetInternalFieldCount(1);
2167
5129
  env->set_fsreqpromise_constructor_template(fpo);
2168
2169
  // Create FunctionTemplate for FileHandle
2170
5129
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2171
10258
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2172
5129
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2173
5129
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2174
5129
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2175
5129
  fdt->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
2176
  Local<String> handleString =
2177
5129
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2178
5129
  fd->SetClassName(handleString);
2179
5129
  StreamBase::AddMethods(env, fd);
2180
  target
2181
      ->Set(context, handleString,
2182
20516
            fd->GetFunction(env->context()).ToLocalChecked())
2183
10258
      .Check();
2184
5129
  env->set_fd_constructor_template(fdt);
2185
2186
  // Create FunctionTemplate for FileHandle::CloseReq
2187
5129
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2188
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2189
10258
                        "FileHandleCloseReq"));
2190
10258
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2191
5129
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2192
5129
  fdcloset->SetInternalFieldCount(1);
2193
5129
  env->set_fdclose_constructor_template(fdcloset);
2194
2195
  Local<Symbol> use_promises_symbol =
2196
    Symbol::New(isolate,
2197
5129
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2198
5129
  env->set_fs_use_promises_symbol(use_promises_symbol);
2199
  target->Set(context,
2200
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2201
15387
              use_promises_symbol).Check();
2202
5129
}
2203
2204
}  // namespace fs
2205
2206
}  // end namespace node
2207
2208

19927
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)