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: 2021-01-16 04:10:54 Branches: 805 1226 65.7 %

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::BigInt;
55
using v8::Boolean;
56
using v8::Context;
57
using v8::EscapableHandleScope;
58
using v8::Function;
59
using v8::FunctionCallbackInfo;
60
using v8::FunctionTemplate;
61
using v8::HandleScope;
62
using v8::Int32;
63
using v8::Integer;
64
using v8::Isolate;
65
using v8::Local;
66
using v8::MaybeLocal;
67
using v8::Number;
68
using v8::Object;
69
using v8::ObjectTemplate;
70
using v8::Promise;
71
using v8::String;
72
using v8::Symbol;
73
using v8::Uint32;
74
using v8::Undefined;
75
using v8::Value;
76
77
#ifndef S_ISDIR
78
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
79
#endif
80
81
#ifdef __POSIX__
82
constexpr char kPathSeparator = '/';
83
#else
84
const char* const kPathSeparator = "\\/";
85
#endif
86
87
10
std::string Basename(const std::string& str, const std::string& extension) {
88
  // Remove everything leading up to and including the final path separator.
89
10
  std::string::size_type pos = str.find_last_of(kPathSeparator);
90
91
  // Starting index for the resulting string
92
10
  std::size_t start_pos = 0;
93
  // String size to return
94
10
  std::size_t str_size = str.size();
95
10
  if (pos != std::string::npos) {
96
10
    start_pos = pos + 1;
97
10
    str_size -= start_pos;
98
  }
99
100
  // Strip away the extension, if any.
101

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

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

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

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

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

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

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

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

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

3
869
2
870
48239
void Close(const FunctionCallbackInfo<Value>& args) {
871
48239
  Environment* env = Environment::GetCurrent(args);
872
873
48239
  const int argc = args.Length();
874
48238
  CHECK_GE(argc, 2);
875
876
96476
  CHECK(args[0]->IsInt32());
877
144711
  int fd = args[0].As<Int32>()->Value();
878
48237
  env->RemoveUnmanagedFd(fd);
879
880
48238
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
881
48238
  if (req_wrap_async != nullptr) {  // close(fd, req)
882
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
883
5113
              uv_fs_close, fd);
884
  } else {  // close(fd, undefined, ctx)
885
43125
    CHECK_EQ(argc, 3);
886
86250
    FSReqWrapSync req_wrap_sync;
887
43124
    FS_SYNC_TRACE_BEGIN(close);
888
43124
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
889
43154
    FS_SYNC_TRACE_END(close);
890
30
  }
891
48293
}
892

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

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

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

13858
    if (err != 0) {
1032
550
      return;  // error info is in ctx
1033

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

900
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1481
450
                  req_wrap->continuation_data()->paths().size() > 0) {
1482

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

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

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


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

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

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

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

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

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

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

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

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

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

290370
  if (!is_async && value->IsString()) {
1945
96770
    auto string = value.As<String>();
1946


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


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

96770
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2002
290310
    args.GetReturnValue().Set(bytesWritten);
2003
  }
2004
}
2005
2006
2007
/*
2008
 * Wrapper for read(2).
2009
 *
2010
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2011
 *
2012
 * 0 fd        int32. file descriptor
2013
 * 1 buffer    instance of Buffer
2014
 * 2 offset    int64. offset to start reading into inside buffer
2015
 * 3 length    int32. length to read
2016
 * 4 position  int64. file position - -1 for current position
2017
 */
2018
55059
static void Read(const FunctionCallbackInfo<Value>& args) {
2019
55059
  Environment* env = Environment::GetCurrent(args);
2020
2021
55059
  const int argc = args.Length();
2022
55059
  CHECK_GE(argc, 5);
2023
2024
110118
  CHECK(args[0]->IsInt32());
2025
165177
  const int fd = args[0].As<Int32>()->Value();
2026
2027
55059
  CHECK(Buffer::HasInstance(args[1]));
2028
110118
  Local<Object> buffer_obj = args[1].As<Object>();
2029
55059
  char* buffer_data = Buffer::Data(buffer_obj);
2030
55059
  size_t buffer_length = Buffer::Length(buffer_obj);
2031
2032
55059
  CHECK(IsSafeJsInt(args[2]));
2033
165177
  const int64_t off_64 = args[2].As<Integer>()->Value();
2034
55058
  CHECK_GE(off_64, 0);
2035
55058
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2036
55058
  const size_t off = static_cast<size_t>(off_64);
2037
2038
110116
  CHECK(args[3]->IsInt32());
2039
165177
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2040
55059
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2041
2042

55066
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2043
220232
  const int64_t pos = args[4]->IsNumber() ?
2044
220220
                      args[4].As<Integer>()->Value() :
2045
55070
                      args[4].As<BigInt>()->Int64Value();
2046
2047
55058
  char* buf = buffer_data + off;
2048
55058
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2049
2050
55058
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2051
55059
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2052
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2053
13750
              uv_fs_read, fd, &uvbuf, 1, pos);
2054
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2055
41309
    CHECK_EQ(argc, 7);
2056
82618
    FSReqWrapSync req_wrap_sync;
2057

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

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

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

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

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

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

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

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

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

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

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

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