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

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

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

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

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

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

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







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







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







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

1291
    FS_SYNC_TRACE_BEGIN(access);
790
2578
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
791

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

53944
    FS_SYNC_TRACE_BEGIN(close);
813
53884
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
814

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

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

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

33331
    FS_SYNC_TRACE_BEGIN(stat);
927
66658
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
928

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

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

114167
    FS_SYNC_TRACE_BEGIN(lstat);
957
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
958
228266
                       *path);
959

114167
    FS_SYNC_TRACE_END(lstat);
960
114133
    if (err != 0) {
961
118840
      return;  // error info is in ctx
962
    }
963
964
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
965
114131
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
966

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

47398
    FS_SYNC_TRACE_BEGIN(fstat);
988
47388
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
989

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

86
    FS_SYNC_TRACE_BEGIN(symlink);
1023
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1024
164
             uv_fs_symlink, *target, *path, flags);
1025

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

11
    FS_SYNC_TRACE_BEGIN(link);
1050
    SyncCall(env, args[3], &req_wrap_sync, "link",
1051
10
             uv_fs_link, *src, *dest);
1052

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

48
    FS_SYNC_TRACE_BEGIN(readlink);
1076
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1077
92
                       uv_fs_readlink, *path);
1078

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

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

5
    FS_SYNC_TRACE_BEGIN(rename);
1120
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1121
6
             *old_path, *new_path);
1122

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

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1146
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1147
14
             len);
1148

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

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

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

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

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

3598
    FS_SYNC_TRACE_BEGIN(unlink);
1213
7076
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1214

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

3810
    FS_SYNC_TRACE_BEGIN(rmdir);
1235
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1236
7608
             uv_fs_rmdir, *path);
1237

3810
    FS_SYNC_TRACE_END(rmdir);
1238
3827
  }
1239
3827
}
1240
1241
4783
int MKDirpSync(uv_loop_t* loop,
1242
               uv_fs_t* req,
1243
               const std::string& path,
1244
               int mode,
1245
               uv_fs_cb cb) {
1246
4783
  FSContinuationData continuation_data(req, mode, cb);
1247
4783
  continuation_data.PushPath(std::move(path));
1248
1249
4783
  while (continuation_data.paths.size() > 0) {
1250
4797
    std::string next_path = continuation_data.PopPath();
1251
4797
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1252
    while (true) {
1253

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

4764
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1279
1
            uv_fs_req_cleanup(req);
1280

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

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

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

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

2127
    FS_SYNC_TRACE_BEGIN(mkdir);
1409
2123
    if (mkdirp) {
1410
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1411
14
               MKDirpSync, *path, mode);
1412
    } else {
1413
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1414
4232
               uv_fs_mkdir, *path, mode);
1415
    }
1416

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

22
    FS_SYNC_TRACE_BEGIN(realpath);
1440
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1441
40
                       uv_fs_realpath, *path);
1442

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

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

15899
    FS_SYNC_TRACE_BEGIN(readdir);
1491
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1492
31794
                       uv_fs_scandir, *path, 0 /*flags*/);
1493

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

54585
    FS_SYNC_TRACE_BEGIN(open);
1576
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1577
109026
                          uv_fs_open, *path, flags, mode);
1578

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

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

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

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

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1644
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1645
40
             uv_fs_copyfile, *src, *dest, flags);
1646

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

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

133526
    FS_SYNC_TRACE_BEGIN(write);
1697
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1698
133476
                                uv_fs_write, fd, &uvbuf, 1, pos);
1699

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

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

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

3785
  if (!is_async && value->IsString()) {
1787
1217
    auto string = value.As<String>();
1788


1218
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1789
1
      auto ext = string->GetExternalOneByteStringResource();
1790
1
      buf = const_cast<char*>(ext->data());
1791
1
      len = ext->length();
1792


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

1217
    FS_SYNC_TRACE_BEGIN(write);
1841
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1842
1217
                                uv_fs_write, fd, &uvbuf, 1, pos);
1843

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

87310
    FS_SYNC_TRACE_BEGIN(read);
1896
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1897
87300
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1898

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

15
    FS_SYNC_TRACE_BEGIN(chmod);
1927
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1928
26
             uv_fs_chmod, *path, mode);
1929

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

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1957
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1958
5
             uv_fs_fchmod, fd, mode);
1959

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

4
    FS_SYNC_TRACE_BEGIN(chown);
1990
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1991
4
             uv_fs_chown, *path, uid, gid);
1992

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

4
    FS_SYNC_TRACE_BEGIN(fchown);
2023
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2024
2
             uv_fs_fchown, fd, uid, gid);
2025

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

4
    FS_SYNC_TRACE_BEGIN(lchown);
2053
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2054
4
             uv_fs_lchown, *path, uid, gid);
2055

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

17
    FS_SYNC_TRACE_BEGIN(utimes);
2083
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2084
30
             uv_fs_utime, *path, atime, mtime);
2085

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

10
    FS_SYNC_TRACE_BEGIN(futimes);
2112
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2113
8
             uv_fs_futime, fd, atime, mtime);
2114

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

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2138
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2139
14
             uv_fs_mkdtemp, *tmpl);
2140

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

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

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