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: 1525 1613 94.5 %
Date: 2020-12-12 04:11:07 Branches: 800 1220 65.6 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
#include "node_file.h"  // NOLINT(build/include_inline)
22
#include "node_file-inl.h"
23
#include "aliased_buffer.h"
24
#include "memory_tracker-inl.h"
25
#include "node_buffer.h"
26
#include "node_process.h"
27
#include "node_stat_watcher.h"
28
#include "util-inl.h"
29
30
#include "tracing/trace_event.h"
31
32
#include "req_wrap-inl.h"
33
#include "stream_base-inl.h"
34
#include "string_bytes.h"
35
36
#include <fcntl.h>
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <cstring>
40
#include <cerrno>
41
#include <climits>
42
43
#if defined(__MINGW32__) || defined(_MSC_VER)
44
# include <io.h>
45
#endif
46
47
#include <memory>
48
49
namespace node {
50
51
namespace fs {
52
53
using v8::Array;
54
using v8::Boolean;
55
using v8::Context;
56
using v8::EscapableHandleScope;
57
using v8::Function;
58
using v8::FunctionCallbackInfo;
59
using v8::FunctionTemplate;
60
using v8::HandleScope;
61
using v8::Int32;
62
using v8::Integer;
63
using v8::Isolate;
64
using v8::Local;
65
using v8::MaybeLocal;
66
using v8::Number;
67
using v8::Object;
68
using v8::ObjectTemplate;
69
using v8::Promise;
70
using v8::String;
71
using v8::Symbol;
72
using v8::Uint32;
73
using v8::Undefined;
74
using v8::Value;
75
76
#ifndef S_ISDIR
77
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
78
#endif
79
80
#ifdef __POSIX__
81
constexpr char kPathSeparator = '/';
82
#else
83
const char* const kPathSeparator = "\\/";
84
#endif
85
86
10
std::string Basename(const std::string& str, const std::string& extension) {
87
  // Remove everything leading up to and including the final path separator.
88
10
  std::string::size_type pos = str.find_last_of(kPathSeparator);
89
90
  // Starting index for the resulting string
91
10
  std::size_t start_pos = 0;
92
  // String size to return
93
10
  std::size_t str_size = str.size();
94
10
  if (pos != std::string::npos) {
95
10
    start_pos = pos + 1;
96
10
    str_size -= start_pos;
97
  }
98
99
  // Strip away the extension, if any.
100

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

2578
  if (obj.IsEmpty() && !env->fd_constructor_template()
161
1926
                            ->NewInstance(env->context())
162
637
                            .ToLocal(&obj)) {
163
    return nullptr;
164
  }
165
652
  return new FileHandle(binding_data, obj, fd);
166
}
167
168
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
169
15
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
170
15
  Environment* env = binding_data->env();
171
15
  CHECK(args.IsConstructCall());
172
30
  CHECK(args[0]->IsInt32());
173
174
  FileHandle* handle =
175
45
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
176
15
  if (handle == nullptr) return;
177
30
  if (args[1]->IsNumber())
178
60
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
179
30
  if (args[2]->IsNumber())
180
60
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
181
}
182
183
1905
FileHandle::~FileHandle() {
184
635
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
185
635
  Close();           // Close synchronously and emit warning
186
635
  CHECK(closed_);    // We have to be closed at the point
187
1270
}
188
189
int FileHandle::DoWrite(WriteWrap* w,
190
                        uv_buf_t* bufs,
191
                        size_t count,
192
                        uv_stream_t* send_handle) {
193
  return UV_ENOSYS;  // Not implemented (yet).
194
}
195
196
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
197
  tracker->TrackField("current_read", current_read_);
198
}
199
200
10
FileHandle::TransferMode FileHandle::GetTransferMode() const {
201

10
  return reading_ || closing_ || closed_ ?
202
10
      TransferMode::kUntransferable : TransferMode::kTransferable;
203
}
204
205
6
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
206
6
  CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
207
12
  auto ret = std::make_unique<TransferData>(fd_);
208
6
  closed_ = true;
209
12
  return ret;
210
}
211
212
6
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
213
214
18
FileHandle::TransferData::~TransferData() {
215
6
  if (fd_ > 0) {
216
    uv_fs_t close_req;
217
4
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
218
4
    uv_fs_req_cleanup(&close_req);
219
  }
220
12
}
221
222
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
223
    Environment* env,
224
    v8::Local<v8::Context> context,
225
    std::unique_ptr<worker::TransferData> self) {
226
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
227
2
  if (bd == nullptr) return {};
228
229
2
  int fd = fd_;
230
2
  fd_ = -1;
231
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
232
}
233
234
// Close the file descriptor if it hasn't already been closed. A process
235
// warning will be emitted using a SetImmediate to avoid calling back to
236
// JS during GC. If closing the fd fails at this point, a fatal exception
237
// will crash the process immediately.
238
635
inline void FileHandle::Close() {
239
1258
  if (closed_) return;
240
  uv_fs_t req;
241
12
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
242
12
  uv_fs_req_cleanup(&req);
243
244
  struct err_detail { int ret; int fd; };
245
246
12
  err_detail detail { ret, fd_ };
247
248
12
  AfterClose();
249
250
12
  if (ret < 0) {
251
    // Do not unref this
252
    env()->SetImmediate([detail](Environment* env) {
253
      char msg[70];
254
      snprintf(msg, arraysize(msg),
255
              "Closing file descriptor %d on garbage collection failed",
256
              detail.fd);
257
      // This exception will end up being fatal for the process because
258
      // it is being thrown from within the SetImmediate handler and
259
      // there is no JS stack to bubble it to. In other words, tearing
260
      // down the process is the only reasonable thing we can do here.
261
      HandleScope handle_scope(env->isolate());
262
      env->ThrowUVException(detail.ret, "close", msg);
263
    });
264
    return;
265
  }
266
267
  // If the close was successful, we still want to emit a process warning
268
  // to notify that the file descriptor was gc'd. We want to be noisy about
269
  // this because not explicitly closing the FileHandle is a bug.
270
271
26
  env()->SetImmediate([detail](Environment* env) {
272
    ProcessEmitWarning(env,
273
                       "Closing file descriptor %d on garbage collection",
274
2
                       detail.fd);
275
2
    if (env->filehandle_close_warning()) {
276
2
      env->set_filehandle_close_warning(false);
277
4
      ProcessEmitDeprecationWarning(
278
          env,
279
          "Closing a FileHandle object on garbage collection is deprecated. "
280
          "Please close FileHandle objects explicitly using "
281
          "FileHandle.prototype.close(). In the future, an error will be "
282
          "thrown if a file descriptor is closed during garbage collection.",
283
          "DEP0137").IsNothing();
284
    }
285
14
  }, CallbackFlags::kUnrefed);
286
}
287
288
625
void FileHandle::CloseReq::Resolve() {
289
625
  Isolate* isolate = env()->isolate();
290
1233
  HandleScope scope(isolate);
291
625
  Context::Scope context_scope(env()->context());
292
1250
  InternalCallbackScope callback_scope(this);
293
1250
  Local<Promise> promise = promise_.Get(isolate);
294
625
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
295
1875
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
296
608
}
297
298
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
299
1
  Isolate* isolate = env()->isolate();
300
2
  HandleScope scope(isolate);
301
1
  Context::Scope context_scope(env()->context());
302
2
  InternalCallbackScope callback_scope(this);
303
2
  Local<Promise> promise = promise_.Get(isolate);
304
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
305
3
  resolver->Reject(env()->context(), reason).Check();
306
1
}
307
308
626
FileHandle* FileHandle::CloseReq::file_handle() {
309
626
  Isolate* isolate = env()->isolate();
310
1252
  HandleScope scope(isolate);
311
1252
  Local<Value> val = ref_.Get(isolate);
312
626
  Local<Object> obj = val.As<Object>();
313
1252
  return Unwrap<FileHandle>(obj);
314
}
315
316
626
FileHandle::CloseReq::CloseReq(Environment* env,
317
                               Local<Object> obj,
318
                               Local<Promise> promise,
319
626
                               Local<Value> ref)
320
1252
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
321
626
  promise_.Reset(env->isolate(), promise);
322
626
  ref_.Reset(env->isolate(), ref);
323
626
}
324
325
3045
FileHandle::CloseReq::~CloseReq() {
326
609
  uv_fs_req_cleanup(req());
327
609
  promise_.Reset();
328
609
  ref_.Reset();
329
1218
}
330
331
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
332
  tracker->TrackField("promise", promise_);
333
  tracker->TrackField("ref", ref_);
334
}
335
336
337
338
// Closes this FileHandle asynchronously and returns a Promise that will be
339
// resolved when the callback is invoked, or rejects with a UVException if
340
// there was a problem closing the fd. This is the preferred mechanism for
341
// closing the FD object even tho the object will attempt to close
342
// automatically on gc.
343
626
MaybeLocal<Promise> FileHandle::ClosePromise() {
344
626
  Isolate* isolate = env()->isolate();
345
626
  EscapableHandleScope scope(isolate);
346
626
  Local<Context> context = env()->context();
347
626
  auto maybe_resolver = Promise::Resolver::New(context);
348
626
  CHECK(!maybe_resolver.IsEmpty());
349
626
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
350
626
  Local<Promise> promise = resolver.As<Promise>();
351
626
  CHECK(!reading_);
352

626
  if (!closed_ && !closing_) {
353
626
    closing_ = true;
354
    Local<Object> close_req_obj;
355
1252
    if (!env()
356
1252
             ->fdclose_constructor_template()
357
1878
             ->NewInstance(env()->context())
358
626
             .ToLocal(&close_req_obj)) {
359
      return MaybeLocal<Promise>();
360
    }
361
1252
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
362
1878
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
363
1235
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
364
626
      CHECK_NOT_NULL(close);
365
626
      close->file_handle()->AfterClose();
366
626
      Isolate* isolate = close->env()->isolate();
367
626
      if (req->result < 0) {
368
2
        HandleScope handle_scope(isolate);
369
1
        close->Reject(UVException(isolate, req->result, "close"));
370
      } else {
371
625
        close->Resolve();
372
      }
373
2487
    }};
374
626
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
375
626
    if (ret < 0) {
376
      req->Reject(UVException(isolate, ret, "close"));
377
      delete req;
378
626
    }
379
  } else {
380
    // Already closed. Just reject the promise immediately
381
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
382
        .Check();
383
  }
384
626
  return scope.Escape(promise);
385
}
386
387
626
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
388
  FileHandle* fd;
389
626
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
390
  Local<Promise> ret;
391
1252
  if (!fd->ClosePromise().ToLocal(&ret)) return;
392
1252
  args.GetReturnValue().Set(ret);
393
}
394
395
396
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
397
  FileHandle* fd;
398
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
399
  // Just act as if this FileHandle has been closed.
400
8
  fd->AfterClose();
401
}
402
403
404
646
void FileHandle::AfterClose() {
405
646
  closing_ = false;
406
646
  closed_ = true;
407
646
  fd_ = -1;
408

646
  if (reading_ && !persistent().IsEmpty())
409
    EmitRead(UV_EOF);
410
646
}
411
412
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
413
  tracker->TrackField("buffer", buffer_);
414
  tracker->TrackField("file_handle", this->file_handle_);
415
}
416
417
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
418
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
419
15
    file_handle_(handle) {}
420
421
212
int FileHandle::ReadStart() {
422

212
  if (!IsAlive() || IsClosing())
423
    return UV_EOF;
424
425
212
  reading_ = true;
426
427
212
  if (current_read_)
428
    return 0;
429
430
424
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
431
432
212
  if (read_length_ == 0) {
433
5
    EmitRead(UV_EOF);
434
5
    return 0;
435
  }
436
437
  {
438
    // Create a new FileHandleReadWrap or re-use one.
439
    // Either way, we need these two scopes for AsyncReset() or otherwise
440
    // for creating the new instance.
441
414
    HandleScope handle_scope(env()->isolate());
442
414
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
443
444
207
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
445
207
    if (freelist.size() > 0) {
446
192
      read_wrap = std::move(freelist.back());
447
192
      freelist.pop_back();
448
      // Use a fresh async resource.
449
      // Lifetime is ensured via AsyncWrap::resource_.
450
192
      Local<Object> resource = Object::New(env()->isolate());
451
384
      USE(resource->Set(
452
1152
          env()->context(), env()->handle_string(), read_wrap->object()));
453
192
      read_wrap->AsyncReset(resource);
454
192
      read_wrap->file_handle_ = this;
455
    } else {
456
      Local<Object> wrap_obj;
457
30
      if (!env()
458
30
               ->filehandlereadwrap_template()
459
45
               ->NewInstance(env()->context())
460
15
               .ToLocal(&wrap_obj)) {
461
        return UV_EBUSY;
462
      }
463
15
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
464
    }
465
  }
466
207
  int64_t recommended_read = 65536;
467

207
  if (read_length_ >= 0 && read_length_ <= recommended_read)
468
7
    recommended_read = read_length_;
469
470
207
  read_wrap->buffer_ = EmitAlloc(recommended_read);
471
472
207
  current_read_ = std::move(read_wrap);
473
474
414
  current_read_->Dispatch(uv_fs_read,
475
                          fd_,
476
207
                          &current_read_->buffer_,
477
                          1,
478
                          read_offset_,
479
621
                          uv_fs_callback_t{[](uv_fs_t* req) {
480
    FileHandle* handle;
481
    {
482
207
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
483
207
      handle = req_wrap->file_handle_;
484
207
      CHECK_EQ(handle->current_read_.get(), req_wrap);
485
    }
486
487
    // ReadStart() checks whether current_read_ is set to determine whether
488
    // a read is in progress. Moving it into a local variable makes sure that
489
    // the ReadStart() call below doesn't think we're still actively reading.
490
    BaseObjectPtr<FileHandleReadWrap> read_wrap =
491
414
        std::move(handle->current_read_);
492
493
207
    int result = req->result;
494
207
    uv_buf_t buffer = read_wrap->buffer_;
495
496
207
    uv_fs_req_cleanup(req);
497
498
    // Push the read wrap back to the freelist, or let it be destroyed
499
    // once we’re exiting the current scope.
500
207
    constexpr size_t kWantedFreelistFill = 100;
501
207
    auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
502
207
    if (freelist.size() < kWantedFreelistFill) {
503
207
      read_wrap->Reset();
504
207
      freelist.emplace_back(std::move(read_wrap));
505
    }
506
507
207
    if (result >= 0) {
508
      // Read at most as many bytes as we originally planned to.
509

206
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
510
        result = handle->read_length_;
511
512
      // If we read data and we have an expected length, decrease it by
513
      // how much we have read.
514
206
      if (handle->read_length_ >= 0)
515
9
        handle->read_length_ -= result;
516
517
      // If we have an offset, increase it by how much we have read.
518
206
      if (handle->read_offset_ >= 0)
519
204
        handle->read_offset_ += result;
520
    }
521
522
    // Reading 0 bytes from a file always means EOF, or that we reached
523
    // the end of the requested range.
524
207
    if (result == 0)
525
7
      result = UV_EOF;
526
527
207
    handle->EmitRead(result, buffer);
528
529
    // Start over, if EmitRead() didn’t tell us to stop.
530
207
    if (handle->reading_)
531
      handle->ReadStart();
532
828
  }});
533
534
207
  return 0;
535
}
536
537
227
int FileHandle::ReadStop() {
538
227
  reading_ = false;
539
227
  return 0;
540
}
541
542
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
543
544
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
545
  return new FileHandleCloseWrap(this, object);
546
}
547
548
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
549
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
550
  closing_ = true;
551
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
552
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
553
        FileHandleCloseWrap::from_req(req));
554
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
555
    handle->AfterClose();
556
557
    int result = req->result;
558
    uv_fs_req_cleanup(req);
559
    wrap->Done(result);
560
  }});
561
562
  return 0;
563
}
564
565
566
3923
void FSReqCallback::Reject(Local<Value> reject) {
567
3923
  MakeCallback(env()->oncomplete_string(), 1, &reject);
568
3923
}
569
570
3155
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
571
3155
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
572
3155
}
573
574
46606
void FSReqCallback::Resolve(Local<Value> value) {
575
  Local<Value> argv[2] {
576
    Null(env()->isolate()),
577
    value
578
93212
  };
579
  MakeCallback(env()->oncomplete_string(),
580
131031
               value->IsUndefined() ? 1 : arraysize(argv),
581
84425
               argv);
582
46602
}
583
584
50529
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
585
101058
  args.GetReturnValue().SetUndefined();
586
50529
}
587
588
50529
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
589
50529
  CHECK(args.IsConstructCall());
590
50529
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
591
151587
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
592
50529
}
593
594
53357
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
595
    : wrap_(wrap),
596
      req_(req),
597
      handle_scope_(wrap->env()->isolate()),
598
53357
      context_scope_(wrap->env()->context()) {
599
53357
  CHECK_EQ(wrap_->req(), req);
600
53357
}
601
602
160059
FSReqAfterScope::~FSReqAfterScope() {
603
53353
  Clear();
604
53353
}
605
606
57499
void FSReqAfterScope::Clear() {
607
57499
  if (!wrap_) return;
608
609
53353
  uv_fs_req_cleanup(wrap_->req());
610
53353
  wrap_->Detach();
611
53353
  wrap_.reset();
612
}
613
614
// TODO(joyeecheung): create a normal context object, and
615
// construct the actual errors in the JS land using the context.
616
// The context should include fds for some fs APIs, currently they are
617
// missing in the error messages. The path, dest, syscall, fd, .etc
618
// can be put into the context before the binding is even invoked,
619
// the only information that has to come from the C++ layer is the
620
// error number (and possibly the syscall for abstraction),
621
// which is also why the errors should have been constructed
622
// in JS for more flexibility.
623
4135
void FSReqAfterScope::Reject(uv_fs_t* req) {
624
8270
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
625
  Local<Value> exception =
626
4135
      UVException(wrap_->env()->isolate(),
627
4135
                  req->result,
628
                  wrap_->syscall(),
629
                  nullptr,
630
                  req->path,
631
12405
                  wrap_->data());
632
4135
  Clear();
633
4135
  wrap->Reject(exception);
634
4135
}
635
636
53357
bool FSReqAfterScope::Proceed() {
637
53357
  if (req_->result < 0) {
638
4135
    Reject(req_);
639
4135
    return false;
640
  }
641
49222
  return true;
642
}
643
644
8717
void AfterNoArgs(uv_fs_t* req) {
645
8717
  FSReqBase* req_wrap = FSReqBase::from_req(req);
646
17431
  FSReqAfterScope after(req_wrap, req);
647
648
8717
  if (after.Proceed())
649
16962
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
650
8714
}
651
652
7443
void AfterStat(uv_fs_t* req) {
653
7443
  FSReqBase* req_wrap = FSReqBase::from_req(req);
654
14886
  FSReqAfterScope after(req_wrap, req);
655
656
7443
  if (after.Proceed()) {
657
3820
    req_wrap->ResolveStat(&req->statbuf);
658
  }
659
7443
}
660
661
35567
void AfterInteger(uv_fs_t* req) {
662
35567
  FSReqBase* req_wrap = FSReqBase::from_req(req);
663
71134
  FSReqAfterScope after(req_wrap, req);
664
665

35567
  if (req->result >= 0 && req_wrap->is_plain_open())
666
5140
    req_wrap->env()->AddUnmanagedFd(req->result);
667
668
35567
  if (after.Proceed())
669
70686
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
670
35567
}
671
672
663
void AfterOpenFileHandle(uv_fs_t* req) {
673
663
  FSReqBase* req_wrap = FSReqBase::from_req(req);
674
1326
  FSReqAfterScope after(req_wrap, req);
675
676
663
  if (after.Proceed()) {
677
634
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(), req->result);
678
634
    if (fd == nullptr) return;
679
1268
    req_wrap->Resolve(fd->object());
680
  }
681
}
682
683
// Reverse the logic applied by path.toNamespacedPath() to create a
684
// namespace-prefixed path.
685
486
void FromNamespacedPath(std::string* path) {
686
#ifdef _WIN32
687
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
688
    *path = path->substr(8);
689
    path->insert(0, "\\\\");
690
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
691
    *path = path->substr(4);
692
  }
693
#endif
694
486
}
695
696
621
void AfterMkdirp(uv_fs_t* req) {
697
621
  FSReqBase* req_wrap = FSReqBase::from_req(req);
698
1242
  FSReqAfterScope after(req_wrap, req);
699
700
  MaybeLocal<Value> path;
701
  Local<Value> error;
702
703
621
  if (after.Proceed()) {
704
615
    if (!req_wrap->continuation_data()->first_path().empty()) {
705
518
      std::string first_path(req_wrap->continuation_data()->first_path());
706
259
      FromNamespacedPath(&first_path);
707
      path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
708
                                 req_wrap->encoding(),
709
259
                                 &error);
710
259
      if (path.IsEmpty())
711
        req_wrap->Reject(error);
712
      else
713
518
        req_wrap->Resolve(path.ToLocalChecked());
714
    } else {
715
712
      req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
716
    }
717
  }
718
621
}
719
720
6
void AfterStringPath(uv_fs_t* req) {
721
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
722
12
  FSReqAfterScope after(req_wrap, req);
723
724
  MaybeLocal<Value> link;
725
  Local<Value> error;
726
727
6
  if (after.Proceed()) {
728
    link = StringBytes::Encode(req_wrap->env()->isolate(),
729
                               req->path,
730
                               req_wrap->encoding(),
731
5
                               &error);
732
5
    if (link.IsEmpty())
733
      req_wrap->Reject(error);
734
    else
735
10
      req_wrap->Resolve(link.ToLocalChecked());
736
  }
737
6
}
738
739
56
void AfterStringPtr(uv_fs_t* req) {
740
56
  FSReqBase* req_wrap = FSReqBase::from_req(req);
741
111
  FSReqAfterScope after(req_wrap, req);
742
743
  MaybeLocal<Value> link;
744
  Local<Value> error;
745
746
56
  if (after.Proceed()) {
747
    link = StringBytes::Encode(req_wrap->env()->isolate(),
748
51
                               static_cast<const char*>(req->ptr),
749
                               req_wrap->encoding(),
750
102
                               &error);
751
51
    if (link.IsEmpty())
752
      req_wrap->Reject(error);
753
    else
754
102
      req_wrap->Resolve(link.ToLocalChecked());
755
  }
756
55
}
757
758
89
void AfterScanDir(uv_fs_t* req) {
759
89
  FSReqBase* req_wrap = FSReqBase::from_req(req);
760
169
  FSReqAfterScope after(req_wrap, req);
761
762
89
  if (!after.Proceed()) {
763
9
    return;
764
  }
765
80
  Environment* env = req_wrap->env();
766
  Local<Value> error;
767
  int r;
768
160
  std::vector<Local<Value>> name_v;
769
770
  for (;;) {
771
    uv_dirent_t ent;
772
773
7079
    r = uv_fs_scandir_next(req, &ent);
774
7079
    if (r == UV_EOF)
775
80
      break;
776
6999
    if (r != 0) {
777
      return req_wrap->Reject(UVException(
778
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
779
    }
780
781
    MaybeLocal<Value> filename =
782
      StringBytes::Encode(env->isolate(),
783
          ent.name,
784
          req_wrap->encoding(),
785
6999
          &error);
786
6999
    if (filename.IsEmpty())
787
      return req_wrap->Reject(error);
788
789
6999
    name_v.push_back(filename.ToLocalChecked());
790
6999
  }
791
792
160
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
793
}
794
795
163
void AfterScanDirWithTypes(uv_fs_t* req) {
796
163
  FSReqBase* req_wrap = FSReqBase::from_req(req);
797
325
  FSReqAfterScope after(req_wrap, req);
798
799
163
  if (!after.Proceed()) {
800
1
    return;
801
  }
802
803
162
  Environment* env = req_wrap->env();
804
162
  Isolate* isolate = env->isolate();
805
  Local<Value> error;
806
  int r;
807
808
324
  std::vector<Local<Value>> name_v;
809
324
  std::vector<Local<Value>> type_v;
810
811
  for (;;) {
812
    uv_dirent_t ent;
813
814
179
    r = uv_fs_scandir_next(req, &ent);
815
179
    if (r == UV_EOF)
816
162
      break;
817
17
    if (r != 0) {
818
      return req_wrap->Reject(
819
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
820
    }
821
822
    MaybeLocal<Value> filename =
823
      StringBytes::Encode(isolate,
824
          ent.name,
825
          req_wrap->encoding(),
826
17
          &error);
827
17
    if (filename.IsEmpty())
828
      return req_wrap->Reject(error);
829
830
17
    name_v.push_back(filename.ToLocalChecked());
831
17
    type_v.emplace_back(Integer::New(isolate, ent.type));
832
17
  }
833
834
  Local<Value> result[] = {
835
    Array::New(isolate, name_v.data(), name_v.size()),
836
    Array::New(isolate, type_v.data(), type_v.size())
837
486
  };
838
324
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
839
}
840
841
260
void Access(const FunctionCallbackInfo<Value>& args) {
842
260
  Environment* env = Environment::GetCurrent(args);
843
260
  Isolate* isolate = env->isolate();
844
520
  HandleScope scope(isolate);
845
846
260
  const int argc = args.Length();
847
260
  CHECK_GE(argc, 2);
848
849
520
  CHECK(args[1]->IsInt32());
850
780
  int mode = args[1].As<Int32>()->Value();
851
852
520
  BufferValue path(isolate, args[0]);
853
260
  CHECK_NOT_NULL(*path);
854
855
260
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
856
260
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
857
41
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
858
41
              uv_fs_access, *path, mode);
859
  } else {  // access(path, mode, undefined, ctx)
860
219
    CHECK_EQ(argc, 4);
861
438
    FSReqWrapSync req_wrap_sync;
862
219
    FS_SYNC_TRACE_BEGIN(access);
863
438
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
864
220
    FS_SYNC_TRACE_END(access);
865
1
  }
866
262
}
867

3
868
2
869
51795
void Close(const FunctionCallbackInfo<Value>& args) {
870
51795
  Environment* env = Environment::GetCurrent(args);
871
872
51794
  const int argc = args.Length();
873
51793
  CHECK_GE(argc, 2);
874
875
103586
  CHECK(args[0]->IsInt32());
876
155379
  int fd = args[0].As<Int32>()->Value();
877
51793
  env->RemoveUnmanagedFd(fd);
878
879
51793
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
880
51793
  if (req_wrap_async != nullptr) {  // close(fd, req)
881
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
882
5074
              uv_fs_close, fd);
883
  } else {  // close(fd, undefined, ctx)
884
46719
    CHECK_EQ(argc, 3);
885
93438
    FSReqWrapSync req_wrap_sync;
886
46719
    FS_SYNC_TRACE_BEGIN(close);
887
46719
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
888
46749
    FS_SYNC_TRACE_END(close);
889
30
  }
890
51849
}
891

90
892
56
893
60
// Used to speed up module loading. Returns an array [string, boolean]
894
55866
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
895
55806
  Environment* env = Environment::GetCurrent(args);
896
55836
  Isolate* isolate = env->isolate();
897
55806
  uv_loop_t* loop = env->event_loop();
898
899
167418
  CHECK(args[0]->IsString());
900
61635
  node::Utf8Value path(isolate, args[0]);
901
902
55806
  if (strlen(*path) != path.length()) {
903
9
    args.GetReturnValue().Set(Array::New(isolate));
904
3
    return;  // Contains a nul byte.
905
  }
906
  uv_fs_t open_req;
907
55803
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
908
55803
  uv_fs_req_cleanup(&open_req);
909
910
55803
  if (fd < 0) {
911
149919
    args.GetReturnValue().Set(Array::New(isolate));
912
49973
    return;
913
  }
914
915
5830
  auto defer_close = OnScopeLeave([fd, loop]() {
916
    uv_fs_t close_req;
917
5830
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
918
5830
    uv_fs_req_cleanup(&close_req);
919
17489
  });
920
921
5830
  const size_t kBlockSize = 32 << 10;
922
11659
  std::vector<char> chars;
923
5830
  int64_t offset = 0;
924
  ssize_t numchars;
925
  do {
926
5830
    const size_t start = chars.size();
927
5830
    chars.resize(start + kBlockSize);
928
929
    uv_buf_t buf;
930
5830
    buf.base = &chars[start];
931
5830
    buf.len = kBlockSize;
932
933
    uv_fs_t read_req;
934
5830
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
935
5830
    uv_fs_req_cleanup(&read_req);
936
937
5830
    if (numchars < 0) {
938
3
      args.GetReturnValue().Set(Array::New(isolate));
939
1
      return;
940
    }
941
5829
    offset += numchars;
942
5829
  } while (static_cast<size_t>(numchars) == kBlockSize);
943
944
5829
  size_t start = 0;
945

5829
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
946
1
    start = 3;  // Skip UTF-8 BOM.
947
  }
948
949
5829
  const size_t size = offset - start;
950
5829
  char* p = &chars[start];
951
5829
  char* pe = &chars[size];
952
  char* pos[2];
953
5829
  char** ppos = &pos[0];
954
955
330293
  while (p < pe) {
956
168049
    char c = *p++;
957

168049
    if (c == '\\' && p < pe && *p == '"') p++;
958
168049
    if (c != '"') continue;
959
22710
    *ppos++ = p;
960
22710
    if (ppos < &pos[2]) continue;
961
11355
    ppos = &pos[0];
962
963
11355
    char* s = &pos[0][0];
964
11355
    char* se = &pos[1][-1];  // Exclude quote.
965
11355
    size_t n = se - s;
966
967
11355
    if (n == 4) {
968
6167
      if (0 == memcmp(s, "main", 4)) break;
969
6027
      if (0 == memcmp(s, "name", 4)) break;
970
380
      if (0 == memcmp(s, "type", 4)) break;
971
5188
    } else if (n == 7) {
972
523
      if (0 == memcmp(s, "exports", 7)) break;
973
517
      if (0 == memcmp(s, "imports", 7)) break;
974
    }
975
  }
976
977
978
  Local<Value> return_value[] = {
979
11658
    String::NewFromUtf8(isolate,
980
5829
                        &chars[start],
981
                        v8::NewStringType::kNormal,
982
5829
                        size).ToLocalChecked(),
983
    Boolean::New(isolate, p < pe ? true : false)
984
17487
  };
985
17487
  args.GetReturnValue().Set(
986
    Array::New(isolate, return_value, arraysize(return_value)));
987
}
988
989
// Used to speed up module loading.  Returns 0 if the path refers to
990
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
991
// The speedup comes from not creating thousands of Stat and Error objects.
992
123043
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
993
123043
  Environment* env = Environment::GetCurrent(args);
994
995
369129
  CHECK(args[0]->IsString());
996
246086
  node::Utf8Value path(env->isolate(), args[0]);
997
998
  uv_fs_t req;
999
123043
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1000
123043
  if (rc == 0) {
1001
65585
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1002
65585
    rc = !!(s->st_mode & S_IFDIR);
1003
  }
1004
123043
  uv_fs_req_cleanup(&req);
1005
1006
246086
  args.GetReturnValue().Set(rc);
1007
123043
}
1008
1009
16444
static void Stat(const FunctionCallbackInfo<Value>& args) {
1010
16444
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1011
16444
  Environment* env = binding_data->env();
1012
1013
16444
  const int argc = args.Length();
1014
16444
  CHECK_GE(argc, 2);
1015
1016
32341
  BufferValue path(env->isolate(), args[0]);
1017
16444
  CHECK_NOT_NULL(*path);
1018
1019
32888
  bool use_bigint = args[1]->IsTrue();
1020
16444
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1021
16444
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1022
2596
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1023
2596
              uv_fs_stat, *path);
1024
  } else {  // stat(path, use_bigint, undefined, ctx)
1025
13848
    CHECK_EQ(argc, 4);
1026
27149
    FSReqWrapSync req_wrap_sync;
1027
13848
    FS_SYNC_TRACE_BEGIN(stat);
1028
27696
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1029
13849
    FS_SYNC_TRACE_END(stat);
1030

13849
    if (err != 0) {
1031
549
      return;  // error info is in ctx
1032

4
    }
1033
2
1034
3
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1035
13303
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1036
26602
    args.GetReturnValue().Set(arr);
1037
1
  }
1038
}
1039
1040
108101
static void LStat(const FunctionCallbackInfo<Value>& args) {
1041
108101
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1042
108101
  Environment* env = binding_data->env();
1043
1044
108101
  const int argc = args.Length();
1045
108101
  CHECK_GE(argc, 3);
1046
1047
215891
  BufferValue path(env->isolate(), args[0]);
1048
108101
  CHECK_NOT_NULL(*path);
1049
1050
216202
  bool use_bigint = args[1]->IsTrue();
1051
108101
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1052
108099
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1053
3936
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1054
3936
              uv_fs_lstat, *path);
1055
  } else {  // lstat(path, use_bigint, undefined, ctx)
1056
104163
    CHECK_EQ(argc, 4);
1057
208017
    FSReqWrapSync req_wrap_sync;
1058
104164
    FS_SYNC_TRACE_BEGIN(lstat);
1059
104165
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1060
104182
                       *path);
1061

104182
    FS_SYNC_TRACE_END(lstat);
1062
104167
    if (err != 0) {
1063
364
      return;  // error info is in ctx
1064
34
    }
1065
2
1066
53
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1067
103871
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1068
207706
    args.GetReturnValue().Set(arr);
1069
17
  }
1070
}
1071
1072
42465
static void FStat(const FunctionCallbackInfo<Value>& args) {
1073
42465
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1074
42465
  Environment* env = binding_data->env();
1075
1076
42465
  const int argc = args.Length();
1077
42465
  CHECK_GE(argc, 2);
1078
1079
84930
  CHECK(args[0]->IsInt32());
1080
127395
  int fd = args[0].As<Int32>()->Value();
1081
1082
84930
  bool use_bigint = args[1]->IsTrue();
1083
42465
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1084
42465
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1085
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1086
911
              uv_fs_fstat, fd);
1087
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1088
41554
    CHECK_EQ(argc, 4);
1089
83087
    FSReqWrapSync req_wrap_sync;
1090
41554
    FS_SYNC_TRACE_BEGIN(fstat);
1091
41554
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1092
41559
    FS_SYNC_TRACE_END(fstat);
1093

41559
    if (err != 0) {
1094
29
      return;  // error info is in ctx
1095

18
    }
1096
8
1097
13
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1098
41543
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1099
83066
    args.GetReturnValue().Set(arr);
1100
5
  }
1101
}
1102
1103
331
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1104
331
  Environment* env = Environment::GetCurrent(args);
1105
331
  Isolate* isolate = env->isolate();
1106
1107
331
  const int argc = args.Length();
1108
331
  CHECK_GE(argc, 4);
1109
1110
662
  BufferValue target(isolate, args[0]);
1111
331
  CHECK_NOT_NULL(*target);
1112
662
  BufferValue path(isolate, args[1]);
1113
331
  CHECK_NOT_NULL(*path);
1114
1115
662
  CHECK(args[2]->IsInt32());
1116
993
  int flags = args[2].As<Int32>()->Value();
1117
1118
331
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1119
331
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1120
25
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1121
25
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1122
  } else {  // symlink(target, path, flags, undefinec, ctx)
1123
306
    CHECK_EQ(argc, 5);
1124
612
    FSReqWrapSync req_wrap_sync;
1125
306
    FS_SYNC_TRACE_BEGIN(symlink);
1126
306
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1127
308
             uv_fs_symlink, *target, *path, flags);
1128

308
    FS_SYNC_TRACE_END(symlink);
1129
2
  }
1130
339
}
1131
4
1132
74
static void Link(const FunctionCallbackInfo<Value>& args) {
1133
80
  Environment* env = Environment::GetCurrent(args);
1134
74
  Isolate* isolate = env->isolate();
1135
1136
74
  const int argc = args.Length();
1137
72
  CHECK_GE(argc, 3);
1138
1139
144
  BufferValue src(isolate, args[0]);
1140
72
  CHECK_NOT_NULL(*src);
1141
1142
144
  BufferValue dest(isolate, args[1]);
1143
72
  CHECK_NOT_NULL(*dest);
1144
1145
72
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1146
72
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1147
67
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1148
67
                  AfterNoArgs, uv_fs_link, *src, *dest);
1149
  } else {  // link(src, dest)
1150
5
    CHECK_EQ(argc, 4);
1151
10
    FSReqWrapSync req_wrap_sync;
1152
5
    FS_SYNC_TRACE_BEGIN(link);
1153
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1154
8
             uv_fs_link, *src, *dest);
1155

8
    FS_SYNC_TRACE_END(link);
1156
3
  }
1157
84
}
1158
6
1159
85
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1160
94
  Environment* env = Environment::GetCurrent(args);
1161
85
  Isolate* isolate = env->isolate();
1162
1163
85
  const int argc = args.Length();
1164
82
  CHECK_GE(argc, 3);
1165
1166
163
  BufferValue path(isolate, args[0]);
1167
82
  CHECK_NOT_NULL(*path);
1168
1169
82
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1170
1171
82
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1172
82
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1173
34
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1174
34
              uv_fs_readlink, *path);
1175
  } else {
1176
48
    CHECK_EQ(argc, 4);
1177
95
    FSReqWrapSync req_wrap_sync;
1178
48
    FS_SYNC_TRACE_BEGIN(readlink);
1179
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1180
49
                       uv_fs_readlink, *path);
1181

49
    FS_SYNC_TRACE_END(readlink);
1182
49
    if (err < 0) {
1183
5
      return;  // syscall failed, no need to continue, error info is in ctx
1184
2
    }
1185
48
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1186
4
1187
1
    Local<Value> error;
1188
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1189
1
                                               link_path,
1190
                                               encoding,
1191
47
                                               &error);
1192
47
    if (rc.IsEmpty()) {
1193
      Local<Object> ctx = args[3].As<Object>();
1194
      ctx->Set(env->context(), env->error_string(), error).Check();
1195
      return;
1196
    }
1197
1198
94
    args.GetReturnValue().Set(rc.ToLocalChecked());
1199
  }
1200
}
1201
1202
6
static void Rename(const FunctionCallbackInfo<Value>& args) {
1203
6
  Environment* env = Environment::GetCurrent(args);
1204
6
  Isolate* isolate = env->isolate();
1205
1206
6
  const int argc = args.Length();
1207
6
  CHECK_GE(argc, 3);
1208
1209
12
  BufferValue old_path(isolate, args[0]);
1210
6
  CHECK_NOT_NULL(*old_path);
1211
12
  BufferValue new_path(isolate, args[1]);
1212
6
  CHECK_NOT_NULL(*new_path);
1213
1214
6
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1215
6
  if (req_wrap_async != nullptr) {
1216
3
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1217
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1218
3
                  *old_path, *new_path);
1219
  } else {
1220
3
    CHECK_EQ(argc, 4);
1221
6
    FSReqWrapSync req_wrap_sync;
1222
3
    FS_SYNC_TRACE_BEGIN(rename);
1223
3
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1224
4
             *old_path, *new_path);
1225

4
    FS_SYNC_TRACE_END(rename);
1226
1
  }
1227
10
}
1228
2
1229
59
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1230
62
  Environment* env = Environment::GetCurrent(args);
1231
1
1232
58
  const int argc = args.Length();
1233
59
  CHECK_GE(argc, 3);
1234
1235
116
  CHECK(args[0]->IsInt32());
1236
174
  const int fd = args[0].As<Int32>()->Value();
1237
1238
58
  CHECK(IsSafeJsInt(args[1]));
1239
174
  const int64_t len = args[1].As<Integer>()->Value();
1240
1241
58
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1242
58
  if (req_wrap_async != nullptr) {
1243
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1244
45
              uv_fs_ftruncate, fd, len);
1245
  } else {
1246
13
    CHECK_EQ(argc, 4);
1247
26
    FSReqWrapSync req_wrap_sync;
1248
13
    FS_SYNC_TRACE_BEGIN(ftruncate);
1249
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1250
14
             len);
1251

14
    FS_SYNC_TRACE_END(ftruncate);
1252
1
  }
1253
62
}
1254
2
1255
8
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1256
11
  Environment* env = Environment::GetCurrent(args);
1257
1
1258
7
  const int argc = args.Length();
1259
8
  CHECK_GE(argc, 2);
1260
1261
14
  CHECK(args[0]->IsInt32());
1262
21
  const int fd = args[0].As<Int32>()->Value();
1263
1264
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1265
7
  if (req_wrap_async != nullptr) {
1266
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1267
4
              uv_fs_fdatasync, fd);
1268
  } else {
1269
3
    CHECK_EQ(argc, 3);
1270
6
    FSReqWrapSync req_wrap_sync;
1271
3
    FS_SYNC_TRACE_BEGIN(fdatasync);
1272
3
    SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1273
4
    FS_SYNC_TRACE_END(fdatasync);
1274
1
  }
1275
9
}
1276

4
1277
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1278
24
  Environment* env = Environment::GetCurrent(args);
1279
2
1280
21
  const int argc = args.Length();
1281
22
  CHECK_GE(argc, 2);
1282
1283
42
  CHECK(args[0]->IsInt32());
1284
63
  const int fd = args[0].As<Int32>()->Value();
1285
1286
21
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1287
21
  if (req_wrap_async != nullptr) {
1288
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1289
4
              uv_fs_fsync, fd);
1290
  } else {
1291
17
    CHECK_EQ(argc, 3);
1292
34
    FSReqWrapSync req_wrap_sync;
1293
17
    FS_SYNC_TRACE_BEGIN(fsync);
1294
17
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1295
18
    FS_SYNC_TRACE_END(fsync);
1296
1
  }
1297
23
}
1298

4
1299
2245
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1300
2246
  Environment* env = Environment::GetCurrent(args);
1301
2
1302
2243
  const int argc = args.Length();
1303
2244
  CHECK_GE(argc, 2);
1304
1305
4486
  BufferValue path(env->isolate(), args[0]);
1306
2243
  CHECK_NOT_NULL(*path);
1307
1308
2243
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1309
2243
  if (req_wrap_async != nullptr) {
1310
1017
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1311
1017
              uv_fs_unlink, *path);
1312
  } else {
1313
1226
    CHECK_EQ(argc, 3);
1314
2452
    FSReqWrapSync req_wrap_sync;
1315
1226
    FS_SYNC_TRACE_BEGIN(unlink);
1316
2452
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1317
1256
    FS_SYNC_TRACE_END(unlink);
1318
30
  }
1319
2298
}
1320

115
1321
1413
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1322
1443
  Environment* env = Environment::GetCurrent(args);
1323
60
1324
1358
  const int argc = args.Length();
1325
1388
  CHECK_GE(argc, 2);
1326
1327
2716
  BufferValue path(env->isolate(), args[0]);
1328
1358
  CHECK_NOT_NULL(*path);
1329
1330
1358
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1331
1358
  if (req_wrap_async != nullptr) {
1332
215
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1333
215
              uv_fs_rmdir, *path);
1334
  } else {  // rmdir(path, undefined, ctx)
1335
1143
    CHECK_EQ(argc, 3);
1336
2286
    FSReqWrapSync req_wrap_sync;
1337
1143
    FS_SYNC_TRACE_BEGIN(rmdir);
1338
1143
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1339
1146
             uv_fs_rmdir, *path);
1340

1146
    FS_SYNC_TRACE_END(rmdir);
1341
3
  }
1342
1370
}
1343
6
1344
5259
int MKDirpSync(uv_loop_t* loop,
1345
12
               uv_fs_t* req,
1346
3
               const std::string& path,
1347
               int mode,
1348
3
               uv_fs_cb cb) {
1349
5256
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1350
1351
  // on the first iteration of algorithm, stash state information.
1352
5256
  if (req_wrap->continuation_data() == nullptr) {
1353
    req_wrap->set_continuation_data(
1354
5256
        std::make_unique<FSContinuationData>(req, mode, cb));
1355
5256
    req_wrap->continuation_data()->PushPath(std::move(path));
1356
  }
1357
1358
15462
  while (req_wrap->continuation_data()->paths().size() > 0) {
1359
10459
    std::string next_path = req_wrap->continuation_data()->PopPath();
1360
5356
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1361
    while (true) {
1362

5357
      switch (err) {
1363
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1364
        // ~FSReqWrapSync():
1365
        case 0:
1366
298
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1367
298
          if (req_wrap->continuation_data()->paths().size() == 0) {
1368
249
            return 0;
1369
          }
1370
49
          break;
1371
        case UV_EACCES:
1372
        case UV_ENOTDIR:
1373
        case UV_EPERM: {
1374
2
          return err;
1375
        }
1376
        case UV_ENOENT: {
1377
          std::string dirname = next_path.substr(0,
1378
51
                                        next_path.find_last_of(kPathSeparator));
1379
51
          if (dirname != next_path) {
1380
50
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1381
50
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1382
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1383
1
            err = UV_EEXIST;
1384
1
            continue;
1385
          }
1386
50
          break;
1387
        }
1388
        default:
1389
5006
          uv_fs_req_cleanup(req);
1390
5006
          int orig_err = err;
1391
5006
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1392

5006
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1393
1
            uv_fs_req_cleanup(req);
1394

2
            if (orig_err == UV_EEXIST &&
1395
1
              req_wrap->continuation_data()->paths().size() > 0) {
1396
              return UV_ENOTDIR;
1397
            }
1398
1
            return UV_EEXIST;
1399
          }
1400
5005
          if (err < 0) return err;
1401
5004
          break;
1402
      }
1403
5103
      break;
1404
1
    }
1405
5103
    uv_fs_req_cleanup(req);
1406
  }
1407
1408
5003
  return 0;
1409
}
1410
1411
847
int MKDirpAsync(uv_loop_t* loop,
1412
                uv_fs_t* req,
1413
                const char* path,
1414
                int mode,
1415
                uv_fs_cb cb) {
1416
847
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1417
  // on the first iteration of algorithm, stash state information.
1418
847
  if (req_wrap->continuation_data() == nullptr) {
1419
    req_wrap->set_continuation_data(
1420
621
        std::make_unique<FSContinuationData>(req, mode, cb));
1421
621
    req_wrap->continuation_data()->PushPath(std::move(path));
1422
  }
1423
1424
  // on each iteration of algorithm, mkdir directory on top of stack.
1425
1694
  std::string next_path = req_wrap->continuation_data()->PopPath();
1426
847
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1427
2541
                        uv_fs_callback_t{[](uv_fs_t* req) {
1428
847
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1429
847
    Environment* env = req_wrap->env();
1430
847
    uv_loop_t* loop = env->event_loop();
1431
1694
    std::string path = req->path;
1432
847
    int err = req->result;
1433
1434
    while (true) {
1435

848
      switch (err) {
1436
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1437
        // FSReqAfterScope::~FSReqAfterScope()
1438
        case 0: {
1439
278
          if (req_wrap->continuation_data()->paths().size() == 0) {
1440
259
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1441
259
            req_wrap->continuation_data()->Done(0);
1442
          } else {
1443
19
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1444
19
            uv_fs_req_cleanup(req);
1445
19
            MKDirpAsync(loop, req, path.c_str(),
1446
19
                        req_wrap->continuation_data()->mode(), nullptr);
1447
          }
1448
278
          break;
1449
        }
1450
        case UV_EACCES:
1451
        case UV_ENOTDIR:
1452
        case UV_EPERM: {
1453
3
          req_wrap->continuation_data()->Done(err);
1454
3
          break;
1455
        }
1456
        case UV_ENOENT: {
1457
          std::string dirname = path.substr(0,
1458
114
                                            path.find_last_of(kPathSeparator));
1459
114
          if (dirname != path) {
1460
113
            req_wrap->continuation_data()->PushPath(std::move(path));
1461
113
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1462
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1463
1
            err = UV_EEXIST;
1464
1
            continue;
1465
          }
1466
113
          uv_fs_req_cleanup(req);
1467
113
          MKDirpAsync(loop, req, path.c_str(),
1468
113
                      req_wrap->continuation_data()->mode(), nullptr);
1469
113
          break;
1470
        }
1471
        default:
1472
453
          uv_fs_req_cleanup(req);
1473
          // Stash err for use in the callback.
1474
453
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1475
453
          int err = uv_fs_stat(loop, req, path.c_str(),
1476
1359
                               uv_fs_callback_t{[](uv_fs_t* req) {
1477
453
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1478
453
            int err = req->result;
1479

906
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1480
453
                  req_wrap->continuation_data()->paths().size() > 0) {
1481

94
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1482
94
                Environment* env = req_wrap->env();
1483
94
                uv_loop_t* loop = env->event_loop();
1484
188
                std::string path = req->path;
1485
94
                uv_fs_req_cleanup(req);
1486
94
                MKDirpAsync(loop, req, path.c_str(),
1487
94
                            req_wrap->continuation_data()->mode(), nullptr);
1488
94
                return;
1489
              }
1490
              err = UV_ENOTDIR;
1491
            }
1492
            // verify that the path pointed to is actually a directory.
1493

359
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1494
359
            req_wrap->continuation_data()->Done(err);
1495
1359
          }});
1496
453
          if (err < 0) req_wrap->continuation_data()->Done(err);
1497
453
          break;
1498
      }
1499
847
      break;
1500
1
    }
1501
3388
  }});
1502
1503
1694
  return err;
1504
}
1505
1506
233
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1507
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1508
233
  env->PrintSyncTrace();
1509
466
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1510
233
                       nullptr);
1511
233
  if (err < 0) {
1512
4
    v8::Local<v8::Context> context = env->context();
1513
8
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1514
4
    v8::Isolate* isolate = env->isolate();
1515
8
    ctx_obj->Set(context,
1516
                 env->errno_string(),
1517
16
                 v8::Integer::New(isolate, err)).Check();
1518
8
    ctx_obj->Set(context,
1519
                 env->syscall_string(),
1520
16
                 OneByteString(isolate, "mkdir")).Check();
1521
  }
1522
233
  return err;
1523
}
1524
1525
1821
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1526
1821
  Environment* env = Environment::GetCurrent(args);
1527
1528
1821
  const int argc = args.Length();
1529
1821
  CHECK_GE(argc, 4);
1530
1531
3642
  BufferValue path(env->isolate(), args[0]);
1532
1821
  CHECK_NOT_NULL(*path);
1533
1534
3642
  CHECK(args[1]->IsInt32());
1535
5463
  const int mode = args[1].As<Int32>()->Value();
1536
1537
3642
  CHECK(args[2]->IsBoolean());
1538
3642
  bool mkdirp = args[2]->IsTrue();
1539
1540
1821
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1541
1821
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1542

856
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1543
              mkdirp ? AfterMkdirp : AfterNoArgs,
1544
856
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1545
  } else {  // mkdir(path, mode, undefined, ctx)
1546
965
    CHECK_EQ(argc, 5);
1547
1930
    FSReqWrapSync req_wrap_sync;
1548
965
    FS_SYNC_TRACE_BEGIN(mkdir);
1549
965
    if (mkdirp) {
1550
235
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1551


464
      if (err == 0 &&
1552
231
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1553
6
        Local<Value> error;
1554
456
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1555
227
        FromNamespacedPath(&first_path);
1556
2
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1557
                                                     first_path.c_str(),
1558
227
                                                     UTF8, &error);
1559
227
        if (path.IsEmpty()) {
1560
          Local<Object> ctx = args[4].As<Object>();
1561
          ctx->Set(env->context(), env->error_string(), error).Check();
1562
          return;
1563
        }
1564
454
        args.GetReturnValue().Set(path.ToLocalChecked());
1565
      }
1566
    } else {
1567
732
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1568
732
               uv_fs_mkdir, *path, mode);
1569
    }
1570
965
    FS_SYNC_TRACE_END(mkdir);
1571
  }
1572
2
}
1573
2
1574
44
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1575
48
  Environment* env = Environment::GetCurrent(args);
1576
44
  Isolate* isolate = env->isolate();
1577
1578
44
  const int argc = args.Length();
1579
42
  CHECK_GE(argc, 3);
1580
1581
82
  BufferValue path(isolate, args[0]);
1582
42
  CHECK_NOT_NULL(*path);
1583
1584
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1585
1586
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1587
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1588
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1589
22
              uv_fs_realpath, *path);
1590
  } else {  // realpath(path, encoding, undefined, ctx)
1591
20
    CHECK_EQ(argc, 4);
1592
38
    FSReqWrapSync req_wrap_sync;
1593
20
    FS_SYNC_TRACE_BEGIN(realpath);
1594
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1595
21
                       uv_fs_realpath, *path);
1596

21
    FS_SYNC_TRACE_END(realpath);
1597
21
    if (err < 0) {
1598
6
      return;  // syscall failed, no need to continue, error info is in ctx
1599
2
    }
1600
1
1601
22
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1602
1
1603
    Local<Value> error;
1604
1
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1605
                                               link_path,
1606
                                               encoding,
1607
18
                                               &error);
1608
18
    if (rc.IsEmpty()) {
1609
      Local<Object> ctx = args[3].As<Object>();
1610
      ctx->Set(env->context(), env->error_string(), error).Check();
1611
      return;
1612
    }
1613
1614
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1615
  }
1616
}
1617
1618
12966
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1619
12966
  Environment* env = Environment::GetCurrent(args);
1620
12966
  Isolate* isolate = env->isolate();
1621
1622
12966
  const int argc = args.Length();
1623
12966
  CHECK_GE(argc, 3);
1624
1625
25834
  BufferValue path(isolate, args[0]);
1626
12966
  CHECK_NOT_NULL(*path);
1627
1628
12966
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1629
1630
25932
  bool with_types = args[2]->IsTrue();
1631
1632
12966
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1633
12966
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1634
252
    if (with_types) {
1635
163
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1636
163
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1637
    } else {
1638
89
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1639
89
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1640
    }
1641
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1642
12714
    CHECK_EQ(argc, 5);
1643
25330
    FSReqWrapSync req_wrap_sync;
1644
12714
    FS_SYNC_TRACE_BEGIN(readdir);
1645
12714
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1646
12715
                       uv_fs_scandir, *path, 0 /*flags*/);
1647

12715
    FS_SYNC_TRACE_END(readdir);
1648
12715
    if (err < 0) {
1649
102
      return;  // syscall failed, no need to continue, error info is in ctx
1650
2
    }
1651
1
1652

12620
    CHECK_GE(req_wrap_sync.req.result, 0);
1653
1
    int r;
1654
25232
    std::vector<Local<Value>> name_v;
1655
25233
    std::vector<Local<Value>> type_v;
1656
1657
    for (;;) {
1658
      uv_dirent_t ent;
1659
1660
687109
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1661
687109
      if (r == UV_EOF)
1662
12616
        break;
1663
674493
      if (r != 0) {
1664
        Local<Object> ctx = args[4].As<Object>();
1665
        ctx->Set(env->context(), env->errno_string(),
1666
                 Integer::New(isolate, r)).Check();
1667
        ctx->Set(env->context(), env->syscall_string(),
1668
                 OneByteString(isolate, "readdir")).Check();
1669
        return;
1670
      }
1671
1672
      Local<Value> error;
1673
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1674
                                                       ent.name,
1675
                                                       encoding,
1676
674493
                                                       &error);
1677
1678
674493
      if (filename.IsEmpty()) {
1679
        Local<Object> ctx = args[4].As<Object>();
1680
        ctx->Set(env->context(), env->error_string(), error).Check();
1681
        return;
1682
      }
1683
1684
674493
      name_v.push_back(filename.ToLocalChecked());
1685
1686
674493
      if (with_types) {
1687
22760
        type_v.emplace_back(Integer::New(isolate, ent.type));
1688
      }
1689
674493
    }
1690
1691
1692
12616
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1693
12616
    if (with_types) {
1694
      Local<Value> result[] = {
1695
        names,
1696
        Array::New(isolate, type_v.data(), type_v.size())
1697
99
      };
1698
99
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1699
    } else {
1700
25166
      args.GetReturnValue().Set(names);
1701
    }
1702
  }
1703
}
1704
1705
52441
static void Open(const FunctionCallbackInfo<Value>& args) {
1706
52441
  Environment* env = Environment::GetCurrent(args);
1707
1708
52441
  const int argc = args.Length();
1709
52441
  CHECK_GE(argc, 3);
1710
1711
104882
  BufferValue path(env->isolate(), args[0]);
1712
52441
  CHECK_NOT_NULL(*path);
1713
1714
104882
  CHECK(args[1]->IsInt32());
1715
157323
  const int flags = args[1].As<Int32>()->Value();
1716
1717
104882
  CHECK(args[2]->IsInt32());
1718
157323
  const int mode = args[2].As<Int32>()->Value();
1719
1720
52441
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1721
52441
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1722
5359
    req_wrap_async->set_is_plain_open(true);
1723
5359
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1724
5359
              uv_fs_open, *path, flags, mode);
1725
  } else {  // open(path, flags, mode, undefined, ctx)
1726
47082
    CHECK_EQ(argc, 5);
1727
94164
    FSReqWrapSync req_wrap_sync;
1728

47118
    FS_SYNC_TRACE_BEGIN(open);
1729
47082
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1730
47082
                          uv_fs_open, *path, flags, mode);
1731
47082
    FS_SYNC_TRACE_END(open);
1732
47107
    if (result >= 0) env->AddUnmanagedFd(result);
1733
94298
    args.GetReturnValue().Set(result);
1734
72
  }
1735
52467
}
1736
134
1737
702
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1738
666
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1739
702
  Environment* env = binding_data->env();
1740
666
  Isolate* isolate = env->isolate();
1741
1742
666
  const int argc = args.Length();
1743
666
  CHECK_GE(argc, 3);
1744
1745
1332
  BufferValue path(isolate, args[0]);
1746
666
  CHECK_NOT_NULL(*path);
1747
1748
1332
  CHECK(args[1]->IsInt32());
1749
1998
  const int flags = args[1].As<Int32>()->Value();
1750
1751
1332
  CHECK(args[2]->IsInt32());
1752
1998
  const int mode = args[2].As<Int32>()->Value();
1753
1754
666
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1755
666
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1756
665
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1757
665
              uv_fs_open, *path, flags, mode);
1758
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1759
1
    CHECK_EQ(argc, 5);
1760
2
    FSReqWrapSync req_wrap_sync;
1761
1
    FS_SYNC_TRACE_BEGIN(open);
1762
1
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1763
1
                          uv_fs_open, *path, flags, mode);
1764

1
    FS_SYNC_TRACE_END(open);
1765
1
    if (result < 0) {
1766
      return;  // syscall failed, no need to continue, error info is in ctx
1767
    }
1768
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1769

1
    if (fd == nullptr) return;
1770
3
    args.GetReturnValue().Set(fd->object());
1771
  }
1772
}
1773
1774
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1775
33
  Environment* env = Environment::GetCurrent(args);
1776
33
  Isolate* isolate = env->isolate();
1777
1778
33
  const int argc = args.Length();
1779
33
  CHECK_GE(argc, 3);
1780
1781
66
  BufferValue src(isolate, args[0]);
1782
33
  CHECK_NOT_NULL(*src);
1783
1784
66
  BufferValue dest(isolate, args[1]);
1785
33
  CHECK_NOT_NULL(*dest);
1786
1787
66
  CHECK(args[2]->IsInt32());
1788
99
  const int flags = args[2].As<Int32>()->Value();
1789
1790
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1791
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1792
14
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1793
14
                  *dest, dest.length(), UTF8, AfterNoArgs,
1794
14
                  uv_fs_copyfile, *src, *dest, flags);
1795
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1796
19
    CHECK_EQ(argc, 5);
1797
38
    FSReqWrapSync req_wrap_sync;
1798
19
    FS_SYNC_TRACE_BEGIN(copyfile);
1799
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1800
20
             uv_fs_copyfile, *src, *dest, flags);
1801

20
    FS_SYNC_TRACE_END(copyfile);
1802
1
  }
1803
37
}
1804
2
1805
1
1806
4
// Wrapper for write(2).
1807
1
//
1808
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1809
1
// 0 fd        integer. file descriptor
1810
// 1 buffer    the data to write
1811
// 2 offset    where in the buffer to start from
1812
// 3 length    how much to write
1813
// 4 position  if integer, position to write at in the file.
1814
//             if null, write from the current position
1815
35208
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1816
35208
  Environment* env = Environment::GetCurrent(args);
1817
1818
35208
  const int argc = args.Length();
1819
35208
  CHECK_GE(argc, 4);
1820
1821
70416
  CHECK(args[0]->IsInt32());
1822
105624
  const int fd = args[0].As<Int32>()->Value();
1823
1824
35208
  CHECK(Buffer::HasInstance(args[1]));
1825
70416
  Local<Object> buffer_obj = args[1].As<Object>();
1826
35208
  char* buffer_data = Buffer::Data(buffer_obj);
1827
35208
  size_t buffer_length = Buffer::Length(buffer_obj);
1828
1829
35208
  CHECK(IsSafeJsInt(args[2]));
1830
105624
  const int64_t off_64 = args[2].As<Integer>()->Value();
1831
35208
  CHECK_GE(off_64, 0);
1832
35208
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1833
35208
  const size_t off = static_cast<size_t>(off_64);
1834
1835
70416
  CHECK(args[3]->IsInt32());
1836
105624
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1837
35208
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1838
35208
  CHECK_LE(len, buffer_length);
1839
35208
  CHECK_GE(off + len, off);
1840
1841
35208
  const int64_t pos = GetOffset(args[4]);
1842
1843
35208
  char* buf = buffer_data + off;
1844
35208
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1845
1846
35208
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1847
35208
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1848
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1849
16282
              uv_fs_write, fd, &uvbuf, 1, pos);
1850
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1851
18926
    CHECK_EQ(argc, 7);
1852
37852
    FSReqWrapSync req_wrap_sync;
1853

18951
    FS_SYNC_TRACE_BEGIN(write);
1854
18926
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1855
18926
                                uv_fs_write, fd, &uvbuf, 1, pos);
1856
18926
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1857
56803
    args.GetReturnValue().Set(bytesWritten);
1858
100
  }
1859
35258
}
1860
25
1861
100
1862
25
// Wrapper for writev(2).
1863
//
1864
25
// bytesWritten = writev(fd, chunks, position, callback)
1865
// 0 fd        integer. file descriptor
1866
// 1 chunks    array of buffers to write
1867
// 2 position  if integer, position to write at in the file.
1868
//             if null, write from the current position
1869
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1870
18
  Environment* env = Environment::GetCurrent(args);
1871
1872
18
  const int argc = args.Length();
1873
18
  CHECK_GE(argc, 3);
1874
1875
36
  CHECK(args[0]->IsInt32());
1876
54
  const int fd = args[0].As<Int32>()->Value();
1877
1878
36
  CHECK(args[1]->IsArray());
1879
36
  Local<Array> chunks = args[1].As<Array>();
1880
1881
18
  int64_t pos = GetOffset(args[2]);
1882
1883
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1884
1885
71
  for (uint32_t i = 0; i < iovs.length(); i++) {
1886
159
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1887
53
    CHECK(Buffer::HasInstance(chunk));
1888
53
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1889
  }
1890
1891
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1892
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1893
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1894
14
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1895
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1896
4
    CHECK_EQ(argc, 5);
1897
8
    FSReqWrapSync req_wrap_sync;
1898
4
    FS_SYNC_TRACE_BEGIN(write);
1899
8
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1900
4
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1901

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1902
12
    args.GetReturnValue().Set(bytesWritten);
1903
  }
1904
18
}
1905
1906
1907
// Wrapper for write(2).
1908
//
1909
// bytesWritten = write(fd, string, position, enc, callback)
1910
// 0 fd        integer. file descriptor
1911
// 1 string    non-buffer values are converted to strings
1912
// 2 position  if integer, position to write at in the file.
1913
//             if null, write from the current position
1914
// 3 enc       encoding of string
1915
95691
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1916
95691
  Environment* env = Environment::GetCurrent(args);
1917
95691
  Isolate* isolate = env->isolate();
1918
1919
95691
  const int argc = args.Length();
1920
95691
  CHECK_GE(argc, 4);
1921
1922
191382
  CHECK(args[0]->IsInt32());
1923
287073
  const int fd = args[0].As<Int32>()->Value();
1924
1925
95691
  const int64_t pos = GetOffset(args[2]);
1926
1927
95691
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1928
1929
95691
  Local<Value> value = args[1];
1930
95691
  char* buf = nullptr;
1931
  size_t len;
1932
1933
95691
  FSReqBase* req_wrap_async = GetReqWrap(args, 4);
1934
95691
  const bool is_async = req_wrap_async != nullptr;
1935
1936
  // Avoid copying the string when it is externalized but only when:
1937
  // 1. The target encoding is compatible with the string's encoding, and
1938
  // 2. The write is synchronous, otherwise the string might get neutered
1939
  //    while the request is in flight, and
1940
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1941
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1942
  // The const_casts are conceptually sound: memory is read but not written.
1943

286955
  if (!is_async && value->IsString()) {
1944
95632
    auto string = value.As<String>();
1945


95633
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1946
1
      auto ext = string->GetExternalOneByteStringResource();
1947
1
      buf = const_cast<char*>(ext->data());
1948
1
      len = ext->length();
1949


95632
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
1950
2
      auto ext = string->GetExternalStringResource();
1951
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1952
1
      len = ext->length() * sizeof(*ext->data());
1953
    }
1954
  }
1955
1956
95691
  if (is_async) {  // write(fd, string, pos, enc, req)
1957
59
    CHECK_NOT_NULL(req_wrap_async);
1958
118
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1959
    FSReqBase::FSReqBuffer& stack_buffer =
1960
59
        req_wrap_async->Init("write", len, enc);
1961
    // StorageSize may return too large a char, so correct the actual length
1962
    // by the write size
1963
59
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1964
59
    stack_buffer.SetLengthAndZeroTerminate(len);
1965
59
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1966
59
    int err = req_wrap_async->Dispatch(uv_fs_write,
1967
                                       fd,
1968
                                       &uvbuf,
1969
                                       1,
1970
                                       pos,
1971
59
                                       AfterInteger);
1972
59
    if (err < 0) {
1973
      uv_fs_t* uv_req = req_wrap_async->req();
1974
      uv_req->result = err;
1975
      uv_req->path = nullptr;
1976
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1977
                             // an error
1978
    } else {
1979
59
      req_wrap_async->SetReturnValue(args);
1980
    }
1981
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1982
95632
    CHECK_EQ(argc, 6);
1983
191264
    FSReqWrapSync req_wrap_sync;
1984
191264
    FSReqBase::FSReqBuffer stack_buffer;
1985
95632
    if (buf == nullptr) {
1986
191260
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1987
        return;
1988
95630
      stack_buffer.AllocateSufficientStorage(len + 1);
1989
      // StorageSize may return too large a char, so correct the actual length
1990
      // by the write size
1991
95630
      len = StringBytes::Write(isolate, *stack_buffer,
1992
                               len, args[1], enc);
1993
95630
      stack_buffer.SetLengthAndZeroTerminate(len);
1994
95630
      buf = *stack_buffer;
1995
    }
1996
95632
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1997
95632
    FS_SYNC_TRACE_BEGIN(write);
1998
95632
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1999
95632
                                uv_fs_write, fd, &uvbuf, 1, pos);
2000

95632
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2001
286896
    args.GetReturnValue().Set(bytesWritten);
2002
  }
2003
}
2004
2005
2006
/*
2007
 * Wrapper for read(2).
2008
 *
2009
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2010
 *
2011
 * 0 fd        int32. file descriptor
2012
 * 1 buffer    instance of Buffer
2013
 * 2 offset    int64. offset to start reading into inside buffer
2014
 * 3 length    int32. length to read
2015
 * 4 position  int64. file position - -1 for current position
2016
 */
2017
58750
static void Read(const FunctionCallbackInfo<Value>& args) {
2018
58750
  Environment* env = Environment::GetCurrent(args);
2019
2020
58750
  const int argc = args.Length();
2021
58750
  CHECK_GE(argc, 5);
2022
2023
117500
  CHECK(args[0]->IsInt32());
2024
176250
  const int fd = args[0].As<Int32>()->Value();
2025
2026
58750
  CHECK(Buffer::HasInstance(args[1]));
2027
117500
  Local<Object> buffer_obj = args[1].As<Object>();
2028
58750
  char* buffer_data = Buffer::Data(buffer_obj);
2029
58750
  size_t buffer_length = Buffer::Length(buffer_obj);
2030
2031
58750
  CHECK(IsSafeJsInt(args[2]));
2032
176250
  const int64_t off_64 = args[2].As<Integer>()->Value();
2033
58750
  CHECK_GE(off_64, 0);
2034
58750
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2035
58750
  const size_t off = static_cast<size_t>(off_64);
2036
2037
117500
  CHECK(args[3]->IsInt32());
2038
176250
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2039
58750
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2040
2041
58750
  CHECK(IsSafeJsInt(args[4]));
2042
176250
  const int64_t pos = args[4].As<Integer>()->Value();
2043
2044
58750
  char* buf = buffer_data + off;
2045
58750
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2046
2047
58750
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2048
58750
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2049
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2050
13846
              uv_fs_read, fd, &uvbuf, 1, pos);
2051
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2052
44904
    CHECK_EQ(argc, 7);
2053
89808
    FSReqWrapSync req_wrap_sync;
2054

44909
    FS_SYNC_TRACE_BEGIN(read);
2055
44904
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2056
44904
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2057
44904
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2058
134715
    args.GetReturnValue().Set(bytesRead);
2059
18
  }
2060
58760
}
2061
3
2062
18
2063
5
// Wrapper for readv(2).
2064
//
2065
5
// bytesRead = fs.readv(fd, buffers[, position], callback)
2066
// 0 fd        integer. file descriptor
2067
// 1 buffers   array of buffers to read
2068
// 2 position  if integer, position to read at in the file.
2069
//             if null, read from the current position
2070
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2071
11
  Environment* env = Environment::GetCurrent(args);
2072
2073
11
  const int argc = args.Length();
2074
11
  CHECK_GE(argc, 3);
2075
2076
22
  CHECK(args[0]->IsInt32());
2077
33
  const int fd = args[0].As<Int32>()->Value();
2078
2079
22
  CHECK(args[1]->IsArray());
2080
22
  Local<Array> buffers = args[1].As<Array>();
2081
2082
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2083
2084
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2085
2086
  // Init uv buffers from ArrayBufferViews
2087
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2088
51
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2089
17
    CHECK(Buffer::HasInstance(buffer));
2090
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2091
  }
2092
2093
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2094
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2095
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2096
7
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2097
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2098
4
    CHECK_EQ(argc, 5);
2099
8
    FSReqWrapSync req_wrap_sync;
2100
4
    FS_SYNC_TRACE_BEGIN(read);
2101
8
    int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2102
4
                             uv_fs_read, fd, *iovs, iovs.length(), pos);
2103

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2104
12
    args.GetReturnValue().Set(bytesRead);
2105
  }
2106
11
}
2107
2108
2109
/* fs.chmod(path, mode);
2110
 * Wrapper for chmod(1) / EIO_CHMOD
2111
 */
2112
91
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2113
91
  Environment* env = Environment::GetCurrent(args);
2114
2115
91
  const int argc = args.Length();
2116
91
  CHECK_GE(argc, 2);
2117
2118
182
  BufferValue path(env->isolate(), args[0]);
2119
91
  CHECK_NOT_NULL(*path);
2120
2121
182
  CHECK(args[1]->IsInt32());
2122
273
  int mode = args[1].As<Int32>()->Value();
2123
2124
91
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2125
91
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2126
76
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2127
76
              uv_fs_chmod, *path, mode);
2128
  } else {  // chmod(path, mode, undefined, ctx)
2129
15
    CHECK_EQ(argc, 4);
2130
30
    FSReqWrapSync req_wrap_sync;
2131
15
    FS_SYNC_TRACE_BEGIN(chmod);
2132
15
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2133
16
             uv_fs_chmod, *path, mode);
2134

16
    FS_SYNC_TRACE_END(chmod);
2135
1
  }
2136
95
}
2137
2
2138
1
2139
4
/* fs.fchmod(fd, mode);
2140
1
 * Wrapper for fchmod(1) / EIO_FCHMOD
2141
 */
2142
13
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2143
12
  Environment* env = Environment::GetCurrent(args);
2144
2145
12
  const int argc = args.Length();
2146
12
  CHECK_GE(argc, 2);
2147
2148
24
  CHECK(args[0]->IsInt32());
2149
36
  const int fd = args[0].As<Int32>()->Value();
2150
2151
24
  CHECK(args[1]->IsInt32());
2152
36
  const int mode = args[1].As<Int32>()->Value();
2153
2154
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2155
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2156
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2157
7
              uv_fs_fchmod, fd, mode);
2158
  } else {  // fchmod(fd, mode, undefined, ctx)
2159
5
    CHECK_EQ(argc, 4);
2160
10
    FSReqWrapSync req_wrap_sync;
2161
5
    FS_SYNC_TRACE_BEGIN(fchmod);
2162
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2163
6
             uv_fs_fchmod, fd, mode);
2164

6
    FS_SYNC_TRACE_END(fchmod);
2165
1
  }
2166
16
}
2167
2
2168
1
2169
4
/* fs.chown(path, uid, gid);
2170
1
 * Wrapper for chown(1) / EIO_CHOWN
2171
 */
2172
5
static void Chown(const FunctionCallbackInfo<Value>& args) {
2173
4
  Environment* env = Environment::GetCurrent(args);
2174
2175
4
  const int argc = args.Length();
2176
4
  CHECK_GE(argc, 3);
2177
2178
8
  BufferValue path(env->isolate(), args[0]);
2179
4
  CHECK_NOT_NULL(*path);
2180
2181
8
  CHECK(args[1]->IsUint32());
2182
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2183
2184
8
  CHECK(args[2]->IsUint32());
2185
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2186
2187
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2188
4
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2189
2
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2190
2
              uv_fs_chown, *path, uid, gid);
2191
  } else {  // chown(path, uid, gid, undefined, ctx)
2192
2
    CHECK_EQ(argc, 5);
2193
4
    FSReqWrapSync req_wrap_sync;
2194
2
    FS_SYNC_TRACE_BEGIN(chown);
2195
2
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2196
3
             uv_fs_chown, *path, uid, gid);
2197

3
    FS_SYNC_TRACE_END(chown);
2198
1
  }
2199
8
}
2200
2
2201
1
2202
4
/* fs.fchown(fd, uid, gid);
2203
1
 * Wrapper for fchown(1) / EIO_FCHOWN
2204
 */
2205
5
static void FChown(const FunctionCallbackInfo<Value>& args) {
2206
4
  Environment* env = Environment::GetCurrent(args);
2207
2208
4
  const int argc = args.Length();
2209
4
  CHECK_GE(argc, 3);
2210
2211
8
  CHECK(args[0]->IsInt32());
2212
12
  const int fd = args[0].As<Int32>()->Value();
2213
2214
8
  CHECK(args[1]->IsUint32());
2215
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2216
2217
8
  CHECK(args[2]->IsUint32());
2218
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2219
2220
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2221
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2222
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2223
2
              uv_fs_fchown, fd, uid, gid);
2224
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2225
2
    CHECK_EQ(argc, 5);
2226
4
    FSReqWrapSync req_wrap_sync;
2227
2
    FS_SYNC_TRACE_BEGIN(fchown);
2228
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2229
3
             uv_fs_fchown, fd, uid, gid);
2230

3
    FS_SYNC_TRACE_END(fchown);
2231
1
  }
2232
8
}
2233
2
2234
1
2235
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2236
6
  Environment* env = Environment::GetCurrent(args);
2237
2238
6
  const int argc = args.Length();
2239
5
  CHECK_GE(argc, 3);
2240
2241
10
  BufferValue path(env->isolate(), args[0]);
2242
5
  CHECK_NOT_NULL(*path);
2243
2244
10
  CHECK(args[1]->IsUint32());
2245
15
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2246
2247
10
  CHECK(args[2]->IsUint32());
2248
15
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2249
2250
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2251
5
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2252
3
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2253
3
              uv_fs_lchown, *path, uid, gid);
2254
  } else {  // lchown(path, uid, gid, undefined, ctx)
2255
2
    CHECK_EQ(argc, 5);
2256
4
    FSReqWrapSync req_wrap_sync;
2257
2
    FS_SYNC_TRACE_BEGIN(lchown);
2258
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2259
3
             uv_fs_lchown, *path, uid, gid);
2260

3
    FS_SYNC_TRACE_END(lchown);
2261
1
  }
2262
9
}
2263
2
2264
1
2265
37
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2266
34
  Environment* env = Environment::GetCurrent(args);
2267
2268
34
  const int argc = args.Length();
2269
33
  CHECK_GE(argc, 3);
2270
2271
66
  BufferValue path(env->isolate(), args[0]);
2272
33
  CHECK_NOT_NULL(*path);
2273
2274
66
  CHECK(args[1]->IsNumber());
2275
99
  const double atime = args[1].As<Number>()->Value();
2276
2277
66
  CHECK(args[2]->IsNumber());
2278
99
  const double mtime = args[2].As<Number>()->Value();
2279
2280
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2281
33
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2282
16
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2283
16
              uv_fs_utime, *path, atime, mtime);
2284
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2285
17
    CHECK_EQ(argc, 5);
2286
34
    FSReqWrapSync req_wrap_sync;
2287
17
    FS_SYNC_TRACE_BEGIN(utimes);
2288
17
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2289
18
             uv_fs_utime, *path, atime, mtime);
2290

18
    FS_SYNC_TRACE_END(utimes);
2291
1
  }
2292
37
}
2293
2
2294
1870
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2295
1873
  Environment* env = Environment::GetCurrent(args);
2296
1
2297
1869
  const int argc = args.Length();
2298
1870
  CHECK_GE(argc, 3);
2299
2300
3738
  CHECK(args[0]->IsInt32());
2301
5607
  const int fd = args[0].As<Int32>()->Value();
2302
2303
3738
  CHECK(args[1]->IsNumber());
2304
5607
  const double atime = args[1].As<Number>()->Value();
2305
2306
3738
  CHECK(args[2]->IsNumber());
2307
5607
  const double mtime = args[2].As<Number>()->Value();
2308
2309
1869
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2310
1869
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2311
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2312
1860
              uv_fs_futime, fd, atime, mtime);
2313
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2314
9
    CHECK_EQ(argc, 5);
2315
18
    FSReqWrapSync req_wrap_sync;
2316
9
    FS_SYNC_TRACE_BEGIN(futimes);
2317
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2318
10
             uv_fs_futime, fd, atime, mtime);
2319

10
    FS_SYNC_TRACE_END(futimes);
2320
1
  }
2321
1873
}
2322
2
2323
15
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2324
18
  Environment* env = Environment::GetCurrent(args);
2325
1
2326
14
  const int argc = args.Length();
2327
15
  CHECK_GE(argc, 3);
2328
2329
28
  BufferValue path(env->isolate(), args[0]);
2330
14
  CHECK_NOT_NULL(*path);
2331
2332
28
  CHECK(args[1]->IsNumber());
2333
42
  const double atime = args[1].As<Number>()->Value();
2334
2335
28
  CHECK(args[2]->IsNumber());
2336
42
  const double mtime = args[2].As<Number>()->Value();
2337
2338
14
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2339
14
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2340
7
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2341
7
              uv_fs_lutime, *path, atime, mtime);
2342
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2343
7
    CHECK_EQ(argc, 5);
2344
14
    FSReqWrapSync req_wrap_sync;
2345
7
    FS_SYNC_TRACE_BEGIN(lutimes);
2346
7
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2347
7
             uv_fs_lutime, *path, atime, mtime);
2348

7
    FS_SYNC_TRACE_END(lutimes);
2349
  }
2350
14
}
2351
2352
14
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2353
14
  Environment* env = Environment::GetCurrent(args);
2354
14
  Isolate* isolate = env->isolate();
2355
2356
14
  const int argc = args.Length();
2357
14
  CHECK_GE(argc, 2);
2358
2359
28
  BufferValue tmpl(isolate, args[0]);
2360
14
  CHECK_NOT_NULL(*tmpl);
2361
2362
14
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2363
2364
14
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2365
14
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2366
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2367
6
              uv_fs_mkdtemp, *tmpl);
2368
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2369
8
    CHECK_EQ(argc, 4);
2370
16
    FSReqWrapSync req_wrap_sync;
2371
8
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2372
8
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2373
9
             uv_fs_mkdtemp, *tmpl);
2374

9
    FS_SYNC_TRACE_END(mkdtemp);
2375
9
    const char* path = req_wrap_sync.req.path;
2376
4
2377
2
    Local<Value> error;
2378
1
    MaybeLocal<Value> rc =
2379
12
        StringBytes::Encode(isolate, path, encoding, &error);
2380
9
    if (rc.IsEmpty()) {
2381
      Local<Object> ctx = args[3].As<Object>();
2382
1
      ctx->Set(env->context(), env->error_string(), error).Check();
2383
      return;
2384
    }
2385
16
    args.GetReturnValue().Set(rc.ToLocalChecked());
2386
  }
2387
}
2388
2389
22
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2390
22
  tracker->TrackField("stats_field_array", stats_field_array);
2391
22
  tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2392
22
  tracker->TrackField("file_handle_read_wrap_freelist",
2393
22
                      file_handle_read_wrap_freelist);
2394
22
}
2395
2396
// TODO(addaleax): Remove once we're on C++17.
2397
constexpr FastStringKey BindingData::binding_data_name;
2398
2399
5017
void Initialize(Local<Object> target,
2400
                Local<Value> unused,
2401
                Local<Context> context,
2402
                void* priv) {
2403
5017
  Environment* env = Environment::GetCurrent(context);
2404
5017
  Isolate* isolate = env->isolate();
2405
  BindingData* const binding_data =
2406
5017
      env->AddBindingData<BindingData>(context, target);
2407
5017
  if (binding_data == nullptr) return;
2408
2409
5017
  env->SetMethod(target, "access", Access);
2410
5017
  env->SetMethod(target, "close", Close);
2411
5017
  env->SetMethod(target, "open", Open);
2412
5017
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2413
5017
  env->SetMethod(target, "read", Read);
2414
5017
  env->SetMethod(target, "readBuffers", ReadBuffers);
2415
5017
  env->SetMethod(target, "fdatasync", Fdatasync);
2416
5017
  env->SetMethod(target, "fsync", Fsync);
2417
5017
  env->SetMethod(target, "rename", Rename);
2418
5017
  env->SetMethod(target, "ftruncate", FTruncate);
2419
5017
  env->SetMethod(target, "rmdir", RMDir);
2420
5017
  env->SetMethod(target, "mkdir", MKDir);
2421
5017
  env->SetMethod(target, "readdir", ReadDir);
2422
5017
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2423
5017
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2424
5017
  env->SetMethod(target, "stat", Stat);
2425
5017
  env->SetMethod(target, "lstat", LStat);
2426
5017
  env->SetMethod(target, "fstat", FStat);
2427
5017
  env->SetMethod(target, "link", Link);
2428
5017
  env->SetMethod(target, "symlink", Symlink);
2429
5017
  env->SetMethod(target, "readlink", ReadLink);
2430
5017
  env->SetMethod(target, "unlink", Unlink);
2431
5017
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2432
5017
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2433
5017
  env->SetMethod(target, "writeString", WriteString);
2434
5017
  env->SetMethod(target, "realpath", RealPath);
2435
5017
  env->SetMethod(target, "copyFile", CopyFile);
2436
2437
5017
  env->SetMethod(target, "chmod", Chmod);
2438
5017
  env->SetMethod(target, "fchmod", FChmod);
2439
  // env->SetMethod(target, "lchmod", LChmod);
2440
2441
5017
  env->SetMethod(target, "chown", Chown);
2442
5017
  env->SetMethod(target, "fchown", FChown);
2443
5017
  env->SetMethod(target, "lchown", LChown);
2444
2445
5017
  env->SetMethod(target, "utimes", UTimes);
2446
5017
  env->SetMethod(target, "futimes", FUTimes);
2447
5017
  env->SetMethod(target, "lutimes", LUTimes);
2448
2449
5017
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2450
2451
  target
2452
10034
      ->Set(context,
2453
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2454
            Integer::New(
2455
                isolate,
2456
20068
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2457
      .Check();
2458
2459
10034
  target->Set(context,
2460
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2461
20068
              binding_data->stats_field_array.GetJSArray()).Check();
2462
2463
10034
  target->Set(context,
2464
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2465
20068
              binding_data->stats_field_bigint_array.GetJSArray()).Check();
2466
2467
5017
  StatWatcher::Initialize(env, target);
2468
2469
  // Create FunctionTemplate for FSReqCallback
2470
5017
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2471
15051
  fst->InstanceTemplate()->SetInternalFieldCount(
2472
5017
      FSReqBase::kInternalFieldCount);
2473
10034
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2474
  Local<String> wrapString =
2475
5017
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2476
5017
  fst->SetClassName(wrapString);
2477
  target
2478
10034
      ->Set(context, wrapString,
2479
20068
            fst->GetFunction(env->context()).ToLocalChecked())
2480
      .Check();
2481
2482
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2483
  // to do anything in the constructor, so we only store the instance template.
2484
5017
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2485
15051
  fh_rw->InstanceTemplate()->SetInternalFieldCount(
2486
5017
      FSReqBase::kInternalFieldCount);
2487
10034
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2488
  Local<String> fhWrapString =
2489
5017
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2490
5017
  fh_rw->SetClassName(fhWrapString);
2491
5017
  env->set_filehandlereadwrap_template(
2492
5017
      fst->InstanceTemplate());
2493
2494
  // Create Function Template for FSReqPromise
2495
5017
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2496
10034
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2497
  Local<String> promiseString =
2498
5017
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2499
5017
  fpt->SetClassName(promiseString);
2500
5017
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2501
5017
  fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2502
5017
  env->set_fsreqpromise_constructor_template(fpo);
2503
2504
  // Create FunctionTemplate for FileHandle
2505
5017
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2506
10034
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2507
5017
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2508
5017
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2509
5017
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2510
5017
  fdt->SetInternalFieldCount(StreamBase::kInternalFieldCount);
2511
  Local<String> handleString =
2512
5017
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2513
5017
  fd->SetClassName(handleString);
2514
5017
  StreamBase::AddMethods(env, fd);
2515
  target
2516
10034
      ->Set(context, handleString,
2517
20068
            fd->GetFunction(env->context()).ToLocalChecked())
2518
      .Check();
2519
5017
  env->set_fd_constructor_template(fdt);
2520
2521
  // Create FunctionTemplate for FileHandle::CloseReq
2522
5017
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2523
10034
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2524
5017
                        "FileHandleCloseReq"));
2525
10034
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2526
5017
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2527
5017
  fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2528
5017
  env->set_fdclose_constructor_template(fdcloset);
2529
2530
  Local<Symbol> use_promises_symbol =
2531
    Symbol::New(isolate,
2532
5017
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2533
5017
  env->set_fs_use_promises_symbol(use_promises_symbol);
2534
10034
  target->Set(context,
2535
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2536
15051
              use_promises_symbol).Check();
2537
}
2538
2539
3789
BindingData* FSReqBase::binding_data() {
2540
3789
  return binding_data_.get();
2541
}
2542
}  // namespace fs
2543
2544
}  // end namespace node
2545
2546

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