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: 1222 1308 93.4 %
Date: 2019-05-05 22:32:45 Branches: 788 1198 65.8 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_file.h"
23
#include "aliased_buffer.h"
24
#include "node_buffer.h"
25
#include "node_process.h"
26
#include "node_stat_watcher.h"
27
#include "util.h"
28
29
#include "tracing/trace_event.h"
30
31
#include "req_wrap-inl.h"
32
#include "stream_base-inl.h"
33
#include "string_bytes.h"
34
#include "string_search.h"
35
36
#include <fcntl.h>
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <cstring>
40
#include <cerrno>
41
#include <climits>
42
43
#if defined(__MINGW32__) || defined(_MSC_VER)
44
# include <io.h>
45
#endif
46
47
#include <memory>
48
49
namespace node {
50
51
namespace fs {
52
53
using v8::Array;
54
using v8::BigUint64Array;
55
using v8::Context;
56
using v8::DontDelete;
57
using v8::EscapableHandleScope;
58
using v8::Float64Array;
59
using v8::Function;
60
using v8::FunctionCallbackInfo;
61
using v8::FunctionTemplate;
62
using v8::HandleScope;
63
using v8::Int32;
64
using v8::Integer;
65
using v8::Isolate;
66
using v8::Local;
67
using v8::MaybeLocal;
68
using v8::Number;
69
using v8::Object;
70
using v8::ObjectTemplate;
71
using v8::Promise;
72
using v8::PropertyAttribute;
73
using v8::ReadOnly;
74
using v8::String;
75
using v8::Symbol;
76
using v8::Uint32;
77
using v8::Undefined;
78
using v8::Value;
79
80
#ifndef S_ISDIR
81
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
82
#endif
83
84
#ifdef __POSIX__
85
constexpr char kPathSeparator = '/';
86
#else
87
const char* const kPathSeparator = "\\/";
88
#endif
89
90
#define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
91
#define TRACE_NAME(name) "fs.sync." #name
92
#define GET_TRACE_ENABLED                                                  \
93
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
94
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
95
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
96
  if (GET_TRACE_ENABLED)                                                   \
97
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
98
  ##__VA_ARGS__);
99
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
100
  if (GET_TRACE_ENABLED)                                                   \
101
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
102
  ##__VA_ARGS__);
103
104
// We sometimes need to convert a C++ lambda function to a raw C-style function.
105
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
106
// functions, and thus does not wrap them properly.
107
typedef void(*uv_fs_callback_t)(uv_fs_t*);
108
109
// The FileHandle object wraps a file descriptor and will close it on garbage
110
// collection if necessary. If that happens, a process warning will be
111
// emitted (or a fatal exception will occur if the fd cannot be closed.)
112
79
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
113
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
114
      StreamBase(env),
115
79
      fd_(fd) {
116
79
  MakeWeak();
117
79
  StreamBase::AttachToObject(GetObject());
118
79
}
119
120
79
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
121

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

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

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

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

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

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







58701
  CHECK_NOT_NULL(req_wrap);
700
58701
  req_wrap->Init(syscall, dest, len, enc);
701
58701
  int err = req_wrap->Dispatch(fn, fn_args..., after);
702







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







592685
  if (err < 0) {
737
2264
    Local<Context> context = env->context();
738
2264
    Local<Object> ctx_obj = ctx.As<Object>();
739
2264
    Isolate* isolate = env->isolate();
740
    ctx_obj->Set(context,
741
             env->errno_string(),
742
9056
             Integer::New(isolate, err)).Check();
743
    ctx_obj->Set(context,
744
             env->syscall_string(),
745
9056
             OneByteString(isolate, syscall)).Check();
746
  }
747
592685
  return err;
748
}
749
750
// TODO(addaleax): Currently, callers check the return value and assume
751
// that nullptr indicates a synchronous call, rather than a failure.
752
// Failure conditions should be disambiguated and handled appropriately.
753
651547
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
754
                             bool use_bigint = false) {
755
651547
  if (value->IsObject()) {
756
58515
    return Unwrap<FSReqBase>(value.As<Object>());
757
1186064
  } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
758
347
    if (use_bigint) {
759
3
      return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
760
    } else {
761
344
      return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
762
    }
763
  }
764
592685
  return nullptr;
765
}
766
767
1190
void Access(const FunctionCallbackInfo<Value>& args) {
768
1190
  Environment* env = Environment::GetCurrent(args);
769
1190
  Isolate* isolate = env->isolate();
770
1190
  HandleScope scope(isolate);
771
772
1190
  const int argc = args.Length();
773
1190
  CHECK_GE(argc, 2);
774
775
2380
  CHECK(args[1]->IsInt32());
776
3570
  int mode = args[1].As<Int32>()->Value();
777
778
2380
  BufferValue path(isolate, args[0]);
779
1190
  CHECK_NOT_NULL(*path);
780
781
1190
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
782
1190
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
783
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
784
68
              uv_fs_access, *path, mode);
785
  } else {  // access(path, mode, undefined, ctx)
786
1122
    CHECK_EQ(argc, 4);
787
1122
    FSReqWrapSync req_wrap_sync;
788

1124
    FS_SYNC_TRACE_BEGIN(access);
789
2244
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
790

1124
    FS_SYNC_TRACE_END(access);
791
1190
  }
792
1190
}
793
794
795
64576
void Close(const FunctionCallbackInfo<Value>& args) {
796
64576
  Environment* env = Environment::GetCurrent(args);
797
798
64576
  const int argc = args.Length();
799
64576
  CHECK_GE(argc, 2);
800
801
129152
  CHECK(args[0]->IsInt32());
802
193728
  int fd = args[0].As<Int32>()->Value();
803
804
64576
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
805
64576
  if (req_wrap_async != nullptr) {  // close(fd, req)
806
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
807
7723
              uv_fs_close, fd);
808
  } else {  // close(fd, undefined, ctx)
809
56853
    CHECK_EQ(argc, 3);
810
56853
    FSReqWrapSync req_wrap_sync;
811

56913
    FS_SYNC_TRACE_BEGIN(close);
812
56853
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
813

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

13433
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
870
1
    start = 3;  // Skip UTF-8 BOM.
871
  }
872
873
13433
  const size_t size = offset - start;
874

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

32552
    FS_SYNC_TRACE_BEGIN(stat);
924
65100
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
925

32552
    FS_SYNC_TRACE_END(stat);
926
32550
    if (err != 0) {
927
34474
      return;  // error info is in ctx
928
    }
929
930
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
931
32548
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
932

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

115634
    FS_SYNC_TRACE_BEGIN(lstat);
954
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
955
231200
                       *path);
956

115634
    FS_SYNC_TRACE_END(lstat);
957
115600
    if (err != 0) {
958
121286
      return;  // error info is in ctx
959
    }
960
961
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
962
115598
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
963

231196
    args.GetReturnValue().Set(arr);
964
121282
  }
965
}
966
967
53239
static void FStat(const FunctionCallbackInfo<Value>& args) {
968
53239
  Environment* env = Environment::GetCurrent(args);
969
970
53239
  const int argc = args.Length();
971
53239
  CHECK_GE(argc, 2);
972
973
106478
  CHECK(args[0]->IsInt32());
974
159717
  int fd = args[0].As<Int32>()->Value();
975
976
106478
  bool use_bigint = args[1]->IsTrue();
977
106478
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
978
53239
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
979
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
980
2796
              uv_fs_fstat, fd);
981
  } else {  // fstat(fd, use_bigint, undefined, ctx)
982
50443
    CHECK_EQ(argc, 4);
983
50443
    FSReqWrapSync req_wrap_sync;
984

50453
    FS_SYNC_TRACE_BEGIN(fstat);
985
50443
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
986

50453
    FS_SYNC_TRACE_END(fstat);
987
50443
    if (err != 0) {
988
53256
      return;  // error info is in ctx
989
    }
990
991
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
992
50426
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
993
100852
    args.GetReturnValue().Set(arr);
994
  }
995
}
996
997
99
static void Symlink(const FunctionCallbackInfo<Value>& args) {
998
99
  Environment* env = Environment::GetCurrent(args);
999
99
  Isolate* isolate = env->isolate();
1000
1001
99
  int argc = args.Length();
1002
99
  CHECK_GE(argc, 4);
1003
1004
99
  BufferValue target(isolate, args[0]);
1005
99
  CHECK_NOT_NULL(*target);
1006
198
  BufferValue path(isolate, args[1]);
1007
99
  CHECK_NOT_NULL(*path);
1008
1009
198
  CHECK(args[2]->IsInt32());
1010
297
  int flags = args[2].As<Int32>()->Value();
1011
1012
99
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1013
99
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1014
21
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1015
42
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1016
  } else {  // symlink(target, path, flags, undefinec, ctx)
1017
78
    CHECK_EQ(argc, 5);
1018
78
    FSReqWrapSync req_wrap_sync;
1019

82
    FS_SYNC_TRACE_BEGIN(symlink);
1020
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1021
156
             uv_fs_symlink, *target, *path, flags);
1022

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

11
    FS_SYNC_TRACE_BEGIN(link);
1047
    SyncCall(env, args[3], &req_wrap_sync, "link",
1048
10
             uv_fs_link, *src, *dest);
1049

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

44
    FS_SYNC_TRACE_BEGIN(readlink);
1073
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1074
84
                       uv_fs_readlink, *path);
1075

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

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

5
    FS_SYNC_TRACE_BEGIN(rename);
1117
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1118
6
             *old_path, *new_path);
1119

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

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1143
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1144
14
             len);
1145

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

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

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

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

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

3589
    FS_SYNC_TRACE_BEGIN(unlink);
1210
7058
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1211

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

3779
    FS_SYNC_TRACE_BEGIN(rmdir);
1232
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1233
7546
             uv_fs_rmdir, *path);
1234

3779
    FS_SYNC_TRACE_END(rmdir);
1235
3809
  }
1236
3809
}
1237
1238
4474
int MKDirpSync(uv_loop_t* loop,
1239
               uv_fs_t* req,
1240
               const std::string& path,
1241
               int mode,
1242
               uv_fs_cb cb) {
1243
4474
  FSContinuationData continuation_data(req, mode, cb);
1244
4474
  continuation_data.PushPath(std::move(path));
1245
1246
4474
  while (continuation_data.paths.size() > 0) {
1247
4488
    std::string next_path = continuation_data.PopPath();
1248
4488
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1249
    while (true) {
1250

4489
      switch (err) {
1251
        case 0:
1252
22
          if (continuation_data.paths.size() == 0) {
1253
16
            return 0;
1254
          }
1255
6
          break;
1256
        case UV_ENOENT: {
1257
          std::string dirname = next_path.substr(0,
1258
8
                                        next_path.find_last_of(kPathSeparator));
1259
8
          if (dirname != next_path) {
1260
7
            continuation_data.PushPath(std::move(next_path));
1261
7
            continuation_data.PushPath(std::move(dirname));
1262
1
          } else if (continuation_data.paths.size() == 0) {
1263
1
            err = UV_EEXIST;
1264
1
            continue;
1265
          }
1266
7
          break;
1267
        }
1268
        case UV_EPERM: {
1269
          return err;
1270
        }
1271
        default:
1272
4459
          uv_fs_req_cleanup(req);
1273
4459
          int orig_err = err;
1274
4459
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1275

4459
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1276
1
            uv_fs_req_cleanup(req);
1277

1
            if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
1278
              return UV_ENOTDIR;
1279
            }
1280
1
            return UV_EEXIST;
1281
          }
1282
4458
          if (err < 0) return err;
1283
4456
          break;
1284
      }
1285
4469
      break;
1286
    }
1287
4469
    uv_fs_req_cleanup(req);
1288
4469
  }
1289
1290
4455
  return 0;
1291
}
1292
1293
22
int MKDirpAsync(uv_loop_t* loop,
1294
                uv_fs_t* req,
1295
                const char* path,
1296
                int mode,
1297
                uv_fs_cb cb) {
1298
22
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1299
  // on the first iteration of algorithm, stash state information.
1300
22
  if (req_wrap->continuation_data == nullptr) {
1301
20
    req_wrap->continuation_data =
1302
10
        std::make_unique<FSContinuationData>(req, mode, cb);
1303
10
    req_wrap->continuation_data->PushPath(std::move(path));
1304
  }
1305
1306
  // on each iteration of algorithm, mkdir directory on top of stack.
1307
22
  std::string next_path = req_wrap->continuation_data->PopPath();
1308
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1309
66
                        uv_fs_callback_t{[](uv_fs_t* req) {
1310
22
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1311
22
    Environment* env = req_wrap->env();
1312
22
    uv_loop_t* loop = env->event_loop();
1313
22
    std::string path = req->path;
1314
22
    int err = req->result;
1315
1316
    while (true) {
1317

23
      switch (err) {
1318
        case 0: {
1319
11
          if (req_wrap->continuation_data->paths.size() == 0) {
1320
5
            req_wrap->continuation_data->Done(0);
1321
          } else {
1322
6
            uv_fs_req_cleanup(req);
1323
            MKDirpAsync(loop, req, path.c_str(),
1324
6
                        req_wrap->continuation_data->mode, nullptr);
1325
          }
1326
11
          break;
1327
        }
1328
        case UV_ENOENT: {
1329
          std::string dirname = path.substr(0,
1330
7
                                            path.find_last_of(kPathSeparator));
1331
7
          if (dirname != path) {
1332
6
            req_wrap->continuation_data->PushPath(std::move(path));
1333
6
            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
6
          uv_fs_req_cleanup(req);
1339
          MKDirpAsync(loop, req, path.c_str(),
1340
6
                      req_wrap->continuation_data->mode, nullptr);
1341
6
          break;
1342
        }
1343
        case UV_EPERM: {
1344
          req_wrap->continuation_data->Done(err);
1345
          break;
1346
        }
1347
        default:
1348
5
          uv_fs_req_cleanup(req);
1349
          // Stash err for use in the callback.
1350
5
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1351
          int err = uv_fs_stat(loop, req, path.c_str(),
1352
15
                               uv_fs_callback_t{[](uv_fs_t* req) {
1353
5
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1354
5
            int err = req->result;
1355

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1356
3
                  req_wrap->continuation_data->paths.size() > 0) {
1357
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1358
                Environment* env = req_wrap->env();
1359
                uv_loop_t* loop = env->event_loop();
1360
                std::string path = req->path;
1361
                uv_fs_req_cleanup(req);
1362
                MKDirpAsync(loop, req, path.c_str(),
1363
                            req_wrap->continuation_data->mode, nullptr);
1364
5
                return;
1365
              }
1366
              err = UV_ENOTDIR;
1367
            }
1368
            // verify that the path pointed to is actually a directory.
1369

5
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1370
5
            uv_fs_req_cleanup(req);
1371
5
            req_wrap->continuation_data->Done(err);
1372
15
          }});
1373
5
          if (err < 0) req_wrap->continuation_data->Done(err);
1374
5
          break;
1375
      }
1376
22
      break;
1377
    }
1378
88
  }});
1379
1380
22
  return err;
1381
}
1382
1383
3337
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1384
3337
  Environment* env = Environment::GetCurrent(args);
1385
1386
3337
  const int argc = args.Length();
1387
3337
  CHECK_GE(argc, 4);
1388
1389
3337
  BufferValue path(env->isolate(), args[0]);
1390
3337
  CHECK_NOT_NULL(*path);
1391
1392
6674
  CHECK(args[1]->IsInt32());
1393
10011
  const int mode = args[1].As<Int32>()->Value();
1394
1395
6674
  CHECK(args[2]->IsBoolean());
1396
6674
  bool mkdirp = args[2]->IsTrue();
1397
1398
3337
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1399
3337
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1400
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1401
1236
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1402
  } else {  // mkdir(path, mode, undefined, ctx)
1403
2101
    CHECK_EQ(argc, 5);
1404
2101
    FSReqWrapSync req_wrap_sync;
1405

2105
    FS_SYNC_TRACE_BEGIN(mkdir);
1406
2101
    if (mkdirp) {
1407
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1408
14
               MKDirpSync, *path, mode);
1409
    } else {
1410
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1411
4188
               uv_fs_mkdir, *path, mode);
1412
    }
1413

2105
    FS_SYNC_TRACE_END(mkdir);
1414
3337
  }
1415
3337
}
1416
1417
36
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1418
36
  Environment* env = Environment::GetCurrent(args);
1419
36
  Isolate* isolate = env->isolate();
1420
1421
36
  const int argc = args.Length();
1422
36
  CHECK_GE(argc, 3);
1423
1424
36
  BufferValue path(isolate, args[0]);
1425
36
  CHECK_NOT_NULL(*path);
1426
1427
36
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1428
1429
36
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1430
36
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1431
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1432
18
              uv_fs_realpath, *path);
1433
  } else {  // realpath(path, encoding, undefined, ctx)
1434
18
    CHECK_EQ(argc, 4);
1435
18
    FSReqWrapSync req_wrap_sync;
1436

20
    FS_SYNC_TRACE_BEGIN(realpath);
1437
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1438
36
                       uv_fs_realpath, *path);
1439

20
    FS_SYNC_TRACE_END(realpath);
1440
18
    if (err < 0) {
1441
2
      return;  // syscall failed, no need to continue, error info is in ctx
1442
    }
1443
1444
16
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1445
1446
    Local<Value> error;
1447
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1448
                                               link_path,
1449
                                               encoding,
1450
16
                                               &error);
1451
16
    if (rc.IsEmpty()) {
1452
      Local<Object> ctx = args[3].As<Object>();
1453
      ctx->Set(env->context(), env->error_string(), error).Check();
1454
      return;
1455
    }
1456
1457

32
    args.GetReturnValue().Set(rc.ToLocalChecked());
1458
34
  }
1459
}
1460
1461
16097
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1462
16097
  Environment* env = Environment::GetCurrent(args);
1463
16097
  Isolate* isolate = env->isolate();
1464
1465
16097
  const int argc = args.Length();
1466
16097
  CHECK_GE(argc, 3);
1467
1468
16097
  BufferValue path(isolate, args[0]);
1469
16097
  CHECK_NOT_NULL(*path);
1470
1471
16097
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1472
1473
32194
  bool with_types = args[2]->IsTrue();
1474
1475
16097
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1476
16097
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1477
177
    if (with_types) {
1478
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1479
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1480
    } else {
1481
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1482
170
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1483
    }
1484
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1485
15920
    CHECK_EQ(argc, 5);
1486
15920
    FSReqWrapSync req_wrap_sync;
1487

15922
    FS_SYNC_TRACE_BEGIN(readdir);
1488
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1489
31840
                       uv_fs_scandir, *path, 0 /*flags*/);
1490

15922
    FS_SYNC_TRACE_END(readdir);
1491
15920
    if (err < 0) {
1492
43
      return;  // syscall failed, no need to continue, error info is in ctx
1493
    }
1494
1495
15877
    CHECK_GE(req_wrap_sync.req.result, 0);
1496
    int r;
1497
31754
    std::vector<Local<Value>> name_v;
1498
31754
    std::vector<Local<Value>> type_v;
1499
1500
684438
    for (int i = 0; ; i++) {
1501
      uv_dirent_t ent;
1502
1503
684438
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1504
684438
      if (r == UV_EOF)
1505
15877
        break;
1506
668561
      if (r != 0) {
1507
        Local<Object> ctx = args[4].As<Object>();
1508
        ctx->Set(env->context(), env->errno_string(),
1509
                 Integer::New(isolate, r)).Check();
1510
        ctx->Set(env->context(), env->syscall_string(),
1511
                 OneByteString(isolate, "readdir")).Check();
1512
        return;
1513
      }
1514
1515
      Local<Value> error;
1516
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1517
                                                       ent.name,
1518
                                                       encoding,
1519
668561
                                                       &error);
1520
1521
668561
      if (filename.IsEmpty()) {
1522
        Local<Object> ctx = args[4].As<Object>();
1523
        ctx->Set(env->context(), env->error_string(), error).Check();
1524
        return;
1525
      }
1526
1527
668561
      name_v.push_back(filename.ToLocalChecked());
1528
1529
668561
      if (with_types) {
1530
19
        type_v.emplace_back(Integer::New(isolate, ent.type));
1531
      }
1532
668561
    }
1533
1534
1535
15877
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1536
15877
    if (with_types) {
1537
5
      Local<Array> result = Array::New(isolate, 2);
1538
15
      result->Set(env->context(), 0, names).Check();
1539
5
      result->Set(env->context(),
1540
                  1,
1541
                  Array::New(isolate, type_v.data(),
1542
20
                             type_v.size())).Check();
1543
10
      args.GetReturnValue().Set(result);
1544
    } else {
1545
31744
      args.GetReturnValue().Set(names);
1546
15877
    }
1547
16054
  }
1548
}
1549
1550
65419
static void Open(const FunctionCallbackInfo<Value>& args) {
1551
65419
  Environment* env = Environment::GetCurrent(args);
1552
1553
65419
  const int argc = args.Length();
1554
65419
  CHECK_GE(argc, 3);
1555
1556
65419
  BufferValue path(env->isolate(), args[0]);
1557
65419
  CHECK_NOT_NULL(*path);
1558
1559
130838
  CHECK(args[1]->IsInt32());
1560
196257
  const int flags = args[1].As<Int32>()->Value();
1561
1562
130838
  CHECK(args[2]->IsInt32());
1563
196257
  const int mode = args[2].As<Int32>()->Value();
1564
1565
65419
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1566
65419
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1567
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1568
8097
              uv_fs_open, *path, flags, mode);
1569
  } else {  // open(path, flags, mode, undefined, ctx)
1570
57322
    CHECK_EQ(argc, 5);
1571
57322
    FSReqWrapSync req_wrap_sync;
1572

57394
    FS_SYNC_TRACE_BEGIN(open);
1573
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1574
114644
                          uv_fs_open, *path, flags, mode);
1575

57394
    FS_SYNC_TRACE_END(open);
1576
114644
    args.GetReturnValue().Set(result);
1577
65419
  }
1578
65419
}
1579
1580
64
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1581
64
  Environment* env = Environment::GetCurrent(args);
1582
64
  Isolate* isolate = env->isolate();
1583
1584
64
  const int argc = args.Length();
1585
64
  CHECK_GE(argc, 3);
1586
1587
64
  BufferValue path(isolate, args[0]);
1588
64
  CHECK_NOT_NULL(*path);
1589
1590
128
  CHECK(args[1]->IsInt32());
1591
192
  const int flags = args[1].As<Int32>()->Value();
1592
1593
128
  CHECK(args[2]->IsInt32());
1594
192
  const int mode = args[2].As<Int32>()->Value();
1595
1596
64
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1597
64
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1598
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1599
63
              uv_fs_open, *path, flags, mode);
1600
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1601
1
    CHECK_EQ(argc, 5);
1602
1
    FSReqWrapSync req_wrap_sync;
1603

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

1
    FS_SYNC_TRACE_END(open);
1607
1
    if (result < 0) {
1608
      return;  // syscall failed, no need to continue, error info is in ctx
1609
    }
1610
1
    FileHandle* fd = FileHandle::New(env, result);
1611
1
    if (fd == nullptr) return;
1612

3
    args.GetReturnValue().Set(fd->object());
1613
64
  }
1614
}
1615
1616
35
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1617
35
  Environment* env = Environment::GetCurrent(args);
1618
35
  Isolate* isolate = env->isolate();
1619
1620
35
  const int argc = args.Length();
1621
35
  CHECK_GE(argc, 3);
1622
1623
35
  BufferValue src(isolate, args[0]);
1624
35
  CHECK_NOT_NULL(*src);
1625
1626
70
  BufferValue dest(isolate, args[1]);
1627
35
  CHECK_NOT_NULL(*dest);
1628
1629
70
  CHECK(args[2]->IsInt32());
1630
105
  const int flags = args[2].As<Int32>()->Value();
1631
1632
35
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1633
35
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1634
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1635
15
                  *dest, dest.length(), UTF8, AfterNoArgs,
1636
30
                  uv_fs_copyfile, *src, *dest, flags);
1637
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1638
20
    CHECK_EQ(argc, 5);
1639
20
    FSReqWrapSync req_wrap_sync;
1640

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1641
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1642
40
             uv_fs_copyfile, *src, *dest, flags);
1643

22
    FS_SYNC_TRACE_END(copyfile);
1644
35
  }
1645
35
}
1646
1647
1648
// Wrapper for write(2).
1649
//
1650
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1651
// 0 fd        integer. file descriptor
1652
// 1 buffer    the data to write
1653
// 2 offset    where in the buffer to start from
1654
// 3 length    how much to write
1655
// 4 position  if integer, position to write at in the file.
1656
//             if null, write from the current position
1657
146660
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1658
146660
  Environment* env = Environment::GetCurrent(args);
1659
1660
146660
  const int argc = args.Length();
1661
146660
  CHECK_GE(argc, 4);
1662
1663
293320
  CHECK(args[0]->IsInt32());
1664
439980
  const int fd = args[0].As<Int32>()->Value();
1665
1666
146660
  CHECK(Buffer::HasInstance(args[1]));
1667
293320
  Local<Object> buffer_obj = args[1].As<Object>();
1668
146660
  char* buffer_data = Buffer::Data(buffer_obj);
1669
146660
  size_t buffer_length = Buffer::Length(buffer_obj);
1670
1671
293320
  CHECK(args[2]->IsInt32());
1672
439980
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1673
146660
  CHECK_LE(off, buffer_length);
1674
1675
293320
  CHECK(args[3]->IsInt32());
1676
439980
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1677
146660
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1678
146660
  CHECK_LE(len, buffer_length);
1679
146660
  CHECK_GE(off + len, off);
1680
1681

306964
  const int64_t pos = GET_OFFSET(args[4]);
1682
1683
146660
  char* buf = buffer_data + off;
1684
146660
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1685
1686
146660
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1687
146660
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1688
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1689
14212
              uv_fs_write, fd, &uvbuf, 1, pos);
1690
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1691
132448
    CHECK_EQ(argc, 7);
1692
132448
    FSReqWrapSync req_wrap_sync;
1693

132498
    FS_SYNC_TRACE_BEGIN(write);
1694
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1695
132448
                                uv_fs_write, fd, &uvbuf, 1, pos);
1696

132498
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1697
397344
    args.GetReturnValue().Set(bytesWritten);
1698
  }
1699
146660
}
1700
1701
1702
// Wrapper for writev(2).
1703
//
1704
// bytesWritten = writev(fd, chunks, position, callback)
1705
// 0 fd        integer. file descriptor
1706
// 1 chunks    array of buffers to write
1707
// 2 position  if integer, position to write at in the file.
1708
//             if null, write from the current position
1709
13
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1710
13
  Environment* env = Environment::GetCurrent(args);
1711
1712
13
  const int argc = args.Length();
1713
13
  CHECK_GE(argc, 3);
1714
1715
26
  CHECK(args[0]->IsInt32());
1716
39
  const int fd = args[0].As<Int32>()->Value();
1717
1718
26
  CHECK(args[1]->IsArray());
1719
26
  Local<Array> chunks = args[1].As<Array>();
1720
1721

26
  int64_t pos = GET_OFFSET(args[2]);
1722
1723
13
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1724
1725
66798
  for (uint32_t i = 0; i < iovs.length(); i++) {
1726
200355
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1727
66785
    CHECK(Buffer::HasInstance(chunk));
1728
66785
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1729
  }
1730
1731
13
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1732
13
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1733
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1734
13
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1735
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1736
    CHECK_EQ(argc, 5);
1737
    FSReqWrapSync req_wrap_sync;
1738
    FS_SYNC_TRACE_BEGIN(write);
1739
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1740
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1741
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1742
    args.GetReturnValue().Set(bytesWritten);
1743
13
  }
1744
13
}
1745
1746
1747
// Wrapper for write(2).
1748
//
1749
// bytesWritten = write(fd, string, position, enc, callback)
1750
// 0 fd        integer. file descriptor
1751
// 1 string    non-buffer values are converted to strings
1752
// 2 position  if integer, position to write at in the file.
1753
//             if null, write from the current position
1754
// 3 enc       encoding of string
1755
1505
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1756
1505
  Environment* env = Environment::GetCurrent(args);
1757
1505
  Isolate* isolate = env->isolate();
1758
1759
1505
  const int argc = args.Length();
1760
1505
  CHECK_GE(argc, 4);
1761
1762
3010
  CHECK(args[0]->IsInt32());
1763
4515
  const int fd = args[0].As<Int32>()->Value();
1764
1765

3493
  const int64_t pos = GET_OFFSET(args[2]);
1766
1767
1505
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1768
1769
1505
  Local<Value> value = args[1];
1770
1505
  char* buf = nullptr;
1771
  size_t len;
1772
1773
1505
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1774
1505
  const bool is_async = req_wrap_async != nullptr;
1775
1776
  // Avoid copying the string when it is externalized but only when:
1777
  // 1. The target encoding is compatible with the string's encoding, and
1778
  // 2. The write is synchronous, otherwise the string might get neutered
1779
  //    while the request is in flight, and
1780
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1781
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1782
  // The const_casts are conceptually sound: memory is read but not written.
1783

4193
  if (!is_async && value->IsString()) {
1784
1344
    auto string = value.As<String>();
1785


1345
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1786
1
      auto ext = string->GetExternalOneByteStringResource();
1787
1
      buf = const_cast<char*>(ext->data());
1788
1
      len = ext->length();
1789


1344
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1790
2
      auto ext = string->GetExternalStringResource();
1791
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1792
1
      len = ext->length() * sizeof(*ext->data());
1793
    }
1794
  }
1795
1796
1505
  if (is_async) {  // write(fd, string, pos, enc, req)
1797
161
    CHECK_NOT_NULL(req_wrap_async);
1798
322
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1799
    FSReqBase::FSReqBuffer& stack_buffer =
1800
161
        req_wrap_async->Init("write", len, enc);
1801
    // StorageSize may return too large a char, so correct the actual length
1802
    // by the write size
1803
161
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1804
161
    stack_buffer.SetLengthAndZeroTerminate(len);
1805
161
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1806
    int err = req_wrap_async->Dispatch(uv_fs_write,
1807
                                       fd,
1808
                                       &uvbuf,
1809
                                       1,
1810
                                       pos,
1811
161
                                       AfterInteger);
1812
161
    if (err < 0) {
1813
      uv_fs_t* uv_req = req_wrap_async->req();
1814
      uv_req->result = err;
1815
      uv_req->path = nullptr;
1816
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1817
                             // an error
1818
    } else {
1819
161
      req_wrap_async->SetReturnValue(args);
1820
    }
1821
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1822
1344
    CHECK_EQ(argc, 6);
1823
1344
    FSReqWrapSync req_wrap_sync;
1824
2688
    FSReqBase::FSReqBuffer stack_buffer;
1825
1344
    if (buf == nullptr) {
1826
2684
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1827
        return;
1828
1342
      stack_buffer.AllocateSufficientStorage(len + 1);
1829
      // StorageSize may return too large a char, so correct the actual length
1830
      // by the write size
1831
      len = StringBytes::Write(isolate, *stack_buffer,
1832
1342
                               len, args[1], enc);
1833
1342
      stack_buffer.SetLengthAndZeroTerminate(len);
1834
1342
      buf = *stack_buffer;
1835
    }
1836
1344
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1837

1344
    FS_SYNC_TRACE_BEGIN(write);
1838
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1839
1344
                                uv_fs_write, fd, &uvbuf, 1, pos);
1840

1344
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1841
5376
    args.GetReturnValue().Set(bytesWritten);
1842
  }
1843
}
1844
1845
1846
/*
1847
 * Wrapper for read(2).
1848
 *
1849
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1850
 *
1851
 * 0 fd        int32. file descriptor
1852
 * 1 buffer    instance of Buffer
1853
 * 2 offset    int32. offset to start reading into inside buffer
1854
 * 3 length    int32. length to read
1855
 * 4 position  int64. file position - -1 for current position
1856
 */
1857
133150
static void Read(const FunctionCallbackInfo<Value>& args) {
1858
133150
  Environment* env = Environment::GetCurrent(args);
1859
1860
133150
  const int argc = args.Length();
1861
133150
  CHECK_GE(argc, 5);
1862
1863
266300
  CHECK(args[0]->IsInt32());
1864
399450
  const int fd = args[0].As<Int32>()->Value();
1865
1866
133150
  CHECK(Buffer::HasInstance(args[1]));
1867
266300
  Local<Object> buffer_obj = args[1].As<Object>();
1868
133150
  char* buffer_data = Buffer::Data(buffer_obj);
1869
133150
  size_t buffer_length = Buffer::Length(buffer_obj);
1870
1871
266300
  CHECK(args[2]->IsInt32());
1872
399450
  const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1873
133150
  CHECK_LT(off, buffer_length);
1874
1875
266300
  CHECK(args[3]->IsInt32());
1876
399450
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1877
133150
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1878
1879
266300
  CHECK(args[4]->IsNumber());
1880
399450
  const int64_t pos = args[4].As<Integer>()->Value();
1881
1882
133150
  char* buf = buffer_data + off;
1883
133150
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1884
1885
133150
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1886
133150
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1887
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1888
13723
              uv_fs_read, fd, &uvbuf, 1, pos);
1889
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1890
119427
    CHECK_EQ(argc, 7);
1891
119427
    FSReqWrapSync req_wrap_sync;
1892

119437
    FS_SYNC_TRACE_BEGIN(read);
1893
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1894
119427
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1895

119437
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1896
358281
    args.GetReturnValue().Set(bytesRead);
1897
  }
1898
133150
}
1899
1900
1901
/* fs.chmod(path, mode);
1902
 * Wrapper for chmod(1) / EIO_CHMOD
1903
 */
1904
266
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1905
266
  Environment* env = Environment::GetCurrent(args);
1906
1907
266
  const int argc = args.Length();
1908
266
  CHECK_GE(argc, 2);
1909
1910
266
  BufferValue path(env->isolate(), args[0]);
1911
266
  CHECK_NOT_NULL(*path);
1912
1913
532
  CHECK(args[1]->IsInt32());
1914
798
  int mode = args[1].As<Int32>()->Value();
1915
1916
266
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1917
266
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1918
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1919
253
              uv_fs_chmod, *path, mode);
1920
  } else {  // chmod(path, mode, undefined, ctx)
1921
13
    CHECK_EQ(argc, 4);
1922
13
    FSReqWrapSync req_wrap_sync;
1923

15
    FS_SYNC_TRACE_BEGIN(chmod);
1924
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1925
26
             uv_fs_chmod, *path, mode);
1926

15
    FS_SYNC_TRACE_END(chmod);
1927
266
  }
1928
266
}
1929
1930
1931
/* fs.fchmod(fd, mode);
1932
 * Wrapper for fchmod(1) / EIO_FCHMOD
1933
 */
1934
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1935
12
  Environment* env = Environment::GetCurrent(args);
1936
1937
12
  const int argc = args.Length();
1938
12
  CHECK_GE(argc, 2);
1939
1940
24
  CHECK(args[0]->IsInt32());
1941
36
  const int fd = args[0].As<Int32>()->Value();
1942
1943
24
  CHECK(args[1]->IsInt32());
1944
36
  const int mode = args[1].As<Int32>()->Value();
1945
1946
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1947
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1948
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1949
7
              uv_fs_fchmod, fd, mode);
1950
  } else {  // fchmod(fd, mode, undefined, ctx)
1951
5
    CHECK_EQ(argc, 4);
1952
5
    FSReqWrapSync req_wrap_sync;
1953

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1954
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1955
5
             uv_fs_fchmod, fd, mode);
1956

7
    FS_SYNC_TRACE_END(fchmod);
1957
  }
1958
12
}
1959
1960
1961
/* fs.chown(path, uid, gid);
1962
 * Wrapper for chown(1) / EIO_CHOWN
1963
 */
1964
128
static void Chown(const FunctionCallbackInfo<Value>& args) {
1965
128
  Environment* env = Environment::GetCurrent(args);
1966
1967
128
  const int argc = args.Length();
1968
128
  CHECK_GE(argc, 3);
1969
1970
128
  BufferValue path(env->isolate(), args[0]);
1971
128
  CHECK_NOT_NULL(*path);
1972
1973
256
  CHECK(args[1]->IsUint32());
1974
384
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1975
1976
256
  CHECK(args[2]->IsUint32());
1977
384
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1978
1979
128
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1980
128
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1981
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1982
126
              uv_fs_chown, *path, uid, gid);
1983
  } else {  // chown(path, uid, gid, undefined, ctx)
1984
2
    CHECK_EQ(argc, 5);
1985
2
    FSReqWrapSync req_wrap_sync;
1986

4
    FS_SYNC_TRACE_BEGIN(chown);
1987
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1988
4
             uv_fs_chown, *path, uid, gid);
1989

4
    FS_SYNC_TRACE_END(chown);
1990
128
  }
1991
128
}
1992
1993
1994
/* fs.fchown(fd, uid, gid);
1995
 * Wrapper for fchown(1) / EIO_FCHOWN
1996
 */
1997
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
1998
4
  Environment* env = Environment::GetCurrent(args);
1999
2000
4
  const int argc = args.Length();
2001
4
  CHECK_GE(argc, 3);
2002
2003
8
  CHECK(args[0]->IsInt32());
2004
12
  const int fd = args[0].As<Int32>()->Value();
2005
2006
8
  CHECK(args[1]->IsUint32());
2007
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2008
2009
8
  CHECK(args[2]->IsUint32());
2010
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2011
2012
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2013
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2014
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2015
2
              uv_fs_fchown, fd, uid, gid);
2016
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2017
2
    CHECK_EQ(argc, 5);
2018
2
    FSReqWrapSync req_wrap_sync;
2019

4
    FS_SYNC_TRACE_BEGIN(fchown);
2020
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2021
2
             uv_fs_fchown, fd, uid, gid);
2022

4
    FS_SYNC_TRACE_END(fchown);
2023
  }
2024
4
}
2025
2026
2027
10
static void LChown(const FunctionCallbackInfo<Value>& args) {
2028
10
  Environment* env = Environment::GetCurrent(args);
2029
2030
10
  const int argc = args.Length();
2031
10
  CHECK_GE(argc, 3);
2032
2033
10
  BufferValue path(env->isolate(), args[0]);
2034
10
  CHECK_NOT_NULL(*path);
2035
2036
20
  CHECK(args[1]->IsUint32());
2037
30
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2038
2039
20
  CHECK(args[2]->IsUint32());
2040
30
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2041
2042
10
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2043
10
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2044
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2045
8
              uv_fs_lchown, *path, uid, gid);
2046
  } else {  // lchown(path, uid, gid, undefined, ctx)
2047
2
    CHECK_EQ(argc, 5);
2048
2
    FSReqWrapSync req_wrap_sync;
2049

4
    FS_SYNC_TRACE_BEGIN(lchown);
2050
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2051
4
             uv_fs_lchown, *path, uid, gid);
2052

4
    FS_SYNC_TRACE_END(lchown);
2053
10
  }
2054
10
}
2055
2056
2057
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2058
29
  Environment* env = Environment::GetCurrent(args);
2059
2060
29
  const int argc = args.Length();
2061
29
  CHECK_GE(argc, 3);
2062
2063
29
  BufferValue path(env->isolate(), args[0]);
2064
29
  CHECK_NOT_NULL(*path);
2065
2066
58
  CHECK(args[1]->IsNumber());
2067
87
  const double atime = args[1].As<Number>()->Value();
2068
2069
58
  CHECK(args[2]->IsNumber());
2070
87
  const double mtime = args[2].As<Number>()->Value();
2071
2072
29
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2073
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2074
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2075
14
              uv_fs_utime, *path, atime, mtime);
2076
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2077
15
    CHECK_EQ(argc, 5);
2078
15
    FSReqWrapSync req_wrap_sync;
2079

17
    FS_SYNC_TRACE_BEGIN(utimes);
2080
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2081
30
             uv_fs_utime, *path, atime, mtime);
2082

17
    FS_SYNC_TRACE_END(utimes);
2083
29
  }
2084
29
}
2085
2086
1896
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2087
1896
  Environment* env = Environment::GetCurrent(args);
2088
2089
1896
  const int argc = args.Length();
2090
1896
  CHECK_GE(argc, 3);
2091
2092
3792
  CHECK(args[0]->IsInt32());
2093
5688
  const int fd = args[0].As<Int32>()->Value();
2094
2095
3792
  CHECK(args[1]->IsNumber());
2096
5688
  const double atime = args[1].As<Number>()->Value();
2097
2098
3792
  CHECK(args[2]->IsNumber());
2099
5688
  const double mtime = args[2].As<Number>()->Value();
2100
2101
1896
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2102
1896
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2103
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2104
1888
              uv_fs_futime, fd, atime, mtime);
2105
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2106
8
    CHECK_EQ(argc, 5);
2107
8
    FSReqWrapSync req_wrap_sync;
2108

10
    FS_SYNC_TRACE_BEGIN(futimes);
2109
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2110
8
             uv_fs_futime, fd, atime, mtime);
2111

10
    FS_SYNC_TRACE_END(futimes);
2112
  }
2113
1896
}
2114
2115
13
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2116
13
  Environment* env = Environment::GetCurrent(args);
2117
13
  Isolate* isolate = env->isolate();
2118
2119
13
  const int argc = args.Length();
2120
13
  CHECK_GE(argc, 2);
2121
2122
13
  BufferValue tmpl(isolate, args[0]);
2123
13
  CHECK_NOT_NULL(*tmpl);
2124
2125
13
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2126
2127
13
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2128
13
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2129
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2130
6
              uv_fs_mkdtemp, *tmpl);
2131
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2132
7
    CHECK_EQ(argc, 4);
2133
7
    FSReqWrapSync req_wrap_sync;
2134

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2135
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2136
14
             uv_fs_mkdtemp, *tmpl);
2137

9
    FS_SYNC_TRACE_END(mkdtemp);
2138
7
    const char* path = req_wrap_sync.req.path;
2139
2140
    Local<Value> error;
2141
    MaybeLocal<Value> rc =
2142
7
        StringBytes::Encode(isolate, path, encoding, &error);
2143
7
    if (rc.IsEmpty()) {
2144
      Local<Object> ctx = args[3].As<Object>();
2145
      ctx->Set(env->context(), env->error_string(), error).Check();
2146
13
      return;
2147
    }
2148

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