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: 1521 1609 94.5 %
Date: 2020-11-20 19:51:53 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
129965
inline int64_t GetOffset(Local<Value> value) {
110
132105
  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
632
FileHandle::FileHandle(BindingData* binding_data,
148
632
                       Local<Object> obj, int fd)
149
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
150
      StreamBase(env()),
151
      fd_(fd),
152
632
      binding_data_(binding_data) {
153
632
  MakeWeak();
154
632
  StreamBase::AttachToObject(GetObject());
155
632
}
156
157
632
FileHandle* FileHandle::New(BindingData* binding_data,
158
                            int fd, Local<Object> obj) {
159
632
  Environment* env = binding_data->env();
160

2498
  if (obj.IsEmpty() && !env->fd_constructor_template()
161
1866
                            ->NewInstance(env->context())
162
617
                            .ToLocal(&obj)) {
163
    return nullptr;
164
  }
165
632
  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
1845
FileHandle::~FileHandle() {
184
615
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
185
615
  Close();           // Close synchronously and emit warning
186
615
  CHECK(closed_);    // We have to be closed at the point
187
1230
}
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
8
FileHandle::TransferMode FileHandle::GetTransferMode() const {
201

8
  return reading_ || closing_ || closed_ ?
202
8
      TransferMode::kUntransferable : TransferMode::kTransferable;
203
}
204
205
5
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
206
5
  CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
207
10
  auto ret = std::make_unique<TransferData>(fd_);
208
5
  closed_ = true;
209
10
  return ret;
210
}
211
212
5
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
213
214
15
FileHandle::TransferData::~TransferData() {
215
5
  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
10
}
221
222
1
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
223
    Environment* env,
224
    v8::Local<v8::Context> context,
225
    std::unique_ptr<worker::TransferData> self) {
226
1
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
227
1
  if (bd == nullptr) return {};
228
229
1
  int fd = fd_;
230
1
  fd_ = -1;
231
1
  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
615
inline void FileHandle::Close() {
239
1221
  if (closed_) return;
240
  uv_fs_t req;
241
9
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
242
9
  uv_fs_req_cleanup(&req);
243
244
  struct err_detail { int ret; int fd; };
245
246
9
  err_detail detail { ret, fd_ };
247
248
9
  AfterClose();
249
250
9
  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
20
  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
11
  }, CallbackFlags::kUnrefed);
286
}
287
288
609
void FileHandle::CloseReq::Resolve() {
289
609
  Isolate* isolate = env()->isolate();
290
1201
  HandleScope scope(isolate);
291
1218
  InternalCallbackScope callback_scope(this);
292
1218
  Local<Promise> promise = promise_.Get(isolate);
293
609
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
294
1827
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
295
592
}
296
297
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
298
1
  Isolate* isolate = env()->isolate();
299
2
  HandleScope scope(isolate);
300
2
  InternalCallbackScope callback_scope(this);
301
2
  Local<Promise> promise = promise_.Get(isolate);
302
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
303
3
  resolver->Reject(env()->context(), reason).Check();
304
1
}
305
306
610
FileHandle* FileHandle::CloseReq::file_handle() {
307
610
  Isolate* isolate = env()->isolate();
308
1220
  HandleScope scope(isolate);
309
1220
  Local<Value> val = ref_.Get(isolate);
310
610
  Local<Object> obj = val.As<Object>();
311
1220
  return Unwrap<FileHandle>(obj);
312
}
313
314
610
FileHandle::CloseReq::CloseReq(Environment* env,
315
                               Local<Object> obj,
316
                               Local<Promise> promise,
317
610
                               Local<Value> ref)
318
1220
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
319
610
  promise_.Reset(env->isolate(), promise);
320
610
  ref_.Reset(env->isolate(), ref);
321
610
}
322
323
2965
FileHandle::CloseReq::~CloseReq() {
324
593
  uv_fs_req_cleanup(req());
325
593
  promise_.Reset();
326
593
  ref_.Reset();
327
1186
}
328
329
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
330
  tracker->TrackField("promise", promise_);
331
  tracker->TrackField("ref", ref_);
332
}
333
334
335
336
// Closes this FileHandle asynchronously and returns a Promise that will be
337
// resolved when the callback is invoked, or rejects with a UVException if
338
// there was a problem closing the fd. This is the preferred mechanism for
339
// closing the FD object even tho the object will attempt to close
340
// automatically on gc.
341
610
MaybeLocal<Promise> FileHandle::ClosePromise() {
342
610
  Isolate* isolate = env()->isolate();
343
610
  EscapableHandleScope scope(isolate);
344
610
  Local<Context> context = env()->context();
345
610
  auto maybe_resolver = Promise::Resolver::New(context);
346
610
  CHECK(!maybe_resolver.IsEmpty());
347
610
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
348
610
  Local<Promise> promise = resolver.As<Promise>();
349
610
  CHECK(!reading_);
350

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

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

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

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

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

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

3
866
2
867
51167
void Close(const FunctionCallbackInfo<Value>& args) {
868
51167
  Environment* env = Environment::GetCurrent(args);
869
870
51166
  const int argc = args.Length();
871
51165
  CHECK_GE(argc, 2);
872
873
102330
  CHECK(args[0]->IsInt32());
874
153495
  int fd = args[0].As<Int32>()->Value();
875
51165
  env->RemoveUnmanagedFd(fd);
876
877
51165
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
878
51165
  if (req_wrap_async != nullptr) {  // close(fd, req)
879
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
880
5037
              uv_fs_close, fd);
881
  } else {  // close(fd, undefined, ctx)
882
46128
    CHECK_EQ(argc, 3);
883
92256
    FSReqWrapSync req_wrap_sync;
884
46128
    FS_SYNC_TRACE_BEGIN(close);
885
46128
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
886
46158
    FS_SYNC_TRACE_END(close);
887
30
  }
888
51221
}
889

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

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

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

13838
    if (err != 0) {
1029
544
      return;  // error info is in ctx
1030

4
    }
1031
2
1032
3
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1033
13297
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1034
26590
    args.GetReturnValue().Set(arr);
1035
1
  }
1036
}
1037
1038
107133
static void LStat(const FunctionCallbackInfo<Value>& args) {
1039
107133
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1040
107133
  Environment* env = binding_data->env();
1041
1042
107133
  const int argc = args.Length();
1043
107133
  CHECK_GE(argc, 3);
1044
1045
213960
  BufferValue path(env->isolate(), args[0]);
1046
107132
  CHECK_NOT_NULL(*path);
1047
1048
214264
  bool use_bigint = args[1]->IsTrue();
1049
107132
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1050
107133
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1051
3896
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1052
3896
              uv_fs_lstat, *path);
1053
  } else {  // lstat(path, use_bigint, undefined, ctx)
1054
103237
    CHECK_EQ(argc, 4);
1055
206168
    FSReqWrapSync req_wrap_sync;
1056
103237
    FS_SYNC_TRACE_BEGIN(lstat);
1057
103237
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1058
103254
                       *path);
1059

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

40987
    if (err != 0) {
1092
29
      return;  // error info is in ctx
1093

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

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

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

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

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

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

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

4
1297
2238
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1298
2239
  Environment* env = Environment::GetCurrent(args);
1299
2
1300
2236
  const int argc = args.Length();
1301
2237
  CHECK_GE(argc, 2);
1302
1303
4472
  BufferValue path(env->isolate(), args[0]);
1304
2236
  CHECK_NOT_NULL(*path);
1305
1306
2236
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1307
2236
  if (req_wrap_async != nullptr) {
1308
1017
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1309
1017
              uv_fs_unlink, *path);
1310
  } else {
1311
1219
    CHECK_EQ(argc, 3);
1312
2438
    FSReqWrapSync req_wrap_sync;
1313
1219
    FS_SYNC_TRACE_BEGIN(unlink);
1314
2438
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1315
1249
    FS_SYNC_TRACE_END(unlink);
1316
30
  }
1317
2291
}
1318

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

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

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

4987
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1391
1
            uv_fs_req_cleanup(req);
1392

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

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

880
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1478
440
                  req_wrap->continuation_data()->paths().size() > 0) {
1479

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

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

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


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

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

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

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

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

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

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

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

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

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

284210
  if (!is_async && value->IsString()) {
1942
94717
    auto string = value.As<String>();
1943


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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