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: 1360 1453 93.6 %
Date: 2020-05-27 22:15:15 Branches: 770 1174 65.6 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
#include "node_file.h"  // NOLINT(build/include_inline)
22
#include "node_file-inl.h"
23
#include "aliased_buffer.h"
24
#include "memory_tracker-inl.h"
25
#include "node_buffer.h"
26
#include "node_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
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::Boolean;
55
using v8::Context;
56
using v8::EscapableHandleScope;
57
using v8::Function;
58
using v8::FunctionCallbackInfo;
59
using v8::FunctionTemplate;
60
using v8::HandleScope;
61
using v8::Int32;
62
using v8::Integer;
63
using v8::Isolate;
64
using v8::Local;
65
using v8::MaybeLocal;
66
using v8::Number;
67
using v8::Object;
68
using v8::ObjectTemplate;
69
using v8::Promise;
70
using v8::String;
71
using v8::Symbol;
72
using v8::Uint32;
73
using v8::Undefined;
74
using v8::Value;
75
76
#ifndef S_ISDIR
77
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
78
#endif
79
80
#ifdef __POSIX__
81
constexpr char kPathSeparator = '/';
82
#else
83
const char* const kPathSeparator = "\\/";
84
#endif
85
86
7
std::string Basename(const std::string& str, const std::string& extension) {
87
7
  std::string ret = str;
88
89
  // Remove everything leading up to and including the final path separator.
90
7
  std::string::size_type pos = ret.find_last_of(kPathSeparator);
91
7
  if (pos != std::string::npos) ret = ret.substr(pos + 1);
92
93
  // Strip away the extension, if any.
94

28
  if (ret.size() >= extension.size() &&
95
21
      ret.substr(ret.size() - extension.size()) == extension) {
96
    ret = ret.substr(0, ret.size() - extension.size());
97
  }
98
99
7
  return ret;
100
}
101
102
55710
inline int64_t GetOffset(Local<Value> value) {
103
55952
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
104
}
105
106
#define TRACE_NAME(name) "fs.sync." #name
107
#define GET_TRACE_ENABLED                                                  \
108
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
109
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
110
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
111
  if (GET_TRACE_ENABLED)                                                   \
112
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
113
  ##__VA_ARGS__);
114
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
115
  if (GET_TRACE_ENABLED)                                                   \
116
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
117
  ##__VA_ARGS__);
118
119
// We sometimes need to convert a C++ lambda function to a raw C-style function.
120
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
121
// functions, and thus does not wrap them properly.
122
typedef void(*uv_fs_callback_t)(uv_fs_t*);
123
124
125
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
126
  tracker->TrackField("paths", paths_);
127
}
128
129
30
FileHandleReadWrap::~FileHandleReadWrap() {}
130
131
50333
FSReqBase::~FSReqBase() {}
132
133
2
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
134
2
  tracker->TrackField("continuation_data", continuation_data_);
135
2
}
136
137
// The FileHandle object wraps a file descriptor and will close it on garbage
138
// collection if necessary. If that happens, a process warning will be
139
// emitted (or a fatal exception will occur if the fd cannot be closed.)
140
296
FileHandle::FileHandle(BindingData* binding_data,
141
296
                       Local<Object> obj, int fd)
142
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
143
      StreamBase(env()),
144
      fd_(fd),
145
296
      binding_data_(binding_data) {
146
296
  MakeWeak();
147
296
  StreamBase::AttachToObject(GetObject());
148
296
}
149
150
296
FileHandle* FileHandle::New(BindingData* binding_data,
151
                            int fd, Local<Object> obj) {
152
296
  Environment* env = binding_data->env();
153

1154
  if (obj.IsEmpty() && !env->fd_constructor_template()
154
858
                            ->NewInstance(env->context())
155
281
                            .ToLocal(&obj)) {
156
    return nullptr;
157
  }
158
296
  return new FileHandle(binding_data, obj, fd);
159
}
160
161
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
162
15
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
163
15
  Environment* env = binding_data->env();
164
15
  CHECK(args.IsConstructCall());
165
30
  CHECK(args[0]->IsInt32());
166
167
  FileHandle* handle =
168
45
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
169
15
  if (handle == nullptr) return;
170
30
  if (args[1]->IsNumber())
171
60
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
172
30
  if (args[2]->IsNumber())
173
60
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
174
}
175
176
888
FileHandle::~FileHandle() {
177
296
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
178
296
  Close();           // Close synchronously and emit warning
179
296
  CHECK(closed_);    // We have to be closed at the point
180
592
}
181
182
int FileHandle::DoWrite(WriteWrap* w,
183
                        uv_buf_t* bufs,
184
                        size_t count,
185
                        uv_stream_t* send_handle) {
186
  return UV_ENOSYS;  // Not implemented (yet).
187
}
188
189
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
190
  tracker->TrackField("current_read", current_read_);
191
}
192
193
// Close the file descriptor if it hasn't already been closed. A process
194
// warning will be emitted using a SetImmediate to avoid calling back to
195
// JS during GC. If closing the fd fails at this point, a fatal exception
196
// will crash the process immediately.
197
296
inline void FileHandle::Close() {
198
584
  if (closed_) return;
199
  uv_fs_t req;
200
8
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
201
8
  uv_fs_req_cleanup(&req);
202
203
  struct err_detail { int ret; int fd; };
204
205
8
  err_detail detail { ret, fd_ };
206
207
8
  AfterClose();
208
209
8
  if (ret < 0) {
210
    // Do not unref this
211
    env()->SetImmediate([detail](Environment* env) {
212
      char msg[70];
213
      snprintf(msg, arraysize(msg),
214
              "Closing file descriptor %d on garbage collection failed",
215
              detail.fd);
216
      // This exception will end up being fatal for the process because
217
      // it is being thrown from within the SetImmediate handler and
218
      // there is no JS stack to bubble it to. In other words, tearing
219
      // down the process is the only reasonable thing we can do here.
220
      HandleScope handle_scope(env->isolate());
221
      env->ThrowUVException(detail.ret, "close", msg);
222
    });
223
    return;
224
  }
225
226
  // If the close was successful, we still want to emit a process warning
227
  // to notify that the file descriptor was gc'd. We want to be noisy about
228
  // this because not explicitly closing the FileHandle is a bug.
229
230
19
  env()->SetImmediate([detail](Environment* env) {
231
    ProcessEmitWarning(env,
232
                       "Closing file descriptor %d on garbage collection",
233
3
                       detail.fd);
234
3
    if (env->filehandle_close_warning()) {
235
3
      env->set_filehandle_close_warning(false);
236
6
      ProcessEmitDeprecationWarning(
237
          env,
238
          "Closing a FileHandle object on garbage collection is deprecated. "
239
          "Please close FileHandle objects explicitly using "
240
          "FileHandle.prototype.close(). In the future, an error will be "
241
          "thrown if a file descriptor is closed during garbage collection.",
242
          "DEP0137").IsNothing();
243
    }
244
11
  }, CallbackFlags::kUnrefed);
245
}
246
247
279
void FileHandle::CloseReq::Resolve() {
248
279
  Isolate* isolate = env()->isolate();
249
558
  HandleScope scope(isolate);
250
558
  InternalCallbackScope callback_scope(this);
251
558
  Local<Promise> promise = promise_.Get(isolate);
252
279
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
253
837
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
254
279
}
255
256
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
257
1
  Isolate* isolate = env()->isolate();
258
2
  HandleScope scope(isolate);
259
2
  InternalCallbackScope callback_scope(this);
260
2
  Local<Promise> promise = promise_.Get(isolate);
261
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
262
3
  resolver->Reject(env()->context(), reason).Check();
263
1
}
264
265
280
FileHandle* FileHandle::CloseReq::file_handle() {
266
280
  Isolate* isolate = env()->isolate();
267
560
  HandleScope scope(isolate);
268
560
  Local<Value> val = ref_.Get(isolate);
269
280
  Local<Object> obj = val.As<Object>();
270
560
  return Unwrap<FileHandle>(obj);
271
}
272
273
280
FileHandle::CloseReq::CloseReq(Environment* env,
274
                               Local<Object> obj,
275
                               Local<Promise> promise,
276
280
                               Local<Value> ref)
277
560
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
278
280
  promise_.Reset(env->isolate(), promise);
279
280
  ref_.Reset(env->isolate(), ref);
280
280
}
281
282
1400
FileHandle::CloseReq::~CloseReq() {
283
280
  uv_fs_req_cleanup(req());
284
280
  promise_.Reset();
285
280
  ref_.Reset();
286
560
}
287
288
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
289
  tracker->TrackField("promise", promise_);
290
  tracker->TrackField("ref", ref_);
291
}
292
293
294
295
// Closes this FileHandle asynchronously and returns a Promise that will be
296
// resolved when the callback is invoked, or rejects with a UVException if
297
// there was a problem closing the fd. This is the preferred mechanism for
298
// closing the FD object even tho the object will attempt to close
299
// automatically on gc.
300
280
MaybeLocal<Promise> FileHandle::ClosePromise() {
301
280
  Isolate* isolate = env()->isolate();
302
280
  EscapableHandleScope scope(isolate);
303
280
  Local<Context> context = env()->context();
304
280
  auto maybe_resolver = Promise::Resolver::New(context);
305
280
  CHECK(!maybe_resolver.IsEmpty());
306
280
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
307
280
  Local<Promise> promise = resolver.As<Promise>();
308
280
  CHECK(!reading_);
309

280
  if (!closed_ && !closing_) {
310
280
    closing_ = true;
311
    Local<Object> close_req_obj;
312
560
    if (!env()
313
560
             ->fdclose_constructor_template()
314
840
             ->NewInstance(env()->context())
315
280
             .ToLocal(&close_req_obj)) {
316
      return MaybeLocal<Promise>();
317
    }
318
560
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
319
840
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
320
560
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
321
280
      CHECK_NOT_NULL(close);
322
280
      close->file_handle()->AfterClose();
323
280
      Isolate* isolate = close->env()->isolate();
324
280
      if (req->result < 0) {
325
2
        HandleScope handle_scope(isolate);
326
1
        close->Reject(UVException(isolate, req->result, "close"));
327
      } else {
328
279
        close->Resolve();
329
      }
330
1120
    }};
331
280
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
332
280
    if (ret < 0) {
333
      req->Reject(UVException(isolate, ret, "close"));
334
      delete req;
335
280
    }
336
  } else {
337
    // Already closed. Just reject the promise immediately
338
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
339
        .Check();
340
  }
341
280
  return scope.Escape(promise);
342
}
343
344
280
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
345
  FileHandle* fd;
346
280
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
347
  Local<Promise> ret;
348
560
  if (!fd->ClosePromise().ToLocal(&ret)) return;
349
560
  args.GetReturnValue().Set(ret);
350
}
351
352
353
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
354
  FileHandle* fd;
355
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
356
  // Just act as if this FileHandle has been closed.
357
8
  fd->AfterClose();
358
}
359
360
361
296
void FileHandle::AfterClose() {
362
296
  closing_ = false;
363
296
  closed_ = true;
364
296
  fd_ = -1;
365

296
  if (reading_ && !persistent().IsEmpty())
366
    EmitRead(UV_EOF);
367
296
}
368
369
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
370
  tracker->TrackField("buffer", buffer_);
371
  tracker->TrackField("file_handle", this->file_handle_);
372
}
373
374
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
375
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
376
15
    file_handle_(handle) {}
377
378
212
int FileHandle::ReadStart() {
379

212
  if (!IsAlive() || IsClosing())
380
    return UV_EOF;
381
382
212
  reading_ = true;
383
384
212
  if (current_read_)
385
    return 0;
386
387
424
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
388
389
212
  if (read_length_ == 0) {
390
5
    EmitRead(UV_EOF);
391
5
    return 0;
392
  }
393
394
  {
395
    // Create a new FileHandleReadWrap or re-use one.
396
    // Either way, we need these two scopes for AsyncReset() or otherwise
397
    // for creating the new instance.
398
414
    HandleScope handle_scope(env()->isolate());
399
414
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
400
401
207
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
402
207
    if (freelist.size() > 0) {
403
192
      read_wrap = std::move(freelist.back());
404
192
      freelist.pop_back();
405
      // Use a fresh async resource.
406
      // Lifetime is ensured via AsyncWrap::resource_.
407
192
      Local<Object> resource = Object::New(env()->isolate());
408
384
      USE(resource->Set(
409
1152
          env()->context(), env()->handle_string(), read_wrap->object()));
410
192
      read_wrap->AsyncReset(resource);
411
192
      read_wrap->file_handle_ = this;
412
    } else {
413
      Local<Object> wrap_obj;
414
30
      if (!env()
415
30
               ->filehandlereadwrap_template()
416
45
               ->NewInstance(env()->context())
417
15
               .ToLocal(&wrap_obj)) {
418
        return UV_EBUSY;
419
      }
420
15
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
421
    }
422
  }
423
207
  int64_t recommended_read = 65536;
424

207
  if (read_length_ >= 0 && read_length_ <= recommended_read)
425
7
    recommended_read = read_length_;
426
427
207
  read_wrap->buffer_ = EmitAlloc(recommended_read);
428
429
207
  current_read_ = std::move(read_wrap);
430
431
414
  current_read_->Dispatch(uv_fs_read,
432
                          fd_,
433
207
                          &current_read_->buffer_,
434
                          1,
435
                          read_offset_,
436
621
                          uv_fs_callback_t{[](uv_fs_t* req) {
437
    FileHandle* handle;
438
    {
439
207
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
440
207
      handle = req_wrap->file_handle_;
441
207
      CHECK_EQ(handle->current_read_.get(), req_wrap);
442
    }
443
444
    // ReadStart() checks whether current_read_ is set to determine whether
445
    // a read is in progress. Moving it into a local variable makes sure that
446
    // the ReadStart() call below doesn't think we're still actively reading.
447
    BaseObjectPtr<FileHandleReadWrap> read_wrap =
448
414
        std::move(handle->current_read_);
449
450
207
    int result = req->result;
451
207
    uv_buf_t buffer = read_wrap->buffer_;
452
453
207
    uv_fs_req_cleanup(req);
454
455
    // Push the read wrap back to the freelist, or let it be destroyed
456
    // once we’re exiting the current scope.
457
207
    constexpr size_t wanted_freelist_fill = 100;
458
207
    auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
459
207
    if (freelist.size() < wanted_freelist_fill) {
460
207
      read_wrap->Reset();
461
207
      freelist.emplace_back(std::move(read_wrap));
462
    }
463
464
207
    if (result >= 0) {
465
      // Read at most as many bytes as we originally planned to.
466

206
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
467
        result = handle->read_length_;
468
469
      // If we read data and we have an expected length, decrease it by
470
      // how much we have read.
471
206
      if (handle->read_length_ >= 0)
472
9
        handle->read_length_ -= result;
473
474
      // If we have an offset, increase it by how much we have read.
475
206
      if (handle->read_offset_ >= 0)
476
204
        handle->read_offset_ += result;
477
    }
478
479
    // Reading 0 bytes from a file always means EOF, or that we reached
480
    // the end of the requested range.
481
207
    if (result == 0)
482
7
      result = UV_EOF;
483
484
207
    handle->EmitRead(result, buffer);
485
486
    // Start over, if EmitRead() didn’t tell us to stop.
487
207
    if (handle->reading_)
488
      handle->ReadStart();
489
828
  }});
490
491
207
  return 0;
492
}
493
494
227
int FileHandle::ReadStop() {
495
227
  reading_ = false;
496
227
  return 0;
497
}
498
499
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
500
501
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
502
  return new FileHandleCloseWrap(this, object);
503
}
504
505
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
506
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
507
  closing_ = true;
508
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
509
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
510
        FileHandleCloseWrap::from_req(req));
511
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
512
    handle->AfterClose();
513
514
    int result = req->result;
515
    uv_fs_req_cleanup(req);
516
    wrap->Done(result);
517
  }});
518
519
  return 0;
520
}
521
522
523
3940
void FSReqCallback::Reject(Local<Value> reject) {
524
3940
  MakeCallback(env()->oncomplete_string(), 1, &reject);
525
3940
}
526
527
3897
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
528
3897
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
529
3897
}
530
531
45104
void FSReqCallback::Resolve(Local<Value> value) {
532
  Local<Value> argv[2] {
533
    Null(env()->isolate()),
534
    value
535
90208
  };
536
  MakeCallback(env()->oncomplete_string(),
537
127502
               value->IsUndefined() ? 1 : arraysize(argv),
538
82398
               argv);
539
45086
}
540
541
49049
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
542
98098
  args.GetReturnValue().SetUndefined();
543
49049
}
544
545
49072
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
546
49072
  CHECK(args.IsConstructCall());
547
49072
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
548
147216
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
549
49072
}
550
551
50328
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
552
    : wrap_(wrap),
553
      req_(req),
554
      handle_scope_(wrap->env()->isolate()),
555
50328
      context_scope_(wrap->env()->context()) {
556
50328
  CHECK_EQ(wrap_->req(), req);
557
50328
}
558
559
150930
FSReqAfterScope::~FSReqAfterScope() {
560
50310
  Clear();
561
50310
}
562
563
54308
void FSReqAfterScope::Clear() {
564
54308
  if (!wrap_) return;
565
566
50310
  uv_fs_req_cleanup(wrap_->req());
567
50310
  wrap_->Detach();
568
50310
  wrap_.reset();
569
}
570
571
// TODO(joyeecheung): create a normal context object, and
572
// construct the actual errors in the JS land using the context.
573
// The context should include fds for some fs APIs, currently they are
574
// missing in the error messages. The path, dest, syscall, fd, .etc
575
// can be put into the context before the binding is even invoked,
576
// the only information that has to come from the C++ layer is the
577
// error number (and possibly the syscall for abstraction),
578
// which is also why the errors should have been constructed
579
// in JS for more flexibility.
580
3987
void FSReqAfterScope::Reject(uv_fs_t* req) {
581
7974
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
582
  Local<Value> exception =
583
3987
      UVException(wrap_->env()->isolate(),
584
3987
                  req->result,
585
                  wrap_->syscall(),
586
                  nullptr,
587
                  req->path,
588
11961
                  wrap_->data());
589
3987
  Clear();
590
3987
  wrap->Reject(exception);
591
3987
}
592
593
50328
bool FSReqAfterScope::Proceed() {
594
50328
  if (req_->result < 0) {
595
3987
    Reject(req_);
596
3987
    return false;
597
  }
598
46341
  return true;
599
}
600
601
8456
void AfterNoArgs(uv_fs_t* req) {
602
8456
  FSReqBase* req_wrap = FSReqBase::from_req(req);
603
16897
  FSReqAfterScope after(req_wrap, req);
604
605
8456
  if (after.Proceed())
606
15718
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
607
8441
}
608
609
7391
void AfterStat(uv_fs_t* req) {
610
7391
  FSReqBase* req_wrap = FSReqBase::from_req(req);
611
14782
  FSReqAfterScope after(req_wrap, req);
612
613
7391
  if (after.Proceed()) {
614
4231
    req_wrap->ResolveStat(&req->statbuf);
615
  }
616
7391
}
617
618
33926
void AfterInteger(uv_fs_t* req) {
619
33926
  FSReqBase* req_wrap = FSReqBase::from_req(req);
620
67850
  FSReqAfterScope after(req_wrap, req);
621
622
33926
  if (after.Proceed())
623
67490
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
624
33924
}
625
626
304
void AfterOpenFileHandle(uv_fs_t* req) {
627
304
  FSReqBase* req_wrap = FSReqBase::from_req(req);
628
608
  FSReqAfterScope after(req_wrap, req);
629
630
304
  if (after.Proceed()) {
631
280
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(), req->result);
632
280
    if (fd == nullptr) return;
633
560
    req_wrap->Resolve(fd->object());
634
  }
635
}
636
637
// Reverse the logic applied by path.toNamespacedPath() to create a
638
// namespace-prefixed path.
639
110
void FromNamespacedPath(std::string* path) {
640
#ifdef _WIN32
641
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
642
    *path = path->substr(8);
643
    path->insert(0, "\\\\");
644
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
645
    *path = path->substr(4);
646
  }
647
#endif
648
110
}
649
650
14
void AfterMkdirp(uv_fs_t* req) {
651
14
  FSReqBase* req_wrap = FSReqBase::from_req(req);
652
28
  FSReqAfterScope after(req_wrap, req);
653
654
  MaybeLocal<Value> path;
655
  Local<Value> error;
656
657
14
  if (after.Proceed()) {
658
8
    if (!req_wrap->continuation_data()->first_path().empty()) {
659
14
      std::string first_path(req_wrap->continuation_data()->first_path());
660
7
      FromNamespacedPath(&first_path);
661
      path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
662
                                 req_wrap->encoding(),
663
7
                                 &error);
664
7
      if (path.IsEmpty())
665
        req_wrap->Reject(error);
666
      else
667
14
        req_wrap->Resolve(path.ToLocalChecked());
668
    } else {
669
2
      req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
670
    }
671
  }
672
14
}
673
674
6
void AfterStringPath(uv_fs_t* req) {
675
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
676
12
  FSReqAfterScope after(req_wrap, req);
677
678
  MaybeLocal<Value> link;
679
  Local<Value> error;
680
681
6
  if (after.Proceed()) {
682
    link = StringBytes::Encode(req_wrap->env()->isolate(),
683
                               req->path,
684
                               req_wrap->encoding(),
685
5
                               &error);
686
5
    if (link.IsEmpty())
687
      req_wrap->Reject(error);
688
    else
689
10
      req_wrap->Resolve(link.ToLocalChecked());
690
  }
691
6
}
692
693
63
void AfterStringPtr(uv_fs_t* req) {
694
63
  FSReqBase* req_wrap = FSReqBase::from_req(req);
695
125
  FSReqAfterScope after(req_wrap, req);
696
697
  MaybeLocal<Value> link;
698
  Local<Value> error;
699
700
63
  if (after.Proceed()) {
701
    link = StringBytes::Encode(req_wrap->env()->isolate(),
702
50
                               static_cast<const char*>(req->ptr),
703
                               req_wrap->encoding(),
704
100
                               &error);
705
50
    if (link.IsEmpty())
706
      req_wrap->Reject(error);
707
    else
708
100
      req_wrap->Resolve(link.ToLocalChecked());
709
  }
710
62
}
711
712
129
void AfterScanDir(uv_fs_t* req) {
713
129
  FSReqBase* req_wrap = FSReqBase::from_req(req);
714
255
  FSReqAfterScope after(req_wrap, req);
715
716
129
  if (!after.Proceed()) {
717
3
    return;
718
  }
719
126
  Environment* env = req_wrap->env();
720
  Local<Value> error;
721
  int r;
722
252
  std::vector<Local<Value>> name_v;
723
724
6616
  for (int i = 0; ; i++) {
725
    uv_dirent_t ent;
726
727
6616
    r = uv_fs_scandir_next(req, &ent);
728
6616
    if (r == UV_EOF)
729
126
      break;
730
6490
    if (r != 0) {
731
      return req_wrap->Reject(UVException(
732
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
733
    }
734
735
    MaybeLocal<Value> filename =
736
      StringBytes::Encode(env->isolate(),
737
          ent.name,
738
          req_wrap->encoding(),
739
6490
          &error);
740
6490
    if (filename.IsEmpty())
741
      return req_wrap->Reject(error);
742
743
6490
    name_v.push_back(filename.ToLocalChecked());
744
6490
  }
745
746
252
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
747
}
748
749
7
void AfterScanDirWithTypes(uv_fs_t* req) {
750
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
751
13
  FSReqAfterScope after(req_wrap, req);
752
753
7
  if (!after.Proceed()) {
754
1
    return;
755
  }
756
757
6
  Environment* env = req_wrap->env();
758
6
  Isolate* isolate = env->isolate();
759
  Local<Value> error;
760
  int r;
761
762
12
  std::vector<Local<Value>> name_v;
763
12
  std::vector<Local<Value>> type_v;
764
765
22
  for (int i = 0; ; i++) {
766
    uv_dirent_t ent;
767
768
22
    r = uv_fs_scandir_next(req, &ent);
769
22
    if (r == UV_EOF)
770
6
      break;
771
16
    if (r != 0) {
772
      return req_wrap->Reject(
773
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
774
    }
775
776
    MaybeLocal<Value> filename =
777
      StringBytes::Encode(isolate,
778
          ent.name,
779
          req_wrap->encoding(),
780
16
          &error);
781
16
    if (filename.IsEmpty())
782
      return req_wrap->Reject(error);
783
784
16
    name_v.push_back(filename.ToLocalChecked());
785
16
    type_v.emplace_back(Integer::New(isolate, ent.type));
786
16
  }
787
788
  Local<Value> result[] = {
789
    Array::New(isolate, name_v.data(), name_v.size()),
790
    Array::New(isolate, type_v.data(), type_v.size())
791
18
  };
792
12
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
793
}
794
795
199
void Access(const FunctionCallbackInfo<Value>& args) {
796
199
  Environment* env = Environment::GetCurrent(args);
797
199
  Isolate* isolate = env->isolate();
798
398
  HandleScope scope(isolate);
799
800
199
  const int argc = args.Length();
801
199
  CHECK_GE(argc, 2);
802
803
398
  CHECK(args[1]->IsInt32());
804
597
  int mode = args[1].As<Int32>()->Value();
805
806
398
  BufferValue path(isolate, args[0]);
807
199
  CHECK_NOT_NULL(*path);
808
809
199
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
810
199
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
811
51
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
812
51
              uv_fs_access, *path, mode);
813
  } else {  // access(path, mode, undefined, ctx)
814
148
    CHECK_EQ(argc, 4);
815
296
    FSReqWrapSync req_wrap_sync;
816

150
    FS_SYNC_TRACE_BEGIN(access);
817
296
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
818

150
    FS_SYNC_TRACE_END(access);
819
  }
820
199
}
821
822
823
40768
void Close(const FunctionCallbackInfo<Value>& args) {
824
40768
  Environment* env = Environment::GetCurrent(args);
825
826
40768
  const int argc = args.Length();
827
40768
  CHECK_GE(argc, 2);
828
829
81536
  CHECK(args[0]->IsInt32());
830
122304
  int fd = args[0].As<Int32>()->Value();
831
832
40768
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
833
40768
  if (req_wrap_async != nullptr) {  // close(fd, req)
834
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
835
5089
              uv_fs_close, fd);
836
  } else {  // close(fd, undefined, ctx)
837
35679
    CHECK_EQ(argc, 3);
838
71358
    FSReqWrapSync req_wrap_sync;
839

35739
    FS_SYNC_TRACE_BEGIN(close);
840
35679
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
841

35739
    FS_SYNC_TRACE_END(close);
842
  }
843
40768
}
844
845
846
// Used to speed up module loading. Returns an array [string, boolean]
847
51198
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
848
51198
  Environment* env = Environment::GetCurrent(args);
849
51198
  Isolate* isolate = env->isolate();
850
51198
  uv_loop_t* loop = env->event_loop();
851
852
153594
  CHECK(args[0]->IsString());
853
56715
  node::Utf8Value path(isolate, args[0]);
854
855
51198
  if (strlen(*path) != path.length()) {
856
9
    args.GetReturnValue().Set(Array::New(isolate));
857
3
    return;  // Contains a nul byte.
858
  }
859
  uv_fs_t open_req;
860
51195
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
861
51195
  uv_fs_req_cleanup(&open_req);
862
863
51195
  if (fd < 0) {
864
137031
    args.GetReturnValue().Set(Array::New(isolate));
865
45677
    return;
866
  }
867
868
5518
  auto defer_close = OnScopeLeave([fd, loop]() {
869
    uv_fs_t close_req;
870
5518
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
871
5518
    uv_fs_req_cleanup(&close_req);
872
16553
  });
873
874
5518
  const size_t kBlockSize = 32 << 10;
875
11035
  std::vector<char> chars;
876
5518
  int64_t offset = 0;
877
  ssize_t numchars;
878
  do {
879
5518
    const size_t start = chars.size();
880
5518
    chars.resize(start + kBlockSize);
881
882
    uv_buf_t buf;
883
5518
    buf.base = &chars[start];
884
5518
    buf.len = kBlockSize;
885
886
    uv_fs_t read_req;
887
5518
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
888
5518
    uv_fs_req_cleanup(&read_req);
889
890
5518
    if (numchars < 0) {
891
3
      args.GetReturnValue().Set(Array::New(isolate));
892
1
      return;
893
    }
894
5517
    offset += numchars;
895
5517
  } while (static_cast<size_t>(numchars) == kBlockSize);
896
897
5517
  size_t start = 0;
898

5517
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
899
1
    start = 3;  // Skip UTF-8 BOM.
900
  }
901
902
5517
  const size_t size = offset - start;
903
5517
  char* p = &chars[start];
904
5517
  char* pe = &chars[size];
905
  char* pos[2];
906
5517
  char** ppos = &pos[0];
907
908
2704455
  while (p < pe) {
909
1354976
    char c = *p++;
910

1354976
    if (c == '\\' && p < pe && *p == '"') p++;
911
1354976
    if (c != '"') continue;
912
130050
    *ppos++ = p;
913
130050
    if (ppos < &pos[2]) continue;
914
65025
    ppos = &pos[0];
915
916
65025
    char* s = &pos[0][0];
917
65025
    char* se = &pos[1][-1];  // Exclude quote.
918
65025
    size_t n = se - s;
919
920
65025
    if (n == 4) {
921
5754
      if (0 == memcmp(s, "main", 4)) break;
922
5641
      if (0 == memcmp(s, "name", 4)) break;
923
5087
      if (0 == memcmp(s, "type", 4)) break;
924
59271
    } else if (n == 7) {
925
932
      if (0 == memcmp(s, "exports", 7)) break;
926
    }
927
  }
928
929
930
  Local<Value> return_value[] = {
931
11034
    String::NewFromUtf8(isolate,
932
5517
                        &chars[start],
933
                        v8::NewStringType::kNormal,
934
5517
                        size).ToLocalChecked(),
935
    Boolean::New(isolate, p < pe ? true : false)
936
16551
  };
937
16551
  args.GetReturnValue().Set(
938
    Array::New(isolate, return_value, arraysize(return_value)));
939
}
940
941
// Used to speed up module loading.  Returns 0 if the path refers to
942
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
943
// The speedup comes from not creating thousands of Stat and Error objects.
944
101448
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
945
101448
  Environment* env = Environment::GetCurrent(args);
946
947
304347
  CHECK(args[0]->IsString());
948
202898
  node::Utf8Value path(env->isolate(), args[0]);
949
950
  uv_fs_t req;
951
101449
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
952
101448
  if (rc == 0) {
953
47249
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
954
47249
    rc = !!(s->st_mode & S_IFDIR);
955
  }
956
101448
  uv_fs_req_cleanup(&req);
957
958
202898
  args.GetReturnValue().Set(rc);
959
101448
}
960
961
15888
static void Stat(const FunctionCallbackInfo<Value>& args) {
962
15888
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
963
15888
  Environment* env = binding_data->env();
964
965
15888
  const int argc = args.Length();
966
15888
  CHECK_GE(argc, 2);
967
968
31588
  BufferValue path(env->isolate(), args[0]);
969
15888
  CHECK_NOT_NULL(*path);
970
971
31776
  bool use_bigint = args[1]->IsTrue();
972
15888
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
973
15888
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
974
1812
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
975
1812
              uv_fs_stat, *path);
976
  } else {  // stat(path, use_bigint, undefined, ctx)
977
14076
    CHECK_EQ(argc, 4);
978
27964
    FSReqWrapSync req_wrap_sync;
979

14078
    FS_SYNC_TRACE_BEGIN(stat);
980
28152
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
981

14078
    FS_SYNC_TRACE_END(stat);
982
14076
    if (err != 0) {
983
188
      return;  // error info is in ctx
984
    }
985
986
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
987
13888
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
988
27776
    args.GetReturnValue().Set(arr);
989
  }
990
}
991
992
92097
static void LStat(const FunctionCallbackInfo<Value>& args) {
993
92097
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
994
92097
  Environment* env = binding_data->env();
995
996
92097
  const int argc = args.Length();
997
92097
  CHECK_GE(argc, 3);
998
999
183921
  BufferValue path(env->isolate(), args[0]);
1000
92097
  CHECK_NOT_NULL(*path);
1001
1002
184194
  bool use_bigint = args[1]->IsTrue();
1003
92097
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1004
92097
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1005
4385
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1006
4385
              uv_fs_lstat, *path);
1007
  } else {  // lstat(path, use_bigint, undefined, ctx)
1008
87712
    CHECK_EQ(argc, 4);
1009
175151
    FSReqWrapSync req_wrap_sync;
1010

87746
    FS_SYNC_TRACE_BEGIN(lstat);
1011
87712
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1012
87712
                       *path);
1013

87746
    FS_SYNC_TRACE_END(lstat);
1014
87712
    if (err != 0) {
1015
273
      return;  // error info is in ctx
1016
    }
1017
1018
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1019
87439
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1020
174878
    args.GetReturnValue().Set(arr);
1021
  }
1022
}
1023
1024
32711
static void FStat(const FunctionCallbackInfo<Value>& args) {
1025
32711
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1026
32711
  Environment* env = binding_data->env();
1027
1028
32711
  const int argc = args.Length();
1029
32711
  CHECK_GE(argc, 2);
1030
1031
65422
  CHECK(args[0]->IsInt32());
1032
98133
  int fd = args[0].As<Int32>()->Value();
1033
1034
65422
  bool use_bigint = args[1]->IsTrue();
1035
32711
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1036
32711
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1037
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1038
1194
              uv_fs_fstat, fd);
1039
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1040
31517
    CHECK_EQ(argc, 4);
1041
63017
    FSReqWrapSync req_wrap_sync;
1042

31527
    FS_SYNC_TRACE_BEGIN(fstat);
1043
31517
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1044

31527
    FS_SYNC_TRACE_END(fstat);
1045
31517
    if (err != 0) {
1046
17
      return;  // error info is in ctx
1047
    }
1048
1049
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1050
31500
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1051
63000
    args.GetReturnValue().Set(arr);
1052
  }
1053
}
1054
1055
208
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1056
208
  Environment* env = Environment::GetCurrent(args);
1057
208
  Isolate* isolate = env->isolate();
1058
1059
208
  const int argc = args.Length();
1060
208
  CHECK_GE(argc, 4);
1061
1062
416
  BufferValue target(isolate, args[0]);
1063
208
  CHECK_NOT_NULL(*target);
1064
416
  BufferValue path(isolate, args[1]);
1065
208
  CHECK_NOT_NULL(*path);
1066
1067
416
  CHECK(args[2]->IsInt32());
1068
624
  int flags = args[2].As<Int32>()->Value();
1069
1070
208
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1071
208
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1072
26
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1073
26
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1074
  } else {  // symlink(target, path, flags, undefinec, ctx)
1075
182
    CHECK_EQ(argc, 5);
1076
364
    FSReqWrapSync req_wrap_sync;
1077

186
    FS_SYNC_TRACE_BEGIN(symlink);
1078
182
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1079
182
             uv_fs_symlink, *target, *path, flags);
1080

186
    FS_SYNC_TRACE_END(symlink);
1081
  }
1082
208
}
1083
1084
76
static void Link(const FunctionCallbackInfo<Value>& args) {
1085
76
  Environment* env = Environment::GetCurrent(args);
1086
76
  Isolate* isolate = env->isolate();
1087
1088
76
  const int argc = args.Length();
1089
76
  CHECK_GE(argc, 3);
1090
1091
152
  BufferValue src(isolate, args[0]);
1092
76
  CHECK_NOT_NULL(*src);
1093
1094
152
  BufferValue dest(isolate, args[1]);
1095
76
  CHECK_NOT_NULL(*dest);
1096
1097
76
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1098
76
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1099
71
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1100
71
                  AfterNoArgs, uv_fs_link, *src, *dest);
1101
  } else {  // link(src, dest)
1102
5
    CHECK_EQ(argc, 4);
1103
10
    FSReqWrapSync req_wrap_sync;
1104

11
    FS_SYNC_TRACE_BEGIN(link);
1105
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1106
5
             uv_fs_link, *src, *dest);
1107

11
    FS_SYNC_TRACE_END(link);
1108
  }
1109
76
}
1110
1111
89
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1112
89
  Environment* env = Environment::GetCurrent(args);
1113
89
  Isolate* isolate = env->isolate();
1114
1115
89
  const int argc = args.Length();
1116
89
  CHECK_GE(argc, 3);
1117
1118
177
  BufferValue path(isolate, args[0]);
1119
89
  CHECK_NOT_NULL(*path);
1120
1121
89
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1122
1123
89
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1124
89
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1125
41
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1126
41
              uv_fs_readlink, *path);
1127
  } else {
1128
48
    CHECK_EQ(argc, 4);
1129
95
    FSReqWrapSync req_wrap_sync;
1130

50
    FS_SYNC_TRACE_BEGIN(readlink);
1131
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1132
48
                       uv_fs_readlink, *path);
1133

50
    FS_SYNC_TRACE_END(readlink);
1134
48
    if (err < 0) {
1135
1
      return;  // syscall failed, no need to continue, error info is in ctx
1136
    }
1137
47
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1138
1139
    Local<Value> error;
1140
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1141
                                               link_path,
1142
                                               encoding,
1143
47
                                               &error);
1144
47
    if (rc.IsEmpty()) {
1145
      Local<Object> ctx = args[3].As<Object>();
1146
      ctx->Set(env->context(), env->error_string(), error).Check();
1147
      return;
1148
    }
1149
1150
94
    args.GetReturnValue().Set(rc.ToLocalChecked());
1151
  }
1152
}
1153
1154
144
static void Rename(const FunctionCallbackInfo<Value>& args) {
1155
144
  Environment* env = Environment::GetCurrent(args);
1156
144
  Isolate* isolate = env->isolate();
1157
1158
144
  const int argc = args.Length();
1159
144
  CHECK_GE(argc, 3);
1160
1161
288
  BufferValue old_path(isolate, args[0]);
1162
144
  CHECK_NOT_NULL(*old_path);
1163
288
  BufferValue new_path(isolate, args[1]);
1164
144
  CHECK_NOT_NULL(*new_path);
1165
1166
144
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1167
144
  if (req_wrap_async != nullptr) {
1168
139
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1169
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1170
139
                  *old_path, *new_path);
1171
  } else {
1172
5
    CHECK_EQ(argc, 4);
1173
10
    FSReqWrapSync req_wrap_sync;
1174

7
    FS_SYNC_TRACE_BEGIN(rename);
1175
5
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1176
5
             *old_path, *new_path);
1177

7
    FS_SYNC_TRACE_END(rename);
1178
  }
1179
144
}
1180
1181
50
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1182
50
  Environment* env = Environment::GetCurrent(args);
1183
1184
50
  const int argc = args.Length();
1185
50
  CHECK_GE(argc, 3);
1186
1187
100
  CHECK(args[0]->IsInt32());
1188
150
  const int fd = args[0].As<Int32>()->Value();
1189
1190
50
  CHECK(IsSafeJsInt(args[1]));
1191
150
  const int64_t len = args[1].As<Integer>()->Value();
1192
1193
50
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1194
50
  if (req_wrap_async != nullptr) {
1195
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1196
37
              uv_fs_ftruncate, fd, len);
1197
  } else {
1198
13
    CHECK_EQ(argc, 4);
1199
26
    FSReqWrapSync req_wrap_sync;
1200

15
    FS_SYNC_TRACE_BEGIN(ftruncate);
1201
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1202
13
             len);
1203

15
    FS_SYNC_TRACE_END(ftruncate);
1204
  }
1205
50
}
1206
1207
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1208
7
  Environment* env = Environment::GetCurrent(args);
1209
1210
7
  const int argc = args.Length();
1211
7
  CHECK_GE(argc, 2);
1212
1213
14
  CHECK(args[0]->IsInt32());
1214
21
  const int fd = args[0].As<Int32>()->Value();
1215
1216
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1217
7
  if (req_wrap_async != nullptr) {
1218
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1219
4
              uv_fs_fdatasync, fd);
1220
  } else {
1221
3
    CHECK_EQ(argc, 3);
1222
6
    FSReqWrapSync req_wrap_sync;
1223

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

5
    FS_SYNC_TRACE_END(fdatasync);
1226
  }
1227
7
}
1228
1229
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1230
23
  Environment* env = Environment::GetCurrent(args);
1231
1232
23
  const int argc = args.Length();
1233
23
  CHECK_GE(argc, 2);
1234
1235
46
  CHECK(args[0]->IsInt32());
1236
69
  const int fd = args[0].As<Int32>()->Value();
1237
1238
23
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1239
23
  if (req_wrap_async != nullptr) {
1240
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1241
6
              uv_fs_fsync, fd);
1242
  } else {
1243
17
    CHECK_EQ(argc, 3);
1244
34
    FSReqWrapSync req_wrap_sync;
1245

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

19
    FS_SYNC_TRACE_END(fsync);
1248
  }
1249
23
}
1250
1251
1324
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1252
1324
  Environment* env = Environment::GetCurrent(args);
1253
1254
1324
  const int argc = args.Length();
1255
1324
  CHECK_GE(argc, 2);
1256
1257
2648
  BufferValue path(env->isolate(), args[0]);
1258
1324
  CHECK_NOT_NULL(*path);
1259
1260
1324
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1261
1324
  if (req_wrap_async != nullptr) {
1262
550
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1263
550
              uv_fs_unlink, *path);
1264
  } else {
1265
774
    CHECK_EQ(argc, 3);
1266
1548
    FSReqWrapSync req_wrap_sync;
1267

834
    FS_SYNC_TRACE_BEGIN(unlink);
1268
1548
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1269

834
    FS_SYNC_TRACE_END(unlink);
1270
  }
1271
1324
}
1272
1273
1104
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1274
1104
  Environment* env = Environment::GetCurrent(args);
1275
1276
1104
  const int argc = args.Length();
1277
1104
  CHECK_GE(argc, 2);
1278
1279
2208
  BufferValue path(env->isolate(), args[0]);
1280
1104
  CHECK_NOT_NULL(*path);
1281
1282
1104
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1283
1104
  if (req_wrap_async != nullptr) {
1284
121
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1285
121
              uv_fs_rmdir, *path);
1286
  } else {  // rmdir(path, undefined, ctx)
1287
983
    CHECK_EQ(argc, 3);
1288
1966
    FSReqWrapSync req_wrap_sync;
1289

989
    FS_SYNC_TRACE_BEGIN(rmdir);
1290
983
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1291
983
             uv_fs_rmdir, *path);
1292

989
    FS_SYNC_TRACE_END(rmdir);
1293
  }
1294
1104
}
1295
1296
4672
int MKDirpSync(uv_loop_t* loop,
1297
               uv_fs_t* req,
1298
               const std::string& path,
1299
               int mode,
1300
               uv_fs_cb cb) {
1301
4672
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1302
1303
  // on the first iteration of algorithm, stash state information.
1304
4672
  if (req_wrap->continuation_data() == nullptr) {
1305
    req_wrap->set_continuation_data(
1306
4672
        std::make_unique<FSContinuationData>(req, mode, cb));
1307
4672
    req_wrap->continuation_data()->PushPath(std::move(path));
1308
  }
1309
1310
13958
  while (req_wrap->continuation_data()->paths().size() > 0) {
1311
9411
    std::string next_path = req_wrap->continuation_data()->PopPath();
1312
4768
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1313
    while (true) {
1314

4769
      switch (err) {
1315
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1316
        // ~FSReqWrapSync():
1317
        case 0:
1318
168
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1319
168
          if (req_wrap->continuation_data()->paths().size() == 0) {
1320
121
            return 0;
1321
          }
1322
47
          break;
1323
        case UV_EACCES:
1324
        case UV_ENOTDIR:
1325
        case UV_EPERM: {
1326
2
          return err;
1327
        }
1328
        case UV_ENOENT: {
1329
          std::string dirname = next_path.substr(0,
1330
49
                                        next_path.find_last_of(kPathSeparator));
1331
49
          if (dirname != next_path) {
1332
48
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1333
48
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1334
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1335
1
            err = UV_EEXIST;
1336
1
            continue;
1337
          }
1338
48
          break;
1339
        }
1340
        default:
1341
4550
          uv_fs_req_cleanup(req);
1342
4550
          int orig_err = err;
1343
4550
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1344

4550
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1345
1
            uv_fs_req_cleanup(req);
1346

2
            if (orig_err == UV_EEXIST &&
1347
1
              req_wrap->continuation_data()->paths().size() > 0) {
1348
              return UV_ENOTDIR;
1349
            }
1350
1
            return UV_EEXIST;
1351
          }
1352
4549
          if (err < 0) return err;
1353
4548
          break;
1354
      }
1355
4643
      break;
1356
1
    }
1357
4643
    uv_fs_req_cleanup(req);
1358
  }
1359
1360
4547
  return 0;
1361
}
1362
1363
24
int MKDirpAsync(uv_loop_t* loop,
1364
                uv_fs_t* req,
1365
                const char* path,
1366
                int mode,
1367
                uv_fs_cb cb) {
1368
24
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1369
  // on the first iteration of algorithm, stash state information.
1370
24
  if (req_wrap->continuation_data() == nullptr) {
1371
    req_wrap->set_continuation_data(
1372
14
        std::make_unique<FSContinuationData>(req, mode, cb));
1373
14
    req_wrap->continuation_data()->PushPath(std::move(path));
1374
  }
1375
1376
  // on each iteration of algorithm, mkdir directory on top of stack.
1377
48
  std::string next_path = req_wrap->continuation_data()->PopPath();
1378
24
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1379
72
                        uv_fs_callback_t{[](uv_fs_t* req) {
1380
24
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1381
24
    Environment* env = req_wrap->env();
1382
24
    uv_loop_t* loop = env->event_loop();
1383
48
    std::string path = req->path;
1384
24
    int err = req->result;
1385
1386
    while (true) {
1387

25
      switch (err) {
1388
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1389
        // FSReqAfterScope::~FSReqAfterScope()
1390
        case 0: {
1391
12
          if (req_wrap->continuation_data()->paths().size() == 0) {
1392
7
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1393
7
            req_wrap->continuation_data()->Done(0);
1394
          } else {
1395
5
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1396
5
            uv_fs_req_cleanup(req);
1397
5
            MKDirpAsync(loop, req, path.c_str(),
1398
5
                        req_wrap->continuation_data()->mode(), nullptr);
1399
          }
1400
12
          break;
1401
        }
1402
        case UV_EACCES:
1403
        case UV_ENOTDIR:
1404
        case UV_EPERM: {
1405
3
          req_wrap->continuation_data()->Done(err);
1406
3
          break;
1407
        }
1408
        case UV_ENOENT: {
1409
          std::string dirname = path.substr(0,
1410
6
                                            path.find_last_of(kPathSeparator));
1411
6
          if (dirname != path) {
1412
5
            req_wrap->continuation_data()->PushPath(std::move(path));
1413
5
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1414
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1415
1
            err = UV_EEXIST;
1416
1
            continue;
1417
          }
1418
5
          uv_fs_req_cleanup(req);
1419
5
          MKDirpAsync(loop, req, path.c_str(),
1420
5
                      req_wrap->continuation_data()->mode(), nullptr);
1421
5
          break;
1422
        }
1423
        default:
1424
4
          uv_fs_req_cleanup(req);
1425
          // Stash err for use in the callback.
1426
4
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1427
4
          int err = uv_fs_stat(loop, req, path.c_str(),
1428
12
                               uv_fs_callback_t{[](uv_fs_t* req) {
1429
4
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1430
4
            int err = req->result;
1431

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1432
4
                  req_wrap->continuation_data()->paths().size() > 0) {
1433
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1434
                Environment* env = req_wrap->env();
1435
                uv_loop_t* loop = env->event_loop();
1436
                std::string path = req->path;
1437
                uv_fs_req_cleanup(req);
1438
                MKDirpAsync(loop, req, path.c_str(),
1439
                            req_wrap->continuation_data()->mode(), nullptr);
1440
                return;
1441
              }
1442
              err = UV_ENOTDIR;
1443
            }
1444
            // verify that the path pointed to is actually a directory.
1445

4
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1446
4
            req_wrap->continuation_data()->Done(err);
1447
12
          }});
1448
4
          if (err < 0) req_wrap->continuation_data()->Done(err);
1449
4
          break;
1450
      }
1451
24
      break;
1452
1
    }
1453
96
  }});
1454
1455
48
  return err;
1456
}
1457
1458
109
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1459
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1460
109
  env->PrintSyncTrace();
1461
218
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1462
109
                       nullptr);
1463
109
  if (err < 0) {
1464
4
    v8::Local<v8::Context> context = env->context();
1465
8
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1466
4
    v8::Isolate* isolate = env->isolate();
1467
8
    ctx_obj->Set(context,
1468
                 env->errno_string(),
1469
16
                 v8::Integer::New(isolate, err)).Check();
1470
8
    ctx_obj->Set(context,
1471
                 env->syscall_string(),
1472
16
                 OneByteString(isolate, "mkdir")).Check();
1473
  }
1474
109
  return err;
1475
}
1476
1477
1627
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1478
1627
  Environment* env = Environment::GetCurrent(args);
1479
1480
1627
  const int argc = args.Length();
1481
1627
  CHECK_GE(argc, 4);
1482
1483
3254
  BufferValue path(env->isolate(), args[0]);
1484
1627
  CHECK_NOT_NULL(*path);
1485
1486
3254
  CHECK(args[1]->IsInt32());
1487
4881
  const int mode = args[1].As<Int32>()->Value();
1488
1489
3254
  CHECK(args[2]->IsBoolean());
1490
3254
  bool mkdirp = args[2]->IsTrue();
1491
1492
1627
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1493
1627
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1494

852
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1495
              mkdirp ? AfterMkdirp : AfterNoArgs,
1496
852
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1497
  } else {  // mkdir(path, mode, undefined, ctx)
1498
775
    CHECK_EQ(argc, 5);
1499
1550
    FSReqWrapSync req_wrap_sync;
1500

779
    FS_SYNC_TRACE_BEGIN(mkdir);
1501
775
    if (mkdirp) {
1502
109
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1503

214
      if (err == 0 &&
1504
105
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1505
        Local<Value> error;
1506
206
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1507
103
        FromNamespacedPath(&first_path);
1508
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1509
                                                     first_path.c_str(),
1510
103
                                                     UTF8, &error);
1511
103
        if (path.IsEmpty()) {
1512
          Local<Object> ctx = args[4].As<Object>();
1513
          ctx->Set(env->context(), env->error_string(), error).Check();
1514
          return;
1515
        }
1516
206
        args.GetReturnValue().Set(path.ToLocalChecked());
1517
      }
1518
    } else {
1519
666
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1520
666
               uv_fs_mkdir, *path, mode);
1521
    }
1522


779
    FS_SYNC_TRACE_END(mkdir);
1523
  }
1524
}
1525
1526
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1527
42
  Environment* env = Environment::GetCurrent(args);
1528
42
  Isolate* isolate = env->isolate();
1529
1530
42
  const int argc = args.Length();
1531
42
  CHECK_GE(argc, 3);
1532
1533
82
  BufferValue path(isolate, args[0]);
1534
42
  CHECK_NOT_NULL(*path);
1535
1536
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1537
1538
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1539
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1540
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1541
22
              uv_fs_realpath, *path);
1542
  } else {  // realpath(path, encoding, undefined, ctx)
1543
20
    CHECK_EQ(argc, 4);
1544
38
    FSReqWrapSync req_wrap_sync;
1545

22
    FS_SYNC_TRACE_BEGIN(realpath);
1546
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1547
20
                       uv_fs_realpath, *path);
1548

22
    FS_SYNC_TRACE_END(realpath);
1549
20
    if (err < 0) {
1550
2
      return;  // syscall failed, no need to continue, error info is in ctx
1551
    }
1552
1553
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1554
1555
    Local<Value> error;
1556
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1557
                                               link_path,
1558
                                               encoding,
1559
18
                                               &error);
1560
18
    if (rc.IsEmpty()) {
1561
      Local<Object> ctx = args[3].As<Object>();
1562
      ctx->Set(env->context(), env->error_string(), error).Check();
1563
      return;
1564
    }
1565
1566
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1567
  }
1568
}
1569
1570
13905
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1571
13905
  Environment* env = Environment::GetCurrent(args);
1572
13905
  Isolate* isolate = env->isolate();
1573
1574
13905
  const int argc = args.Length();
1575
13905
  CHECK_GE(argc, 3);
1576
1577
27713
  BufferValue path(isolate, args[0]);
1578
13905
  CHECK_NOT_NULL(*path);
1579
1580
13905
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1581
1582
27810
  bool with_types = args[2]->IsTrue();
1583
1584
13905
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1585
13905
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1586
136
    if (with_types) {
1587
7
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1588
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1589
    } else {
1590
129
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1591
129
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1592
    }
1593
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1594
13769
    CHECK_EQ(argc, 5);
1595
27441
    FSReqWrapSync req_wrap_sync;
1596

13771
    FS_SYNC_TRACE_BEGIN(readdir);
1597
13769
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1598
13769
                       uv_fs_scandir, *path, 0 /*flags*/);
1599

13771
    FS_SYNC_TRACE_END(readdir);
1600
13769
    if (err < 0) {
1601
97
      return;  // syscall failed, no need to continue, error info is in ctx
1602
    }
1603
1604
13672
    CHECK_GE(req_wrap_sync.req.result, 0);
1605
    int r;
1606
27344
    std::vector<Local<Value>> name_v;
1607
27344
    std::vector<Local<Value>> type_v;
1608
1609
700465
    for (int i = 0; ; i++) {
1610
      uv_dirent_t ent;
1611
1612
700465
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1613
700465
      if (r == UV_EOF)
1614
13672
        break;
1615
686793
      if (r != 0) {
1616
        Local<Object> ctx = args[4].As<Object>();
1617
        ctx->Set(env->context(), env->errno_string(),
1618
                 Integer::New(isolate, r)).Check();
1619
        ctx->Set(env->context(), env->syscall_string(),
1620
                 OneByteString(isolate, "readdir")).Check();
1621
        return;
1622
      }
1623
1624
      Local<Value> error;
1625
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1626
                                                       ent.name,
1627
                                                       encoding,
1628
686793
                                                       &error);
1629
1630
686793
      if (filename.IsEmpty()) {
1631
        Local<Object> ctx = args[4].As<Object>();
1632
        ctx->Set(env->context(), env->error_string(), error).Check();
1633
        return;
1634
      }
1635
1636
686793
      name_v.push_back(filename.ToLocalChecked());
1637
1638
686793
      if (with_types) {
1639
20936
        type_v.emplace_back(Integer::New(isolate, ent.type));
1640
      }
1641
686793
    }
1642
1643
1644
13672
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1645
13672
    if (with_types) {
1646
      Local<Value> result[] = {
1647
        names,
1648
        Array::New(isolate, type_v.data(), type_v.size())
1649
99
      };
1650
99
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1651
    } else {
1652
27278
      args.GetReturnValue().Set(names);
1653
    }
1654
  }
1655
}
1656
1657
41363
static void Open(const FunctionCallbackInfo<Value>& args) {
1658
41363
  Environment* env = Environment::GetCurrent(args);
1659
1660
41363
  const int argc = args.Length();
1661
41363
  CHECK_GE(argc, 3);
1662
1663
82726
  BufferValue path(env->isolate(), args[0]);
1664
41363
  CHECK_NOT_NULL(*path);
1665
1666
82726
  CHECK(args[1]->IsInt32());
1667
124089
  const int flags = args[1].As<Int32>()->Value();
1668
1669
82726
  CHECK(args[2]->IsInt32());
1670
124089
  const int mode = args[2].As<Int32>()->Value();
1671
1672
41363
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1673
41363
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1674
5331
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1675
5331
              uv_fs_open, *path, flags, mode);
1676
  } else {  // open(path, flags, mode, undefined, ctx)
1677
36032
    CHECK_EQ(argc, 5);
1678
72064
    FSReqWrapSync req_wrap_sync;
1679

36104
    FS_SYNC_TRACE_BEGIN(open);
1680
36032
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1681
36032
                          uv_fs_open, *path, flags, mode);
1682

36104
    FS_SYNC_TRACE_END(open);
1683
72064
    args.GetReturnValue().Set(result);
1684
  }
1685
41363
}
1686
1687
305
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1688
305
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1689
305
  Environment* env = binding_data->env();
1690
305
  Isolate* isolate = env->isolate();
1691
1692
305
  const int argc = args.Length();
1693
305
  CHECK_GE(argc, 3);
1694
1695
610
  BufferValue path(isolate, args[0]);
1696
305
  CHECK_NOT_NULL(*path);
1697
1698
610
  CHECK(args[1]->IsInt32());
1699
915
  const int flags = args[1].As<Int32>()->Value();
1700
1701
610
  CHECK(args[2]->IsInt32());
1702
915
  const int mode = args[2].As<Int32>()->Value();
1703
1704
305
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1705
305
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1706
304
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1707
304
              uv_fs_open, *path, flags, mode);
1708
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1709
1
    CHECK_EQ(argc, 5);
1710
2
    FSReqWrapSync req_wrap_sync;
1711

1
    FS_SYNC_TRACE_BEGIN(open);
1712
1
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1713
1
                          uv_fs_open, *path, flags, mode);
1714

1
    FS_SYNC_TRACE_END(open);
1715
1
    if (result < 0) {
1716
      return;  // syscall failed, no need to continue, error info is in ctx
1717
    }
1718
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1719
1
    if (fd == nullptr) return;
1720
3
    args.GetReturnValue().Set(fd->object());
1721
  }
1722
}
1723
1724
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1725
33
  Environment* env = Environment::GetCurrent(args);
1726
33
  Isolate* isolate = env->isolate();
1727
1728
33
  const int argc = args.Length();
1729
33
  CHECK_GE(argc, 3);
1730
1731
66
  BufferValue src(isolate, args[0]);
1732
33
  CHECK_NOT_NULL(*src);
1733
1734
66
  BufferValue dest(isolate, args[1]);
1735
33
  CHECK_NOT_NULL(*dest);
1736
1737
66
  CHECK(args[2]->IsInt32());
1738
99
  const int flags = args[2].As<Int32>()->Value();
1739
1740
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1741
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1742
14
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1743
14
                  *dest, dest.length(), UTF8, AfterNoArgs,
1744
14
                  uv_fs_copyfile, *src, *dest, flags);
1745
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1746
19
    CHECK_EQ(argc, 5);
1747
38
    FSReqWrapSync req_wrap_sync;
1748

21
    FS_SYNC_TRACE_BEGIN(copyfile);
1749
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1750
19
             uv_fs_copyfile, *src, *dest, flags);
1751

21
    FS_SYNC_TRACE_END(copyfile);
1752
  }
1753
33
}
1754
1755
1756
// Wrapper for write(2).
1757
//
1758
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1759
// 0 fd        integer. file descriptor
1760
// 1 buffer    the data to write
1761
// 2 offset    where in the buffer to start from
1762
// 3 length    how much to write
1763
// 4 position  if integer, position to write at in the file.
1764
//             if null, write from the current position
1765
54201
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1766
54201
  Environment* env = Environment::GetCurrent(args);
1767
1768
54201
  const int argc = args.Length();
1769
54201
  CHECK_GE(argc, 4);
1770
1771
108402
  CHECK(args[0]->IsInt32());
1772
162603
  const int fd = args[0].As<Int32>()->Value();
1773
1774
54201
  CHECK(Buffer::HasInstance(args[1]));
1775
108402
  Local<Object> buffer_obj = args[1].As<Object>();
1776
54201
  char* buffer_data = Buffer::Data(buffer_obj);
1777
54201
  size_t buffer_length = Buffer::Length(buffer_obj);
1778
1779
54201
  CHECK(IsSafeJsInt(args[2]));
1780
162603
  const int64_t off_64 = args[2].As<Integer>()->Value();
1781
54201
  CHECK_GE(off_64, 0);
1782
54201
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1783
54201
  const size_t off = static_cast<size_t>(off_64);
1784
1785
108402
  CHECK(args[3]->IsInt32());
1786
162603
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1787
54201
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1788
54201
  CHECK_LE(len, buffer_length);
1789
54201
  CHECK_GE(off + len, off);
1790
1791
54201
  const int64_t pos = GetOffset(args[4]);
1792
1793
54201
  char* buf = buffer_data + off;
1794
54201
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1795
1796
54201
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1797
54201
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1798
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1799
14399
              uv_fs_write, fd, &uvbuf, 1, pos);
1800
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1801
39802
    CHECK_EQ(argc, 7);
1802
79604
    FSReqWrapSync req_wrap_sync;
1803

39852
    FS_SYNC_TRACE_BEGIN(write);
1804
39802
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1805
39802
                                uv_fs_write, fd, &uvbuf, 1, pos);
1806

39852
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1807
119406
    args.GetReturnValue().Set(bytesWritten);
1808
  }
1809
54201
}
1810
1811
1812
// Wrapper for writev(2).
1813
//
1814
// bytesWritten = writev(fd, chunks, position, callback)
1815
// 0 fd        integer. file descriptor
1816
// 1 chunks    array of buffers to write
1817
// 2 position  if integer, position to write at in the file.
1818
//             if null, write from the current position
1819
22
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1820
22
  Environment* env = Environment::GetCurrent(args);
1821
1822
22
  const int argc = args.Length();
1823
22
  CHECK_GE(argc, 3);
1824
1825
44
  CHECK(args[0]->IsInt32());
1826
66
  const int fd = args[0].As<Int32>()->Value();
1827
1828
44
  CHECK(args[1]->IsArray());
1829
44
  Local<Array> chunks = args[1].As<Array>();
1830
1831
22
  int64_t pos = GetOffset(args[2]);
1832
1833
44
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1834
1835
83
  for (uint32_t i = 0; i < iovs.length(); i++) {
1836
183
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1837
61
    CHECK(Buffer::HasInstance(chunk));
1838
61
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1839
  }
1840
1841
22
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1842
22
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1843
18
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1844
18
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1845
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1846
4
    CHECK_EQ(argc, 5);
1847
8
    FSReqWrapSync req_wrap_sync;
1848

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1852
12
    args.GetReturnValue().Set(bytesWritten);
1853
  }
1854
22
}
1855
1856
1857
// Wrapper for write(2).
1858
//
1859
// bytesWritten = write(fd, string, position, enc, callback)
1860
// 0 fd        integer. file descriptor
1861
// 1 string    non-buffer values are converted to strings
1862
// 2 position  if integer, position to write at in the file.
1863
//             if null, write from the current position
1864
// 3 enc       encoding of string
1865
1477
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1866
1477
  Environment* env = Environment::GetCurrent(args);
1867
1477
  Isolate* isolate = env->isolate();
1868
1869
1477
  const int argc = args.Length();
1870
1477
  CHECK_GE(argc, 4);
1871
1872
2954
  CHECK(args[0]->IsInt32());
1873
4431
  const int fd = args[0].As<Int32>()->Value();
1874
1875
1477
  const int64_t pos = GetOffset(args[2]);
1876
1877
1477
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1878
1879
1477
  Local<Value> value = args[1];
1880
1477
  char* buf = nullptr;
1881
  size_t len;
1882
1883
1477
  FSReqBase* req_wrap_async = GetReqWrap(args, 4);
1884
1477
  const bool is_async = req_wrap_async != nullptr;
1885
1886
  // Avoid copying the string when it is externalized but only when:
1887
  // 1. The target encoding is compatible with the string's encoding, and
1888
  // 2. The write is synchronous, otherwise the string might get neutered
1889
  //    while the request is in flight, and
1890
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1891
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1892
  // The const_casts are conceptually sound: memory is read but not written.
1893

4217
  if (!is_async && value->IsString()) {
1894
1370
    auto string = value.As<String>();
1895


1371
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1896
1
      auto ext = string->GetExternalOneByteStringResource();
1897
1
      buf = const_cast<char*>(ext->data());
1898
1
      len = ext->length();
1899


1370
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1900
2
      auto ext = string->GetExternalStringResource();
1901
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1902
1
      len = ext->length() * sizeof(*ext->data());
1903
    }
1904
  }
1905
1906
1477
  if (is_async) {  // write(fd, string, pos, enc, req)
1907
107
    CHECK_NOT_NULL(req_wrap_async);
1908
214
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1909
    FSReqBase::FSReqBuffer& stack_buffer =
1910
107
        req_wrap_async->Init("write", len, enc);
1911
    // StorageSize may return too large a char, so correct the actual length
1912
    // by the write size
1913
107
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1914
107
    stack_buffer.SetLengthAndZeroTerminate(len);
1915
107
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1916
107
    int err = req_wrap_async->Dispatch(uv_fs_write,
1917
                                       fd,
1918
                                       &uvbuf,
1919
                                       1,
1920
                                       pos,
1921
107
                                       AfterInteger);
1922
107
    if (err < 0) {
1923
      uv_fs_t* uv_req = req_wrap_async->req();
1924
      uv_req->result = err;
1925
      uv_req->path = nullptr;
1926
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1927
                             // an error
1928
    } else {
1929
107
      req_wrap_async->SetReturnValue(args);
1930
    }
1931
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1932
1370
    CHECK_EQ(argc, 6);
1933
2740
    FSReqWrapSync req_wrap_sync;
1934
2740
    FSReqBase::FSReqBuffer stack_buffer;
1935
1370
    if (buf == nullptr) {
1936
2736
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1937
        return;
1938
1368
      stack_buffer.AllocateSufficientStorage(len + 1);
1939
      // StorageSize may return too large a char, so correct the actual length
1940
      // by the write size
1941
1368
      len = StringBytes::Write(isolate, *stack_buffer,
1942
                               len, args[1], enc);
1943
1368
      stack_buffer.SetLengthAndZeroTerminate(len);
1944
1368
      buf = *stack_buffer;
1945
    }
1946
1370
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1947

1370
    FS_SYNC_TRACE_BEGIN(write);
1948
1370
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1949
1370
                                uv_fs_write, fd, &uvbuf, 1, pos);
1950

1370
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1951
4110
    args.GetReturnValue().Set(bytesWritten);
1952
  }
1953
}
1954
1955
1956
/*
1957
 * Wrapper for read(2).
1958
 *
1959
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1960
 *
1961
 * 0 fd        int32. file descriptor
1962
 * 1 buffer    instance of Buffer
1963
 * 2 offset    int64. offset to start reading into inside buffer
1964
 * 3 length    int32. length to read
1965
 * 4 position  int64. file position - -1 for current position
1966
 */
1967
48701
static void Read(const FunctionCallbackInfo<Value>& args) {
1968
48701
  Environment* env = Environment::GetCurrent(args);
1969
1970
48701
  const int argc = args.Length();
1971
48701
  CHECK_GE(argc, 5);
1972
1973
97402
  CHECK(args[0]->IsInt32());
1974
146103
  const int fd = args[0].As<Int32>()->Value();
1975
1976
48701
  CHECK(Buffer::HasInstance(args[1]));
1977
97402
  Local<Object> buffer_obj = args[1].As<Object>();
1978
48701
  char* buffer_data = Buffer::Data(buffer_obj);
1979
48701
  size_t buffer_length = Buffer::Length(buffer_obj);
1980
1981
48701
  CHECK(IsSafeJsInt(args[2]));
1982
146103
  const int64_t off_64 = args[2].As<Integer>()->Value();
1983
48701
  CHECK_GE(off_64, 0);
1984
48701
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
1985
48701
  const size_t off = static_cast<size_t>(off_64);
1986
1987
97402
  CHECK(args[3]->IsInt32());
1988
146103
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1989
48701
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1990
1991
48701
  CHECK(IsSafeJsInt(args[4]));
1992
146103
  const int64_t pos = args[4].As<Integer>()->Value();
1993
1994
48701
  char* buf = buffer_data + off;
1995
48701
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1996
1997
48701
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1998
48701
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1999
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2000
14068
              uv_fs_read, fd, &uvbuf, 1, pos);
2001
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2002
34633
    CHECK_EQ(argc, 7);
2003
69266
    FSReqWrapSync req_wrap_sync;
2004

34643
    FS_SYNC_TRACE_BEGIN(read);
2005
34633
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2006
34633
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2007

34643
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2008
103899
    args.GetReturnValue().Set(bytesRead);
2009
  }
2010
48701
}
2011
2012
2013
// Wrapper for readv(2).
2014
//
2015
// bytesRead = fs.readv(fd, buffers[, position], callback)
2016
// 0 fd        integer. file descriptor
2017
// 1 buffers   array of buffers to read
2018
// 2 position  if integer, position to read at in the file.
2019
//             if null, read from the current position
2020
10
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2021
10
  Environment* env = Environment::GetCurrent(args);
2022
2023
10
  const int argc = args.Length();
2024
10
  CHECK_GE(argc, 3);
2025
2026
20
  CHECK(args[0]->IsInt32());
2027
30
  const int fd = args[0].As<Int32>()->Value();
2028
2029
20
  CHECK(args[1]->IsArray());
2030
20
  Local<Array> buffers = args[1].As<Array>();
2031
2032
10
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2033
2034
20
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2035
2036
  // Init uv buffers from ArrayBufferViews
2037
26
  for (uint32_t i = 0; i < iovs.length(); i++) {
2038
48
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2039
16
    CHECK(Buffer::HasInstance(buffer));
2040
16
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2041
  }
2042
2043
10
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2044
10
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2045
6
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2046
6
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2047
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2048
4
    CHECK_EQ(argc, 5);
2049
8
    FSReqWrapSync req_wrap_sync;
2050

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

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2054
12
    args.GetReturnValue().Set(bytesRead);
2055
  }
2056
10
}
2057
2058
2059
/* fs.chmod(path, mode);
2060
 * Wrapper for chmod(1) / EIO_CHMOD
2061
 */
2062
165
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2063
165
  Environment* env = Environment::GetCurrent(args);
2064
2065
165
  const int argc = args.Length();
2066
165
  CHECK_GE(argc, 2);
2067
2068
330
  BufferValue path(env->isolate(), args[0]);
2069
165
  CHECK_NOT_NULL(*path);
2070
2071
330
  CHECK(args[1]->IsInt32());
2072
495
  int mode = args[1].As<Int32>()->Value();
2073
2074
165
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2075
165
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2076
149
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2077
149
              uv_fs_chmod, *path, mode);
2078
  } else {  // chmod(path, mode, undefined, ctx)
2079
16
    CHECK_EQ(argc, 4);
2080
32
    FSReqWrapSync req_wrap_sync;
2081

18
    FS_SYNC_TRACE_BEGIN(chmod);
2082
16
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2083
16
             uv_fs_chmod, *path, mode);
2084

18
    FS_SYNC_TRACE_END(chmod);
2085
  }
2086
165
}
2087
2088
2089
/* fs.fchmod(fd, mode);
2090
 * Wrapper for fchmod(1) / EIO_FCHMOD
2091
 */
2092
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2093
12
  Environment* env = Environment::GetCurrent(args);
2094
2095
12
  const int argc = args.Length();
2096
12
  CHECK_GE(argc, 2);
2097
2098
24
  CHECK(args[0]->IsInt32());
2099
36
  const int fd = args[0].As<Int32>()->Value();
2100
2101
24
  CHECK(args[1]->IsInt32());
2102
36
  const int mode = args[1].As<Int32>()->Value();
2103
2104
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2105
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2106
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2107
7
              uv_fs_fchmod, fd, mode);
2108
  } else {  // fchmod(fd, mode, undefined, ctx)
2109
5
    CHECK_EQ(argc, 4);
2110
10
    FSReqWrapSync req_wrap_sync;
2111

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2112
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2113
5
             uv_fs_fchmod, fd, mode);
2114

7
    FS_SYNC_TRACE_END(fchmod);
2115
  }
2116
12
}
2117
2118
2119
/* fs.chown(path, uid, gid);
2120
 * Wrapper for chown(1) / EIO_CHOWN
2121
 */
2122
73
static void Chown(const FunctionCallbackInfo<Value>& args) {
2123
73
  Environment* env = Environment::GetCurrent(args);
2124
2125
73
  const int argc = args.Length();
2126
73
  CHECK_GE(argc, 3);
2127
2128
146
  BufferValue path(env->isolate(), args[0]);
2129
73
  CHECK_NOT_NULL(*path);
2130
2131
146
  CHECK(args[1]->IsUint32());
2132
219
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2133
2134
146
  CHECK(args[2]->IsUint32());
2135
219
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2136
2137
73
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2138
73
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2139
70
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2140
70
              uv_fs_chown, *path, uid, gid);
2141
  } else {  // chown(path, uid, gid, undefined, ctx)
2142
3
    CHECK_EQ(argc, 5);
2143
6
    FSReqWrapSync req_wrap_sync;
2144

5
    FS_SYNC_TRACE_BEGIN(chown);
2145
3
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2146
3
             uv_fs_chown, *path, uid, gid);
2147

5
    FS_SYNC_TRACE_END(chown);
2148
  }
2149
73
}
2150
2151
2152
/* fs.fchown(fd, uid, gid);
2153
 * Wrapper for fchown(1) / EIO_FCHOWN
2154
 */
2155
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2156
4
  Environment* env = Environment::GetCurrent(args);
2157
2158
4
  const int argc = args.Length();
2159
4
  CHECK_GE(argc, 3);
2160
2161
8
  CHECK(args[0]->IsInt32());
2162
12
  const int fd = args[0].As<Int32>()->Value();
2163
2164
8
  CHECK(args[1]->IsUint32());
2165
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2166
2167
8
  CHECK(args[2]->IsUint32());
2168
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2169
2170
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2171
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2172
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2173
2
              uv_fs_fchown, fd, uid, gid);
2174
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2175
2
    CHECK_EQ(argc, 5);
2176
4
    FSReqWrapSync req_wrap_sync;
2177

4
    FS_SYNC_TRACE_BEGIN(fchown);
2178
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2179
2
             uv_fs_fchown, fd, uid, gid);
2180

4
    FS_SYNC_TRACE_END(fchown);
2181
  }
2182
4
}
2183
2184
2185
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2186
9
  Environment* env = Environment::GetCurrent(args);
2187
2188
9
  const int argc = args.Length();
2189
9
  CHECK_GE(argc, 3);
2190
2191
18
  BufferValue path(env->isolate(), args[0]);
2192
9
  CHECK_NOT_NULL(*path);
2193
2194
18
  CHECK(args[1]->IsUint32());
2195
27
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2196
2197
18
  CHECK(args[2]->IsUint32());
2198
27
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2199
2200
9
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2201
9
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2202
7
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2203
7
              uv_fs_lchown, *path, uid, gid);
2204
  } else {  // lchown(path, uid, gid, undefined, ctx)
2205
2
    CHECK_EQ(argc, 5);
2206
4
    FSReqWrapSync req_wrap_sync;
2207

4
    FS_SYNC_TRACE_BEGIN(lchown);
2208
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2209
2
             uv_fs_lchown, *path, uid, gid);
2210

4
    FS_SYNC_TRACE_END(lchown);
2211
  }
2212
9
}
2213
2214
2215
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2216
29
  Environment* env = Environment::GetCurrent(args);
2217
2218
29
  const int argc = args.Length();
2219
29
  CHECK_GE(argc, 3);
2220
2221
58
  BufferValue path(env->isolate(), args[0]);
2222
29
  CHECK_NOT_NULL(*path);
2223
2224
58
  CHECK(args[1]->IsNumber());
2225
87
  const double atime = args[1].As<Number>()->Value();
2226
2227
58
  CHECK(args[2]->IsNumber());
2228
87
  const double mtime = args[2].As<Number>()->Value();
2229
2230
29
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2231
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2232
14
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2233
14
              uv_fs_utime, *path, atime, mtime);
2234
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2235
15
    CHECK_EQ(argc, 5);
2236
30
    FSReqWrapSync req_wrap_sync;
2237

17
    FS_SYNC_TRACE_BEGIN(utimes);
2238
15
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2239
15
             uv_fs_utime, *path, atime, mtime);
2240

17
    FS_SYNC_TRACE_END(utimes);
2241
  }
2242
29
}
2243
2244
1271
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2245
1271
  Environment* env = Environment::GetCurrent(args);
2246
2247
1271
  const int argc = args.Length();
2248
1271
  CHECK_GE(argc, 3);
2249
2250
2542
  CHECK(args[0]->IsInt32());
2251
3813
  const int fd = args[0].As<Int32>()->Value();
2252
2253
2542
  CHECK(args[1]->IsNumber());
2254
3813
  const double atime = args[1].As<Number>()->Value();
2255
2256
2542
  CHECK(args[2]->IsNumber());
2257
3813
  const double mtime = args[2].As<Number>()->Value();
2258
2259
1271
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2260
1271
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2261
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2262
1263
              uv_fs_futime, fd, atime, mtime);
2263
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2264
8
    CHECK_EQ(argc, 5);
2265
16
    FSReqWrapSync req_wrap_sync;
2266

10
    FS_SYNC_TRACE_BEGIN(futimes);
2267
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2268
8
             uv_fs_futime, fd, atime, mtime);
2269

10
    FS_SYNC_TRACE_END(futimes);
2270
  }
2271
1271
}
2272
2273
14
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2274
14
  Environment* env = Environment::GetCurrent(args);
2275
14
  Isolate* isolate = env->isolate();
2276
2277
14
  const int argc = args.Length();
2278
14
  CHECK_GE(argc, 2);
2279
2280
28
  BufferValue tmpl(isolate, args[0]);
2281
14
  CHECK_NOT_NULL(*tmpl);
2282
2283
14
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2284
2285
14
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2286
14
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2287
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2288
6
              uv_fs_mkdtemp, *tmpl);
2289
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2290
8
    CHECK_EQ(argc, 4);
2291
16
    FSReqWrapSync req_wrap_sync;
2292

10
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2293
8
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2294
8
             uv_fs_mkdtemp, *tmpl);
2295

10
    FS_SYNC_TRACE_END(mkdtemp);
2296
8
    const char* path = req_wrap_sync.req.path;
2297
2298
    Local<Value> error;
2299
    MaybeLocal<Value> rc =
2300
8
        StringBytes::Encode(isolate, path, encoding, &error);
2301
8
    if (rc.IsEmpty()) {
2302
      Local<Object> ctx = args[3].As<Object>();
2303
      ctx->Set(env->context(), env->error_string(), error).Check();
2304
      return;
2305
    }
2306
16
    args.GetReturnValue().Set(rc.ToLocalChecked());
2307
  }
2308
}
2309
2310
19
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2311
19
  tracker->TrackField("stats_field_array", stats_field_array);
2312
19
  tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2313
19
  tracker->TrackField("file_handle_read_wrap_freelist",
2314
19
                      file_handle_read_wrap_freelist);
2315
19
}
2316
2317
// TODO(addaleax): Remove once we're on C++17.
2318
constexpr FastStringKey BindingData::binding_data_name;
2319
2320
4568
void Initialize(Local<Object> target,
2321
                Local<Value> unused,
2322
                Local<Context> context,
2323
                void* priv) {
2324
4568
  Environment* env = Environment::GetCurrent(context);
2325
4568
  Isolate* isolate = env->isolate();
2326
  BindingData* const binding_data =
2327
4568
      env->AddBindingData<BindingData>(context, target);
2328
4568
  if (binding_data == nullptr) return;
2329
2330
4568
  env->SetMethod(target, "access", Access);
2331
4568
  env->SetMethod(target, "close", Close);
2332
4568
  env->SetMethod(target, "open", Open);
2333
4568
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2334
4568
  env->SetMethod(target, "read", Read);
2335
4568
  env->SetMethod(target, "readBuffers", ReadBuffers);
2336
4568
  env->SetMethod(target, "fdatasync", Fdatasync);
2337
4568
  env->SetMethod(target, "fsync", Fsync);
2338
4568
  env->SetMethod(target, "rename", Rename);
2339
4568
  env->SetMethod(target, "ftruncate", FTruncate);
2340
4568
  env->SetMethod(target, "rmdir", RMDir);
2341
4568
  env->SetMethod(target, "mkdir", MKDir);
2342
4568
  env->SetMethod(target, "readdir", ReadDir);
2343
4568
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2344
4568
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2345
4568
  env->SetMethod(target, "stat", Stat);
2346
4568
  env->SetMethod(target, "lstat", LStat);
2347
4568
  env->SetMethod(target, "fstat", FStat);
2348
4568
  env->SetMethod(target, "link", Link);
2349
4568
  env->SetMethod(target, "symlink", Symlink);
2350
4568
  env->SetMethod(target, "readlink", ReadLink);
2351
4568
  env->SetMethod(target, "unlink", Unlink);
2352
4568
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2353
4568
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2354
4568
  env->SetMethod(target, "writeString", WriteString);
2355
4568
  env->SetMethod(target, "realpath", RealPath);
2356
4568
  env->SetMethod(target, "copyFile", CopyFile);
2357
2358
4568
  env->SetMethod(target, "chmod", Chmod);
2359
4568
  env->SetMethod(target, "fchmod", FChmod);
2360
  // env->SetMethod(target, "lchmod", LChmod);
2361
2362
4568
  env->SetMethod(target, "chown", Chown);
2363
4568
  env->SetMethod(target, "fchown", FChown);
2364
4568
  env->SetMethod(target, "lchown", LChown);
2365
2366
4568
  env->SetMethod(target, "utimes", UTimes);
2367
4568
  env->SetMethod(target, "futimes", FUTimes);
2368
2369
4568
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2370
2371
  target
2372
9136
      ->Set(context,
2373
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2374
            Integer::New(
2375
                isolate,
2376
18272
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2377
      .Check();
2378
2379
9136
  target->Set(context,
2380
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2381
18272
              binding_data->stats_field_array.GetJSArray()).Check();
2382
2383
9136
  target->Set(context,
2384
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2385
18272
              binding_data->stats_field_bigint_array.GetJSArray()).Check();
2386
2387
4568
  StatWatcher::Initialize(env, target);
2388
2389
  // Create FunctionTemplate for FSReqCallback
2390
4568
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2391
13704
  fst->InstanceTemplate()->SetInternalFieldCount(
2392
4568
      FSReqBase::kInternalFieldCount);
2393
9136
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2394
  Local<String> wrapString =
2395
4568
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2396
4568
  fst->SetClassName(wrapString);
2397
  target
2398
9136
      ->Set(context, wrapString,
2399
18272
            fst->GetFunction(env->context()).ToLocalChecked())
2400
      .Check();
2401
2402
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2403
  // to do anything in the constructor, so we only store the instance template.
2404
4568
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2405
13704
  fh_rw->InstanceTemplate()->SetInternalFieldCount(
2406
4568
      FSReqBase::kInternalFieldCount);
2407
9136
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2408
  Local<String> fhWrapString =
2409
4568
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2410
4568
  fh_rw->SetClassName(fhWrapString);
2411
4568
  env->set_filehandlereadwrap_template(
2412
4568
      fst->InstanceTemplate());
2413
2414
  // Create Function Template for FSReqPromise
2415
4568
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2416
9136
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2417
  Local<String> promiseString =
2418
4568
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2419
4568
  fpt->SetClassName(promiseString);
2420
4568
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2421
4568
  fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2422
4568
  env->set_fsreqpromise_constructor_template(fpo);
2423
2424
  // Create FunctionTemplate for FileHandle
2425
4568
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2426
9136
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2427
4568
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2428
4568
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2429
4568
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2430
4568
  fdt->SetInternalFieldCount(StreamBase::kInternalFieldCount);
2431
  Local<String> handleString =
2432
4568
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2433
4568
  fd->SetClassName(handleString);
2434
4568
  StreamBase::AddMethods(env, fd);
2435
  target
2436
9136
      ->Set(context, handleString,
2437
18272
            fd->GetFunction(env->context()).ToLocalChecked())
2438
      .Check();
2439
4568
  env->set_fd_constructor_template(fdt);
2440
2441
  // Create FunctionTemplate for FileHandle::CloseReq
2442
4568
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2443
9136
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2444
4568
                        "FileHandleCloseReq"));
2445
9136
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2446
4568
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2447
4568
  fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2448
4568
  env->set_fdclose_constructor_template(fdcloset);
2449
2450
  Local<Symbol> use_promises_symbol =
2451
    Symbol::New(isolate,
2452
4568
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2453
4568
  env->set_fs_use_promises_symbol(use_promises_symbol);
2454
9136
  target->Set(context,
2455
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2456
13704
              use_promises_symbol).Check();
2457
}
2458
2459
}  // namespace fs
2460
2461
}  // end namespace node
2462
2463

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