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: 1400 1493 93.8 %
Date: 2020-06-24 22:13:30 Branches: 787 1212 64.9 %

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

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

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

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

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

302
  if (reading_ && !persistent().IsEmpty())
400
    EmitRead(UV_EOF);
401
302
}
402
403
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
404
  tracker->TrackField("buffer", buffer_);
405
  tracker->TrackField("file_handle", this->file_handle_);
406
}
407
408
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
409
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
410
15
    file_handle_(handle) {}
411
412
212
int FileHandle::ReadStart() {
413

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

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

206
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
501
        result = handle->read_length_;
502
503
      // If we read data and we have an expected length, decrease it by
504
      // how much we have read.
505
206
      if (handle->read_length_ >= 0)
506
9
        handle->read_length_ -= result;
507
508
      // If we have an offset, increase it by how much we have read.
509
206
      if (handle->read_offset_ >= 0)
510
204
        handle->read_offset_ += result;
511
    }
512
513
    // Reading 0 bytes from a file always means EOF, or that we reached
514
    // the end of the requested range.
515
207
    if (result == 0)
516
7
      result = UV_EOF;
517
518
207
    handle->EmitRead(result, buffer);
519
520
    // Start over, if EmitRead() didn’t tell us to stop.
521
207
    if (handle->reading_)
522
      handle->ReadStart();
523
828
  }});
524
525
207
  return 0;
526
}
527
528
227
int FileHandle::ReadStop() {
529
227
  reading_ = false;
530
227
  return 0;
531
}
532
533
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
534
535
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
536
  return new FileHandleCloseWrap(this, object);
537
}
538
539
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
540
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
541
  closing_ = true;
542
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
543
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
544
        FileHandleCloseWrap::from_req(req));
545
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
546
    handle->AfterClose();
547
548
    int result = req->result;
549
    uv_fs_req_cleanup(req);
550
    wrap->Done(result);
551
  }});
552
553
  return 0;
554
}
555
556
557
3951
void FSReqCallback::Reject(Local<Value> reject) {
558
3951
  MakeCallback(env()->oncomplete_string(), 1, &reject);
559
3951
}
560
561
3900
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
562
3900
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
563
3900
}
564
565
45229
void FSReqCallback::Resolve(Local<Value> value) {
566
  Local<Value> argv[2] {
567
    Null(env()->isolate()),
568
    value
569
90458
  };
570
  MakeCallback(env()->oncomplete_string(),
571
127860
               value->IsUndefined() ? 1 : arraysize(argv),
572
82631
               argv);
573
45212
}
574
575
49183
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
576
98366
  args.GetReturnValue().SetUndefined();
577
49183
}
578
579
49206
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
580
49206
  CHECK(args.IsConstructCall());
581
49206
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
582
147618
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
583
49206
}
584
585
50495
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
586
    : wrap_(wrap),
587
      req_(req),
588
      handle_scope_(wrap->env()->isolate()),
589
50495
      context_scope_(wrap->env()->context()) {
590
50495
  CHECK_EQ(wrap_->req(), req);
591
50495
}
592
593
151434
FSReqAfterScope::~FSReqAfterScope() {
594
50478
  Clear();
595
50478
}
596
597
54488
void FSReqAfterScope::Clear() {
598
54488
  if (!wrap_) return;
599
600
50478
  uv_fs_req_cleanup(wrap_->req());
601
50478
  wrap_->Detach();
602
50478
  wrap_.reset();
603
}
604
605
// TODO(joyeecheung): create a normal context object, and
606
// construct the actual errors in the JS land using the context.
607
// The context should include fds for some fs APIs, currently they are
608
// missing in the error messages. The path, dest, syscall, fd, .etc
609
// can be put into the context before the binding is even invoked,
610
// the only information that has to come from the C++ layer is the
611
// error number (and possibly the syscall for abstraction),
612
// which is also why the errors should have been constructed
613
// in JS for more flexibility.
614
3999
void FSReqAfterScope::Reject(uv_fs_t* req) {
615
7998
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
616
  Local<Value> exception =
617
3999
      UVException(wrap_->env()->isolate(),
618
3999
                  req->result,
619
                  wrap_->syscall(),
620
                  nullptr,
621
                  req->path,
622
11997
                  wrap_->data());
623
3999
  Clear();
624
3999
  wrap->Reject(exception);
625
3999
}
626
627
50495
bool FSReqAfterScope::Proceed() {
628
50495
  if (req_->result < 0) {
629
3999
    Reject(req_);
630
3999
    return false;
631
  }
632
46496
  return true;
633
}
634
635
8474
void AfterNoArgs(uv_fs_t* req) {
636
8474
  FSReqBase* req_wrap = FSReqBase::from_req(req);
637
16933
  FSReqAfterScope after(req_wrap, req);
638
639
8474
  if (after.Proceed())
640
15752
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
641
8459
}
642
643
7412
void AfterStat(uv_fs_t* req) {
644
7412
  FSReqBase* req_wrap = FSReqBase::from_req(req);
645
14824
  FSReqAfterScope after(req_wrap, req);
646
647
7412
  if (after.Proceed()) {
648
4241
    req_wrap->ResolveStat(&req->statbuf);
649
  }
650
7412
}
651
652
34044
void AfterInteger(uv_fs_t* req) {
653
34044
  FSReqBase* req_wrap = FSReqBase::from_req(req);
654
68087
  FSReqAfterScope after(req_wrap, req);
655
656
34044
  if (after.Proceed())
657
67726
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
658
34043
}
659
660
314
void AfterOpenFileHandle(uv_fs_t* req) {
661
314
  FSReqBase* req_wrap = FSReqBase::from_req(req);
662
628
  FSReqAfterScope after(req_wrap, req);
663
664
314
  if (after.Proceed()) {
665
290
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(), req->result);
666
290
    if (fd == nullptr) return;
667
580
    req_wrap->Resolve(fd->object());
668
  }
669
}
670
671
// Reverse the logic applied by path.toNamespacedPath() to create a
672
// namespace-prefixed path.
673
110
void FromNamespacedPath(std::string* path) {
674
#ifdef _WIN32
675
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
676
    *path = path->substr(8);
677
    path->insert(0, "\\\\");
678
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
679
    *path = path->substr(4);
680
  }
681
#endif
682
110
}
683
684
14
void AfterMkdirp(uv_fs_t* req) {
685
14
  FSReqBase* req_wrap = FSReqBase::from_req(req);
686
28
  FSReqAfterScope after(req_wrap, req);
687
688
  MaybeLocal<Value> path;
689
  Local<Value> error;
690
691
14
  if (after.Proceed()) {
692
8
    if (!req_wrap->continuation_data()->first_path().empty()) {
693
14
      std::string first_path(req_wrap->continuation_data()->first_path());
694
7
      FromNamespacedPath(&first_path);
695
      path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
696
                                 req_wrap->encoding(),
697
7
                                 &error);
698
7
      if (path.IsEmpty())
699
        req_wrap->Reject(error);
700
      else
701
14
        req_wrap->Resolve(path.ToLocalChecked());
702
    } else {
703
2
      req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
704
    }
705
  }
706
14
}
707
708
6
void AfterStringPath(uv_fs_t* req) {
709
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
710
12
  FSReqAfterScope after(req_wrap, req);
711
712
  MaybeLocal<Value> link;
713
  Local<Value> error;
714
715
6
  if (after.Proceed()) {
716
    link = StringBytes::Encode(req_wrap->env()->isolate(),
717
                               req->path,
718
                               req_wrap->encoding(),
719
5
                               &error);
720
5
    if (link.IsEmpty())
721
      req_wrap->Reject(error);
722
    else
723
10
      req_wrap->Resolve(link.ToLocalChecked());
724
  }
725
6
}
726
727
63
void AfterStringPtr(uv_fs_t* req) {
728
63
  FSReqBase* req_wrap = FSReqBase::from_req(req);
729
125
  FSReqAfterScope after(req_wrap, req);
730
731
  MaybeLocal<Value> link;
732
  Local<Value> error;
733
734
63
  if (after.Proceed()) {
735
    link = StringBytes::Encode(req_wrap->env()->isolate(),
736
50
                               static_cast<const char*>(req->ptr),
737
                               req_wrap->encoding(),
738
100
                               &error);
739
50
    if (link.IsEmpty())
740
      req_wrap->Reject(error);
741
    else
742
100
      req_wrap->Resolve(link.ToLocalChecked());
743
  }
744
62
}
745
746
129
void AfterScanDir(uv_fs_t* req) {
747
129
  FSReqBase* req_wrap = FSReqBase::from_req(req);
748
255
  FSReqAfterScope after(req_wrap, req);
749
750
129
  if (!after.Proceed()) {
751
3
    return;
752
  }
753
126
  Environment* env = req_wrap->env();
754
  Local<Value> error;
755
  int r;
756
252
  std::vector<Local<Value>> name_v;
757
758
  for (;;) {
759
    uv_dirent_t ent;
760
761
6739
    r = uv_fs_scandir_next(req, &ent);
762
6739
    if (r == UV_EOF)
763
126
      break;
764
6613
    if (r != 0) {
765
      return req_wrap->Reject(UVException(
766
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
767
    }
768
769
    MaybeLocal<Value> filename =
770
      StringBytes::Encode(env->isolate(),
771
          ent.name,
772
          req_wrap->encoding(),
773
6613
          &error);
774
6613
    if (filename.IsEmpty())
775
      return req_wrap->Reject(error);
776
777
6613
    name_v.push_back(filename.ToLocalChecked());
778
6613
  }
779
780
252
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
781
}
782
783
7
void AfterScanDirWithTypes(uv_fs_t* req) {
784
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
785
13
  FSReqAfterScope after(req_wrap, req);
786
787
7
  if (!after.Proceed()) {
788
1
    return;
789
  }
790
791
6
  Environment* env = req_wrap->env();
792
6
  Isolate* isolate = env->isolate();
793
  Local<Value> error;
794
  int r;
795
796
12
  std::vector<Local<Value>> name_v;
797
12
  std::vector<Local<Value>> type_v;
798
799
  for (;;) {
800
    uv_dirent_t ent;
801
802
22
    r = uv_fs_scandir_next(req, &ent);
803
22
    if (r == UV_EOF)
804
6
      break;
805
16
    if (r != 0) {
806
      return req_wrap->Reject(
807
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
808
    }
809
810
    MaybeLocal<Value> filename =
811
      StringBytes::Encode(isolate,
812
          ent.name,
813
          req_wrap->encoding(),
814
16
          &error);
815
16
    if (filename.IsEmpty())
816
      return req_wrap->Reject(error);
817
818
16
    name_v.push_back(filename.ToLocalChecked());
819
16
    type_v.emplace_back(Integer::New(isolate, ent.type));
820
16
  }
821
822
  Local<Value> result[] = {
823
    Array::New(isolate, name_v.data(), name_v.size()),
824
    Array::New(isolate, type_v.data(), type_v.size())
825
18
  };
826
12
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
827
}
828
829
199
void Access(const FunctionCallbackInfo<Value>& args) {
830
199
  Environment* env = Environment::GetCurrent(args);
831
199
  Isolate* isolate = env->isolate();
832
398
  HandleScope scope(isolate);
833
834
199
  const int argc = args.Length();
835
199
  CHECK_GE(argc, 2);
836
837
398
  CHECK(args[1]->IsInt32());
838
597
  int mode = args[1].As<Int32>()->Value();
839
840
398
  BufferValue path(isolate, args[0]);
841
199
  CHECK_NOT_NULL(*path);
842
843
199
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
844
199
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
845
51
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
846
51
              uv_fs_access, *path, mode);
847
  } else {  // access(path, mode, undefined, ctx)
848
148
    CHECK_EQ(argc, 4);
849
296
    FSReqWrapSync req_wrap_sync;
850

150
    FS_SYNC_TRACE_BEGIN(access);
851
296
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
852

150
    FS_SYNC_TRACE_END(access);
853
  }
854
199
}
855
856
857
44173
void Close(const FunctionCallbackInfo<Value>& args) {
858
44173
  Environment* env = Environment::GetCurrent(args);
859
860
44173
  const int argc = args.Length();
861
44173
  CHECK_GE(argc, 2);
862
863
88346
  CHECK(args[0]->IsInt32());
864
132519
  int fd = args[0].As<Int32>()->Value();
865
866
44173
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
867
44173
  if (req_wrap_async != nullptr) {  // close(fd, req)
868
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
869
5095
              uv_fs_close, fd);
870
  } else {  // close(fd, undefined, ctx)
871
39078
    CHECK_EQ(argc, 3);
872
78156
    FSReqWrapSync req_wrap_sync;
873

39138
    FS_SYNC_TRACE_BEGIN(close);
874
39078
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
875

39137
    FS_SYNC_TRACE_END(close);
876
  }
877
44172
}
878
879
880
// Used to speed up module loading. Returns an array [string, boolean]
881
52142
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
882
52142
  Environment* env = Environment::GetCurrent(args);
883
52142
  Isolate* isolate = env->isolate();
884
52142
  uv_loop_t* loop = env->event_loop();
885
886
156426
  CHECK(args[0]->IsString());
887
57707
  node::Utf8Value path(isolate, args[0]);
888
889
52142
  if (strlen(*path) != path.length()) {
890
9
    args.GetReturnValue().Set(Array::New(isolate));
891
3
    return;  // Contains a nul byte.
892
  }
893
  uv_fs_t open_req;
894
52139
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
895
52139
  uv_fs_req_cleanup(&open_req);
896
897
52139
  if (fd < 0) {
898
139719
    args.GetReturnValue().Set(Array::New(isolate));
899
46573
    return;
900
  }
901
902
5566
  auto defer_close = OnScopeLeave([fd, loop]() {
903
    uv_fs_t close_req;
904
5566
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
905
5566
    uv_fs_req_cleanup(&close_req);
906
16697
  });
907
908
5566
  const size_t kBlockSize = 32 << 10;
909
11131
  std::vector<char> chars;
910
5566
  int64_t offset = 0;
911
  ssize_t numchars;
912
  do {
913
5566
    const size_t start = chars.size();
914
5566
    chars.resize(start + kBlockSize);
915
916
    uv_buf_t buf;
917
5566
    buf.base = &chars[start];
918
5566
    buf.len = kBlockSize;
919
920
    uv_fs_t read_req;
921
5566
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
922
5566
    uv_fs_req_cleanup(&read_req);
923
924
5566
    if (numchars < 0) {
925
3
      args.GetReturnValue().Set(Array::New(isolate));
926
1
      return;
927
    }
928
5565
    offset += numchars;
929
5565
  } while (static_cast<size_t>(numchars) == kBlockSize);
930
931
5565
  size_t start = 0;
932

5565
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
933
1
    start = 3;  // Skip UTF-8 BOM.
934
  }
935
936
5565
  const size_t size = offset - start;
937
5565
  char* p = &chars[start];
938
5565
  char* pe = &chars[size];
939
  char* pos[2];
940
5565
  char** ppos = &pos[0];
941
942
2730939
  while (p < pe) {
943
1368242
    char c = *p++;
944

1368242
    if (c == '\\' && p < pe && *p == '"') p++;
945
1368242
    if (c != '"') continue;
946
131322
    *ppos++ = p;
947
131322
    if (ppos < &pos[2]) continue;
948
65661
    ppos = &pos[0];
949
950
65661
    char* s = &pos[0][0];
951
65661
    char* se = &pos[1][-1];  // Exclude quote.
952
65661
    size_t n = se - s;
953
954
65661
    if (n == 4) {
955
5802
      if (0 == memcmp(s, "main", 4)) break;
956
5689
      if (0 == memcmp(s, "name", 4)) break;
957
5135
      if (0 == memcmp(s, "type", 4)) break;
958
59859
    } else if (n == 7) {
959
938
      if (0 == memcmp(s, "exports", 7)) break;
960
    }
961
  }
962
963
964
  Local<Value> return_value[] = {
965
11130
    String::NewFromUtf8(isolate,
966
5565
                        &chars[start],
967
                        v8::NewStringType::kNormal,
968
5565
                        size).ToLocalChecked(),
969
    Boolean::New(isolate, p < pe ? true : false)
970
16695
  };
971
16695
  args.GetReturnValue().Set(
972
    Array::New(isolate, return_value, arraysize(return_value)));
973
}
974
975
// Used to speed up module loading.  Returns 0 if the path refers to
976
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
977
// The speedup comes from not creating thousands of Stat and Error objects.
978
105543
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
979
105543
  Environment* env = Environment::GetCurrent(args);
980
981
316629
  CHECK(args[0]->IsString());
982
211086
  node::Utf8Value path(env->isolate(), args[0]);
983
984
  uv_fs_t req;
985
105543
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
986
105543
  if (rc == 0) {
987
50731
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
988
50731
    rc = !!(s->st_mode & S_IFDIR);
989
  }
990
105543
  uv_fs_req_cleanup(&req);
991
992
211086
  args.GetReturnValue().Set(rc);
993
105543
}
994
995
15909
static void Stat(const FunctionCallbackInfo<Value>& args) {
996
15909
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
997
15909
  Environment* env = binding_data->env();
998
999
15909
  const int argc = args.Length();
1000
15909
  CHECK_GE(argc, 2);
1001
1002
31630
  BufferValue path(env->isolate(), args[0]);
1003
15909
  CHECK_NOT_NULL(*path);
1004
1005
31818
  bool use_bigint = args[1]->IsTrue();
1006
15909
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1007
15909
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1008
1823
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1009
1823
              uv_fs_stat, *path);
1010
  } else {  // stat(path, use_bigint, undefined, ctx)
1011
14086
    CHECK_EQ(argc, 4);
1012
27984
    FSReqWrapSync req_wrap_sync;
1013

14088
    FS_SYNC_TRACE_BEGIN(stat);
1014
28172
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1015

14088
    FS_SYNC_TRACE_END(stat);
1016
14086
    if (err != 0) {
1017
188
      return;  // error info is in ctx
1018
    }
1019
1020
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1021
13898
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1022
27796
    args.GetReturnValue().Set(arr);
1023
  }
1024
}
1025
1026
96442
static void LStat(const FunctionCallbackInfo<Value>& args) {
1027
96442
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1028
96442
  Environment* env = binding_data->env();
1029
1030
96442
  const int argc = args.Length();
1031
96442
  CHECK_GE(argc, 3);
1032
1033
192610
  BufferValue path(env->isolate(), args[0]);
1034
96441
  CHECK_NOT_NULL(*path);
1035
1036
192884
  bool use_bigint = args[1]->IsTrue();
1037
96443
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1038
96437
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1039
4386
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1040
4386
              uv_fs_lstat, *path);
1041
  } else {  // lstat(path, use_bigint, undefined, ctx)
1042
92051
    CHECK_EQ(argc, 4);
1043
183831
    FSReqWrapSync req_wrap_sync;
1044

92091
    FS_SYNC_TRACE_BEGIN(lstat);
1045
92057
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1046
92057
                       *path);
1047

92082
    FS_SYNC_TRACE_END(lstat);
1048
92055
    if (err != 0) {
1049
275
      return;  // error info is in ctx
1050
    }
1051
1052
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1053
91780
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1054
183564
    args.GetReturnValue().Set(arr);
1055
  }
1056
}
1057
1058
36049
static void FStat(const FunctionCallbackInfo<Value>& args) {
1059
36049
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1060
36050
  Environment* env = binding_data->env();
1061
1062
36049
  const int argc = args.Length();
1063
36049
  CHECK_GE(argc, 2);
1064
1065
72098
  CHECK(args[0]->IsInt32());
1066
108150
  int fd = args[0].As<Int32>()->Value();
1067
1068
72100
  bool use_bigint = args[1]->IsTrue();
1069
36049
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1070
36050
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1071
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1072
1203
              uv_fs_fstat, fd);
1073
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1074
34847
    CHECK_EQ(argc, 4);
1075
69677
    FSReqWrapSync req_wrap_sync;
1076

34857
    FS_SYNC_TRACE_BEGIN(fstat);
1077
34847
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1078

34856
    FS_SYNC_TRACE_END(fstat);
1079
34846
    if (err != 0) {
1080
17
      return;  // error info is in ctx
1081
    }
1082
1083
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1084
34829
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1085
69660
    args.GetReturnValue().Set(arr);
1086
  }
1087
}
1088
1089
209
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1090
209
  Environment* env = Environment::GetCurrent(args);
1091
209
  Isolate* isolate = env->isolate();
1092
1093
209
  const int argc = args.Length();
1094
209
  CHECK_GE(argc, 4);
1095
1096
418
  BufferValue target(isolate, args[0]);
1097
209
  CHECK_NOT_NULL(*target);
1098
418
  BufferValue path(isolate, args[1]);
1099
209
  CHECK_NOT_NULL(*path);
1100
1101
418
  CHECK(args[2]->IsInt32());
1102
627
  int flags = args[2].As<Int32>()->Value();
1103
1104
209
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1105
209
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1106
26
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1107
26
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1108
  } else {  // symlink(target, path, flags, undefinec, ctx)
1109
183
    CHECK_EQ(argc, 5);
1110
366
    FSReqWrapSync req_wrap_sync;
1111

187
    FS_SYNC_TRACE_BEGIN(symlink);
1112
183
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1113
183
             uv_fs_symlink, *target, *path, flags);
1114

187
    FS_SYNC_TRACE_END(symlink);
1115
  }
1116
209
}
1117
1118
76
static void Link(const FunctionCallbackInfo<Value>& args) {
1119
76
  Environment* env = Environment::GetCurrent(args);
1120
76
  Isolate* isolate = env->isolate();
1121
1122
76
  const int argc = args.Length();
1123
76
  CHECK_GE(argc, 3);
1124
1125
152
  BufferValue src(isolate, args[0]);
1126
76
  CHECK_NOT_NULL(*src);
1127
1128
152
  BufferValue dest(isolate, args[1]);
1129
76
  CHECK_NOT_NULL(*dest);
1130
1131
76
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1132
76
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1133
71
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1134
71
                  AfterNoArgs, uv_fs_link, *src, *dest);
1135
  } else {  // link(src, dest)
1136
5
    CHECK_EQ(argc, 4);
1137
10
    FSReqWrapSync req_wrap_sync;
1138

11
    FS_SYNC_TRACE_BEGIN(link);
1139
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1140
5
             uv_fs_link, *src, *dest);
1141

11
    FS_SYNC_TRACE_END(link);
1142
  }
1143
76
}
1144
1145
89
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1146
89
  Environment* env = Environment::GetCurrent(args);
1147
89
  Isolate* isolate = env->isolate();
1148
1149
89
  const int argc = args.Length();
1150
89
  CHECK_GE(argc, 3);
1151
1152
177
  BufferValue path(isolate, args[0]);
1153
89
  CHECK_NOT_NULL(*path);
1154
1155
89
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1156
1157
89
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1158
89
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1159
41
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1160
41
              uv_fs_readlink, *path);
1161
  } else {
1162
48
    CHECK_EQ(argc, 4);
1163
95
    FSReqWrapSync req_wrap_sync;
1164

50
    FS_SYNC_TRACE_BEGIN(readlink);
1165
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1166
48
                       uv_fs_readlink, *path);
1167

50
    FS_SYNC_TRACE_END(readlink);
1168
48
    if (err < 0) {
1169
1
      return;  // syscall failed, no need to continue, error info is in ctx
1170
    }
1171
47
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1172
1173
    Local<Value> error;
1174
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1175
                                               link_path,
1176
                                               encoding,
1177
47
                                               &error);
1178
47
    if (rc.IsEmpty()) {
1179
      Local<Object> ctx = args[3].As<Object>();
1180
      ctx->Set(env->context(), env->error_string(), error).Check();
1181
      return;
1182
    }
1183
1184
94
    args.GetReturnValue().Set(rc.ToLocalChecked());
1185
  }
1186
}
1187
1188
144
static void Rename(const FunctionCallbackInfo<Value>& args) {
1189
144
  Environment* env = Environment::GetCurrent(args);
1190
144
  Isolate* isolate = env->isolate();
1191
1192
144
  const int argc = args.Length();
1193
144
  CHECK_GE(argc, 3);
1194
1195
288
  BufferValue old_path(isolate, args[0]);
1196
144
  CHECK_NOT_NULL(*old_path);
1197
288
  BufferValue new_path(isolate, args[1]);
1198
144
  CHECK_NOT_NULL(*new_path);
1199
1200
144
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1201
144
  if (req_wrap_async != nullptr) {
1202
139
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1203
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1204
139
                  *old_path, *new_path);
1205
  } else {
1206
5
    CHECK_EQ(argc, 4);
1207
10
    FSReqWrapSync req_wrap_sync;
1208

7
    FS_SYNC_TRACE_BEGIN(rename);
1209
5
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1210
5
             *old_path, *new_path);
1211

7
    FS_SYNC_TRACE_END(rename);
1212
  }
1213
144
}
1214
1215
50
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1216
50
  Environment* env = Environment::GetCurrent(args);
1217
1218
50
  const int argc = args.Length();
1219
50
  CHECK_GE(argc, 3);
1220
1221
100
  CHECK(args[0]->IsInt32());
1222
150
  const int fd = args[0].As<Int32>()->Value();
1223
1224
50
  CHECK(IsSafeJsInt(args[1]));
1225
150
  const int64_t len = args[1].As<Integer>()->Value();
1226
1227
50
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1228
50
  if (req_wrap_async != nullptr) {
1229
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1230
37
              uv_fs_ftruncate, fd, len);
1231
  } else {
1232
13
    CHECK_EQ(argc, 4);
1233
26
    FSReqWrapSync req_wrap_sync;
1234

15
    FS_SYNC_TRACE_BEGIN(ftruncate);
1235
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1236
13
             len);
1237

15
    FS_SYNC_TRACE_END(ftruncate);
1238
  }
1239
50
}
1240
1241
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1242
7
  Environment* env = Environment::GetCurrent(args);
1243
1244
7
  const int argc = args.Length();
1245
7
  CHECK_GE(argc, 2);
1246
1247
14
  CHECK(args[0]->IsInt32());
1248
21
  const int fd = args[0].As<Int32>()->Value();
1249
1250
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1251
7
  if (req_wrap_async != nullptr) {
1252
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1253
4
              uv_fs_fdatasync, fd);
1254
  } else {
1255
3
    CHECK_EQ(argc, 3);
1256
6
    FSReqWrapSync req_wrap_sync;
1257

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

5
    FS_SYNC_TRACE_END(fdatasync);
1260
  }
1261
7
}
1262
1263
25
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1264
25
  Environment* env = Environment::GetCurrent(args);
1265
1266
25
  const int argc = args.Length();
1267
25
  CHECK_GE(argc, 2);
1268
1269
50
  CHECK(args[0]->IsInt32());
1270
75
  const int fd = args[0].As<Int32>()->Value();
1271
1272
25
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1273
25
  if (req_wrap_async != nullptr) {
1274
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1275
6
              uv_fs_fsync, fd);
1276
  } else {
1277
19
    CHECK_EQ(argc, 3);
1278
38
    FSReqWrapSync req_wrap_sync;
1279

21
    FS_SYNC_TRACE_BEGIN(fsync);
1280
19
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1281

21
    FS_SYNC_TRACE_END(fsync);
1282
  }
1283
25
}
1284
1285
1328
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1286
1328
  Environment* env = Environment::GetCurrent(args);
1287
1288
1328
  const int argc = args.Length();
1289
1328
  CHECK_GE(argc, 2);
1290
1291
2656
  BufferValue path(env->isolate(), args[0]);
1292
1328
  CHECK_NOT_NULL(*path);
1293
1294
1328
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1295
1328
  if (req_wrap_async != nullptr) {
1296
550
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1297
550
              uv_fs_unlink, *path);
1298
  } else {
1299
778
    CHECK_EQ(argc, 3);
1300
1556
    FSReqWrapSync req_wrap_sync;
1301

838
    FS_SYNC_TRACE_BEGIN(unlink);
1302
1556
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1303

838
    FS_SYNC_TRACE_END(unlink);
1304
  }
1305
1328
}
1306
1307
1104
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1308
1104
  Environment* env = Environment::GetCurrent(args);
1309
1310
1104
  const int argc = args.Length();
1311
1104
  CHECK_GE(argc, 2);
1312
1313
2208
  BufferValue path(env->isolate(), args[0]);
1314
1104
  CHECK_NOT_NULL(*path);
1315
1316
1104
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1317
1104
  if (req_wrap_async != nullptr) {
1318
121
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1319
121
              uv_fs_rmdir, *path);
1320
  } else {  // rmdir(path, undefined, ctx)
1321
983
    CHECK_EQ(argc, 3);
1322
1966
    FSReqWrapSync req_wrap_sync;
1323

989
    FS_SYNC_TRACE_BEGIN(rmdir);
1324
983
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1325
983
             uv_fs_rmdir, *path);
1326

989
    FS_SYNC_TRACE_END(rmdir);
1327
  }
1328
1104
}
1329
1330
4784
int MKDirpSync(uv_loop_t* loop,
1331
               uv_fs_t* req,
1332
               const std::string& path,
1333
               int mode,
1334
               uv_fs_cb cb) {
1335
4784
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1336
1337
  // on the first iteration of algorithm, stash state information.
1338
4784
  if (req_wrap->continuation_data() == nullptr) {
1339
    req_wrap->set_continuation_data(
1340
4784
        std::make_unique<FSContinuationData>(req, mode, cb));
1341
4784
    req_wrap->continuation_data()->PushPath(std::move(path));
1342
  }
1343
1344
14294
  while (req_wrap->continuation_data()->paths().size() > 0) {
1345
9635
    std::string next_path = req_wrap->continuation_data()->PopPath();
1346
4880
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1347
    while (true) {
1348

4881
      switch (err) {
1349
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1350
        // ~FSReqWrapSync():
1351
        case 0:
1352
168
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1353
168
          if (req_wrap->continuation_data()->paths().size() == 0) {
1354
121
            return 0;
1355
          }
1356
47
          break;
1357
        case UV_EACCES:
1358
        case UV_ENOTDIR:
1359
        case UV_EPERM: {
1360
2
          return err;
1361
        }
1362
        case UV_ENOENT: {
1363
          std::string dirname = next_path.substr(0,
1364
49
                                        next_path.find_last_of(kPathSeparator));
1365
49
          if (dirname != next_path) {
1366
48
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1367
48
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1368
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1369
1
            err = UV_EEXIST;
1370
1
            continue;
1371
          }
1372
48
          break;
1373
        }
1374
        default:
1375
4662
          uv_fs_req_cleanup(req);
1376
4662
          int orig_err = err;
1377
4662
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1378

4662
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1379
1
            uv_fs_req_cleanup(req);
1380

2
            if (orig_err == UV_EEXIST &&
1381
1
              req_wrap->continuation_data()->paths().size() > 0) {
1382
              return UV_ENOTDIR;
1383
            }
1384
1
            return UV_EEXIST;
1385
          }
1386
4661
          if (err < 0) return err;
1387
4660
          break;
1388
      }
1389
4755
      break;
1390
1
    }
1391
4755
    uv_fs_req_cleanup(req);
1392
  }
1393
1394
4659
  return 0;
1395
}
1396
1397
24
int MKDirpAsync(uv_loop_t* loop,
1398
                uv_fs_t* req,
1399
                const char* path,
1400
                int mode,
1401
                uv_fs_cb cb) {
1402
24
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1403
  // on the first iteration of algorithm, stash state information.
1404
24
  if (req_wrap->continuation_data() == nullptr) {
1405
    req_wrap->set_continuation_data(
1406
14
        std::make_unique<FSContinuationData>(req, mode, cb));
1407
14
    req_wrap->continuation_data()->PushPath(std::move(path));
1408
  }
1409
1410
  // on each iteration of algorithm, mkdir directory on top of stack.
1411
48
  std::string next_path = req_wrap->continuation_data()->PopPath();
1412
24
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1413
72
                        uv_fs_callback_t{[](uv_fs_t* req) {
1414
24
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1415
24
    Environment* env = req_wrap->env();
1416
24
    uv_loop_t* loop = env->event_loop();
1417
48
    std::string path = req->path;
1418
24
    int err = req->result;
1419
1420
    while (true) {
1421

25
      switch (err) {
1422
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1423
        // FSReqAfterScope::~FSReqAfterScope()
1424
        case 0: {
1425
12
          if (req_wrap->continuation_data()->paths().size() == 0) {
1426
7
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1427
7
            req_wrap->continuation_data()->Done(0);
1428
          } else {
1429
5
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1430
5
            uv_fs_req_cleanup(req);
1431
5
            MKDirpAsync(loop, req, path.c_str(),
1432
5
                        req_wrap->continuation_data()->mode(), nullptr);
1433
          }
1434
12
          break;
1435
        }
1436
        case UV_EACCES:
1437
        case UV_ENOTDIR:
1438
        case UV_EPERM: {
1439
3
          req_wrap->continuation_data()->Done(err);
1440
3
          break;
1441
        }
1442
        case UV_ENOENT: {
1443
          std::string dirname = path.substr(0,
1444
6
                                            path.find_last_of(kPathSeparator));
1445
6
          if (dirname != path) {
1446
5
            req_wrap->continuation_data()->PushPath(std::move(path));
1447
5
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1448
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1449
1
            err = UV_EEXIST;
1450
1
            continue;
1451
          }
1452
5
          uv_fs_req_cleanup(req);
1453
5
          MKDirpAsync(loop, req, path.c_str(),
1454
5
                      req_wrap->continuation_data()->mode(), nullptr);
1455
5
          break;
1456
        }
1457
        default:
1458
4
          uv_fs_req_cleanup(req);
1459
          // Stash err for use in the callback.
1460
4
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1461
4
          int err = uv_fs_stat(loop, req, path.c_str(),
1462
12
                               uv_fs_callback_t{[](uv_fs_t* req) {
1463
4
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1464
4
            int err = req->result;
1465

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1466
4
                  req_wrap->continuation_data()->paths().size() > 0) {
1467
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1468
                Environment* env = req_wrap->env();
1469
                uv_loop_t* loop = env->event_loop();
1470
                std::string path = req->path;
1471
                uv_fs_req_cleanup(req);
1472
                MKDirpAsync(loop, req, path.c_str(),
1473
                            req_wrap->continuation_data()->mode(), nullptr);
1474
                return;
1475
              }
1476
              err = UV_ENOTDIR;
1477
            }
1478
            // verify that the path pointed to is actually a directory.
1479

4
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1480
4
            req_wrap->continuation_data()->Done(err);
1481
12
          }});
1482
4
          if (err < 0) req_wrap->continuation_data()->Done(err);
1483
4
          break;
1484
      }
1485
24
      break;
1486
1
    }
1487
96
  }});
1488
1489
48
  return err;
1490
}
1491
1492
109
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1493
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1494
109
  env->PrintSyncTrace();
1495
218
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1496
109
                       nullptr);
1497
109
  if (err < 0) {
1498
4
    v8::Local<v8::Context> context = env->context();
1499
8
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1500
4
    v8::Isolate* isolate = env->isolate();
1501
8
    ctx_obj->Set(context,
1502
                 env->errno_string(),
1503
16
                 v8::Integer::New(isolate, err)).Check();
1504
8
    ctx_obj->Set(context,
1505
                 env->syscall_string(),
1506
16
                 OneByteString(isolate, "mkdir")).Check();
1507
  }
1508
109
  return err;
1509
}
1510
1511
1634
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1512
1634
  Environment* env = Environment::GetCurrent(args);
1513
1514
1634
  const int argc = args.Length();
1515
1634
  CHECK_GE(argc, 4);
1516
1517
3268
  BufferValue path(env->isolate(), args[0]);
1518
1634
  CHECK_NOT_NULL(*path);
1519
1520
3268
  CHECK(args[1]->IsInt32());
1521
4902
  const int mode = args[1].As<Int32>()->Value();
1522
1523
3268
  CHECK(args[2]->IsBoolean());
1524
3268
  bool mkdirp = args[2]->IsTrue();
1525
1526
1634
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1527
1634
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1528

853
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1529
              mkdirp ? AfterMkdirp : AfterNoArgs,
1530
853
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1531
  } else {  // mkdir(path, mode, undefined, ctx)
1532
781
    CHECK_EQ(argc, 5);
1533
1562
    FSReqWrapSync req_wrap_sync;
1534

785
    FS_SYNC_TRACE_BEGIN(mkdir);
1535
781
    if (mkdirp) {
1536
109
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1537

214
      if (err == 0 &&
1538
105
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1539
        Local<Value> error;
1540
206
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1541
103
        FromNamespacedPath(&first_path);
1542
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1543
                                                     first_path.c_str(),
1544
103
                                                     UTF8, &error);
1545
103
        if (path.IsEmpty()) {
1546
          Local<Object> ctx = args[4].As<Object>();
1547
          ctx->Set(env->context(), env->error_string(), error).Check();
1548
          return;
1549
        }
1550
206
        args.GetReturnValue().Set(path.ToLocalChecked());
1551
      }
1552
    } else {
1553
672
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1554
672
               uv_fs_mkdir, *path, mode);
1555
    }
1556


785
    FS_SYNC_TRACE_END(mkdir);
1557
  }
1558
}
1559
1560
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1561
42
  Environment* env = Environment::GetCurrent(args);
1562
42
  Isolate* isolate = env->isolate();
1563
1564
42
  const int argc = args.Length();
1565
42
  CHECK_GE(argc, 3);
1566
1567
82
  BufferValue path(isolate, args[0]);
1568
42
  CHECK_NOT_NULL(*path);
1569
1570
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1571
1572
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1573
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1574
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1575
22
              uv_fs_realpath, *path);
1576
  } else {  // realpath(path, encoding, undefined, ctx)
1577
20
    CHECK_EQ(argc, 4);
1578
38
    FSReqWrapSync req_wrap_sync;
1579

22
    FS_SYNC_TRACE_BEGIN(realpath);
1580
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1581
20
                       uv_fs_realpath, *path);
1582

22
    FS_SYNC_TRACE_END(realpath);
1583
20
    if (err < 0) {
1584
2
      return;  // syscall failed, no need to continue, error info is in ctx
1585
    }
1586
1587
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1588
1589
    Local<Value> error;
1590
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1591
                                               link_path,
1592
                                               encoding,
1593
18
                                               &error);
1594
18
    if (rc.IsEmpty()) {
1595
      Local<Object> ctx = args[3].As<Object>();
1596
      ctx->Set(env->context(), env->error_string(), error).Check();
1597
      return;
1598
    }
1599
1600
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1601
  }
1602
}
1603
1604
13905
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1605
13905
  Environment* env = Environment::GetCurrent(args);
1606
13905
  Isolate* isolate = env->isolate();
1607
1608
13905
  const int argc = args.Length();
1609
13905
  CHECK_GE(argc, 3);
1610
1611
27713
  BufferValue path(isolate, args[0]);
1612
13905
  CHECK_NOT_NULL(*path);
1613
1614
13905
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1615
1616
27810
  bool with_types = args[2]->IsTrue();
1617
1618
13905
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1619
13905
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1620
136
    if (with_types) {
1621
7
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1622
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1623
    } else {
1624
129
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1625
129
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1626
    }
1627
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1628
13769
    CHECK_EQ(argc, 5);
1629
27441
    FSReqWrapSync req_wrap_sync;
1630

13771
    FS_SYNC_TRACE_BEGIN(readdir);
1631
13769
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1632
13769
                       uv_fs_scandir, *path, 0 /*flags*/);
1633

13771
    FS_SYNC_TRACE_END(readdir);
1634
13769
    if (err < 0) {
1635
97
      return;  // syscall failed, no need to continue, error info is in ctx
1636
    }
1637
1638
13672
    CHECK_GE(req_wrap_sync.req.result, 0);
1639
    int r;
1640
27344
    std::vector<Local<Value>> name_v;
1641
27344
    std::vector<Local<Value>> type_v;
1642
1643
705206
    for (int i = 0; ; i++) {
1644
      uv_dirent_t ent;
1645
1646
705206
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1647
705206
      if (r == UV_EOF)
1648
13672
        break;
1649
691534
      if (r != 0) {
1650
        Local<Object> ctx = args[4].As<Object>();
1651
        ctx->Set(env->context(), env->errno_string(),
1652
                 Integer::New(isolate, r)).Check();
1653
        ctx->Set(env->context(), env->syscall_string(),
1654
                 OneByteString(isolate, "readdir")).Check();
1655
        return;
1656
      }
1657
1658
      Local<Value> error;
1659
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1660
                                                       ent.name,
1661
                                                       encoding,
1662
691534
                                                       &error);
1663
1664
691534
      if (filename.IsEmpty()) {
1665
        Local<Object> ctx = args[4].As<Object>();
1666
        ctx->Set(env->context(), env->error_string(), error).Check();
1667
        return;
1668
      }
1669
1670
691534
      name_v.push_back(filename.ToLocalChecked());
1671
1672
691534
      if (with_types) {
1673
21418
        type_v.emplace_back(Integer::New(isolate, ent.type));
1674
      }
1675
691534
    }
1676
1677
1678
13672
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1679
13672
    if (with_types) {
1680
      Local<Value> result[] = {
1681
        names,
1682
        Array::New(isolate, type_v.data(), type_v.size())
1683
99
      };
1684
99
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1685
    } else {
1686
27278
      args.GetReturnValue().Set(names);
1687
    }
1688
  }
1689
}
1690
1691
44768
static void Open(const FunctionCallbackInfo<Value>& args) {
1692
44768
  Environment* env = Environment::GetCurrent(args);
1693
1694
44768
  const int argc = args.Length();
1695
44768
  CHECK_GE(argc, 3);
1696
1697
89536
  BufferValue path(env->isolate(), args[0]);
1698
44768
  CHECK_NOT_NULL(*path);
1699
1700
89536
  CHECK(args[1]->IsInt32());
1701
134304
  const int flags = args[1].As<Int32>()->Value();
1702
1703
89536
  CHECK(args[2]->IsInt32());
1704
134304
  const int mode = args[2].As<Int32>()->Value();
1705
1706
44768
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1707
44768
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1708
5335
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1709
5335
              uv_fs_open, *path, flags, mode);
1710
  } else {  // open(path, flags, mode, undefined, ctx)
1711
39433
    CHECK_EQ(argc, 5);
1712
78865
    FSReqWrapSync req_wrap_sync;
1713

39505
    FS_SYNC_TRACE_BEGIN(open);
1714
39433
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1715
39433
                          uv_fs_open, *path, flags, mode);
1716

39504
    FS_SYNC_TRACE_END(open);
1717
78864
    args.GetReturnValue().Set(result);
1718
  }
1719
44767
}
1720
1721
315
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1722
315
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1723
315
  Environment* env = binding_data->env();
1724
315
  Isolate* isolate = env->isolate();
1725
1726
315
  const int argc = args.Length();
1727
315
  CHECK_GE(argc, 3);
1728
1729
630
  BufferValue path(isolate, args[0]);
1730
315
  CHECK_NOT_NULL(*path);
1731
1732
630
  CHECK(args[1]->IsInt32());
1733
945
  const int flags = args[1].As<Int32>()->Value();
1734
1735
630
  CHECK(args[2]->IsInt32());
1736
945
  const int mode = args[2].As<Int32>()->Value();
1737
1738
315
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1739
315
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1740
314
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1741
314
              uv_fs_open, *path, flags, mode);
1742
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1743
1
    CHECK_EQ(argc, 5);
1744
2
    FSReqWrapSync req_wrap_sync;
1745

1
    FS_SYNC_TRACE_BEGIN(open);
1746
1
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1747
1
                          uv_fs_open, *path, flags, mode);
1748

1
    FS_SYNC_TRACE_END(open);
1749
1
    if (result < 0) {
1750
      return;  // syscall failed, no need to continue, error info is in ctx
1751
    }
1752
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1753
1
    if (fd == nullptr) return;
1754
3
    args.GetReturnValue().Set(fd->object());
1755
  }
1756
}
1757
1758
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1759
33
  Environment* env = Environment::GetCurrent(args);
1760
33
  Isolate* isolate = env->isolate();
1761
1762
33
  const int argc = args.Length();
1763
33
  CHECK_GE(argc, 3);
1764
1765
66
  BufferValue src(isolate, args[0]);
1766
33
  CHECK_NOT_NULL(*src);
1767
1768
66
  BufferValue dest(isolate, args[1]);
1769
33
  CHECK_NOT_NULL(*dest);
1770
1771
66
  CHECK(args[2]->IsInt32());
1772
99
  const int flags = args[2].As<Int32>()->Value();
1773
1774
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1775
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1776
14
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1777
14
                  *dest, dest.length(), UTF8, AfterNoArgs,
1778
14
                  uv_fs_copyfile, *src, *dest, flags);
1779
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1780
19
    CHECK_EQ(argc, 5);
1781
38
    FSReqWrapSync req_wrap_sync;
1782

21
    FS_SYNC_TRACE_BEGIN(copyfile);
1783
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1784
19
             uv_fs_copyfile, *src, *dest, flags);
1785

21
    FS_SYNC_TRACE_END(copyfile);
1786
  }
1787
33
}
1788
1789
1790
// Wrapper for write(2).
1791
//
1792
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1793
// 0 fd        integer. file descriptor
1794
// 1 buffer    the data to write
1795
// 2 offset    where in the buffer to start from
1796
// 3 length    how much to write
1797
// 4 position  if integer, position to write at in the file.
1798
//             if null, write from the current position
1799
54319
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1800
54319
  Environment* env = Environment::GetCurrent(args);
1801
1802
54319
  const int argc = args.Length();
1803
54319
  CHECK_GE(argc, 4);
1804
1805
108638
  CHECK(args[0]->IsInt32());
1806
162957
  const int fd = args[0].As<Int32>()->Value();
1807
1808
54319
  CHECK(Buffer::HasInstance(args[1]));
1809
108638
  Local<Object> buffer_obj = args[1].As<Object>();
1810
54319
  char* buffer_data = Buffer::Data(buffer_obj);
1811
54319
  size_t buffer_length = Buffer::Length(buffer_obj);
1812
1813
54319
  CHECK(IsSafeJsInt(args[2]));
1814
162957
  const int64_t off_64 = args[2].As<Integer>()->Value();
1815
54319
  CHECK_GE(off_64, 0);
1816
54319
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1817
54319
  const size_t off = static_cast<size_t>(off_64);
1818
1819
108638
  CHECK(args[3]->IsInt32());
1820
162957
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1821
54319
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1822
54319
  CHECK_LE(len, buffer_length);
1823
54319
  CHECK_GE(off + len, off);
1824
1825
54319
  const int64_t pos = GetOffset(args[4]);
1826
1827
54319
  char* buf = buffer_data + off;
1828
54319
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1829
1830
54319
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1831
54319
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1832
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1833
14424
              uv_fs_write, fd, &uvbuf, 1, pos);
1834
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1835
39895
    CHECK_EQ(argc, 7);
1836
79790
    FSReqWrapSync req_wrap_sync;
1837

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

39945
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1841
119685
    args.GetReturnValue().Set(bytesWritten);
1842
  }
1843
54319
}
1844
1845
1846
// Wrapper for writev(2).
1847
//
1848
// bytesWritten = writev(fd, chunks, position, callback)
1849
// 0 fd        integer. file descriptor
1850
// 1 chunks    array of buffers to write
1851
// 2 position  if integer, position to write at in the file.
1852
//             if null, write from the current position
1853
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1854
18
  Environment* env = Environment::GetCurrent(args);
1855
1856
18
  const int argc = args.Length();
1857
18
  CHECK_GE(argc, 3);
1858
1859
36
  CHECK(args[0]->IsInt32());
1860
54
  const int fd = args[0].As<Int32>()->Value();
1861
1862
36
  CHECK(args[1]->IsArray());
1863
36
  Local<Array> chunks = args[1].As<Array>();
1864
1865
18
  int64_t pos = GetOffset(args[2]);
1866
1867
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1868
1869
71
  for (uint32_t i = 0; i < iovs.length(); i++) {
1870
159
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1871
53
    CHECK(Buffer::HasInstance(chunk));
1872
53
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1873
  }
1874
1875
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1876
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1877
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1878
14
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1879
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1880
4
    CHECK_EQ(argc, 5);
1881
8
    FSReqWrapSync req_wrap_sync;
1882

4
    FS_SYNC_TRACE_BEGIN(write);
1883
8
    int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1884
4
                                uv_fs_write, fd, *iovs, iovs.length(), pos);
1885

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

4304
  if (!is_async && value->IsString()) {
1928
1399
    auto string = value.As<String>();
1929


1400
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1930
1
      auto ext = string->GetExternalOneByteStringResource();
1931
1
      buf = const_cast<char*>(ext->data());
1932
1
      len = ext->length();
1933


1399
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1934
2
      auto ext = string->GetExternalStringResource();
1935
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1936
1
      len = ext->length() * sizeof(*ext->data());
1937
    }
1938
  }
1939
1940
1506
  if (is_async) {  // write(fd, string, pos, enc, req)
1941
107
    CHECK_NOT_NULL(req_wrap_async);
1942
214
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1943
    FSReqBase::FSReqBuffer& stack_buffer =
1944
107
        req_wrap_async->Init("write", len, enc);
1945
    // StorageSize may return too large a char, so correct the actual length
1946
    // by the write size
1947
107
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1948
107
    stack_buffer.SetLengthAndZeroTerminate(len);
1949
107
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1950
107
    int err = req_wrap_async->Dispatch(uv_fs_write,
1951
                                       fd,
1952
                                       &uvbuf,
1953
                                       1,
1954
                                       pos,
1955
107
                                       AfterInteger);
1956
107
    if (err < 0) {
1957
      uv_fs_t* uv_req = req_wrap_async->req();
1958
      uv_req->result = err;
1959
      uv_req->path = nullptr;
1960
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1961
                             // an error
1962
    } else {
1963
107
      req_wrap_async->SetReturnValue(args);
1964
    }
1965
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1966
1399
    CHECK_EQ(argc, 6);
1967
2798
    FSReqWrapSync req_wrap_sync;
1968
2798
    FSReqBase::FSReqBuffer stack_buffer;
1969
1399
    if (buf == nullptr) {
1970
2794
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1971
        return;
1972
1397
      stack_buffer.AllocateSufficientStorage(len + 1);
1973
      // StorageSize may return too large a char, so correct the actual length
1974
      // by the write size
1975
1397
      len = StringBytes::Write(isolate, *stack_buffer,
1976
                               len, args[1], enc);
1977
1397
      stack_buffer.SetLengthAndZeroTerminate(len);
1978
1397
      buf = *stack_buffer;
1979
    }
1980
1399
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1981

1399
    FS_SYNC_TRACE_BEGIN(write);
1982
1399
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1983
1399
                                uv_fs_write, fd, &uvbuf, 1, pos);
1984

1399
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1985
4197
    args.GetReturnValue().Set(bytesWritten);
1986
  }
1987
}
1988
1989
1990
/*
1991
 * Wrapper for read(2).
1992
 *
1993
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1994
 *
1995
 * 0 fd        int32. file descriptor
1996
 * 1 buffer    instance of Buffer
1997
 * 2 offset    int64. offset to start reading into inside buffer
1998
 * 3 length    int32. length to read
1999
 * 4 position  int64. file position - -1 for current position
2000
 */
2001
52183
static void Read(const FunctionCallbackInfo<Value>& args) {
2002
52183
  Environment* env = Environment::GetCurrent(args);
2003
2004
52183
  const int argc = args.Length();
2005
52183
  CHECK_GE(argc, 5);
2006
2007
104366
  CHECK(args[0]->IsInt32());
2008
156549
  const int fd = args[0].As<Int32>()->Value();
2009
2010
52183
  CHECK(Buffer::HasInstance(args[1]));
2011
104366
  Local<Object> buffer_obj = args[1].As<Object>();
2012
52183
  char* buffer_data = Buffer::Data(buffer_obj);
2013
52183
  size_t buffer_length = Buffer::Length(buffer_obj);
2014
2015
52183
  CHECK(IsSafeJsInt(args[2]));
2016
156546
  const int64_t off_64 = args[2].As<Integer>()->Value();
2017
52182
  CHECK_GE(off_64, 0);
2018
52182
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2019
52182
  const size_t off = static_cast<size_t>(off_64);
2020
2021
104364
  CHECK(args[3]->IsInt32());
2022
156549
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2023
52183
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2024
2025
52183
  CHECK(IsSafeJsInt(args[4]));
2026
156549
  const int64_t pos = args[4].As<Integer>()->Value();
2027
2028
52182
  char* buf = buffer_data + off;
2029
52182
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2030
2031
52183
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2032
52182
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2033
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2034
14159
              uv_fs_read, fd, &uvbuf, 1, pos);
2035
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2036
38023
    CHECK_EQ(argc, 7);
2037
76047
    FSReqWrapSync req_wrap_sync;
2038

38033
    FS_SYNC_TRACE_BEGIN(read);
2039
38024
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2040
38024
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2041

38034
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2042
114072
    args.GetReturnValue().Set(bytesRead);
2043
  }
2044
52183
}
2045
2046
2047
// Wrapper for readv(2).
2048
//
2049
// bytesRead = fs.readv(fd, buffers[, position], callback)
2050
// 0 fd        integer. file descriptor
2051
// 1 buffers   array of buffers to read
2052
// 2 position  if integer, position to read at in the file.
2053
//             if null, read from the current position
2054
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2055
11
  Environment* env = Environment::GetCurrent(args);
2056
2057
11
  const int argc = args.Length();
2058
11
  CHECK_GE(argc, 3);
2059
2060
22
  CHECK(args[0]->IsInt32());
2061
33
  const int fd = args[0].As<Int32>()->Value();
2062
2063
22
  CHECK(args[1]->IsArray());
2064
22
  Local<Array> buffers = args[1].As<Array>();
2065
2066
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2067
2068
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2069
2070
  // Init uv buffers from ArrayBufferViews
2071
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2072
51
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2073
17
    CHECK(Buffer::HasInstance(buffer));
2074
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2075
  }
2076
2077
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2078
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2079
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2080
7
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2081
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2082
4
    CHECK_EQ(argc, 5);
2083
8
    FSReqWrapSync req_wrap_sync;
2084

4
    FS_SYNC_TRACE_BEGIN(read);
2085
8
    int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2086
4
                             uv_fs_read, fd, *iovs, iovs.length(), pos);
2087

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2088
12
    args.GetReturnValue().Set(bytesRead);
2089
  }
2090
11
}
2091
2092
2093
/* fs.chmod(path, mode);
2094
 * Wrapper for chmod(1) / EIO_CHMOD
2095
 */
2096
165
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2097
165
  Environment* env = Environment::GetCurrent(args);
2098
2099
165
  const int argc = args.Length();
2100
165
  CHECK_GE(argc, 2);
2101
2102
330
  BufferValue path(env->isolate(), args[0]);
2103
165
  CHECK_NOT_NULL(*path);
2104
2105
330
  CHECK(args[1]->IsInt32());
2106
495
  int mode = args[1].As<Int32>()->Value();
2107
2108
165
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2109
165
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2110
149
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2111
149
              uv_fs_chmod, *path, mode);
2112
  } else {  // chmod(path, mode, undefined, ctx)
2113
16
    CHECK_EQ(argc, 4);
2114
32
    FSReqWrapSync req_wrap_sync;
2115

18
    FS_SYNC_TRACE_BEGIN(chmod);
2116
16
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2117
16
             uv_fs_chmod, *path, mode);
2118

18
    FS_SYNC_TRACE_END(chmod);
2119
  }
2120
165
}
2121
2122
2123
/* fs.fchmod(fd, mode);
2124
 * Wrapper for fchmod(1) / EIO_FCHMOD
2125
 */
2126
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2127
12
  Environment* env = Environment::GetCurrent(args);
2128
2129
12
  const int argc = args.Length();
2130
12
  CHECK_GE(argc, 2);
2131
2132
24
  CHECK(args[0]->IsInt32());
2133
36
  const int fd = args[0].As<Int32>()->Value();
2134
2135
24
  CHECK(args[1]->IsInt32());
2136
36
  const int mode = args[1].As<Int32>()->Value();
2137
2138
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2139
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2140
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2141
7
              uv_fs_fchmod, fd, mode);
2142
  } else {  // fchmod(fd, mode, undefined, ctx)
2143
5
    CHECK_EQ(argc, 4);
2144
10
    FSReqWrapSync req_wrap_sync;
2145

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2146
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2147
5
             uv_fs_fchmod, fd, mode);
2148

7
    FS_SYNC_TRACE_END(fchmod);
2149
  }
2150
12
}
2151
2152
2153
/* fs.chown(path, uid, gid);
2154
 * Wrapper for chown(1) / EIO_CHOWN
2155
 */
2156
73
static void Chown(const FunctionCallbackInfo<Value>& args) {
2157
73
  Environment* env = Environment::GetCurrent(args);
2158
2159
73
  const int argc = args.Length();
2160
73
  CHECK_GE(argc, 3);
2161
2162
146
  BufferValue path(env->isolate(), args[0]);
2163
73
  CHECK_NOT_NULL(*path);
2164
2165
146
  CHECK(args[1]->IsUint32());
2166
219
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2167
2168
146
  CHECK(args[2]->IsUint32());
2169
219
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2170
2171
73
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2172
73
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2173
70
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2174
70
              uv_fs_chown, *path, uid, gid);
2175
  } else {  // chown(path, uid, gid, undefined, ctx)
2176
3
    CHECK_EQ(argc, 5);
2177
6
    FSReqWrapSync req_wrap_sync;
2178

5
    FS_SYNC_TRACE_BEGIN(chown);
2179
3
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2180
3
             uv_fs_chown, *path, uid, gid);
2181

5
    FS_SYNC_TRACE_END(chown);
2182
  }
2183
73
}
2184
2185
2186
/* fs.fchown(fd, uid, gid);
2187
 * Wrapper for fchown(1) / EIO_FCHOWN
2188
 */
2189
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2190
4
  Environment* env = Environment::GetCurrent(args);
2191
2192
4
  const int argc = args.Length();
2193
4
  CHECK_GE(argc, 3);
2194
2195
8
  CHECK(args[0]->IsInt32());
2196
12
  const int fd = args[0].As<Int32>()->Value();
2197
2198
8
  CHECK(args[1]->IsUint32());
2199
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2200
2201
8
  CHECK(args[2]->IsUint32());
2202
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2203
2204
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2205
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2206
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2207
2
              uv_fs_fchown, fd, uid, gid);
2208
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2209
2
    CHECK_EQ(argc, 5);
2210
4
    FSReqWrapSync req_wrap_sync;
2211

4
    FS_SYNC_TRACE_BEGIN(fchown);
2212
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2213
2
             uv_fs_fchown, fd, uid, gid);
2214

4
    FS_SYNC_TRACE_END(fchown);
2215
  }
2216
4
}
2217
2218
2219
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2220
9
  Environment* env = Environment::GetCurrent(args);
2221
2222
9
  const int argc = args.Length();
2223
9
  CHECK_GE(argc, 3);
2224
2225
18
  BufferValue path(env->isolate(), args[0]);
2226
9
  CHECK_NOT_NULL(*path);
2227
2228
18
  CHECK(args[1]->IsUint32());
2229
27
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2230
2231
18
  CHECK(args[2]->IsUint32());
2232
27
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2233
2234
9
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2235
9
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2236
7
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2237
7
              uv_fs_lchown, *path, uid, gid);
2238
  } else {  // lchown(path, uid, gid, undefined, ctx)
2239
2
    CHECK_EQ(argc, 5);
2240
4
    FSReqWrapSync req_wrap_sync;
2241

4
    FS_SYNC_TRACE_BEGIN(lchown);
2242
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2243
2
             uv_fs_lchown, *path, uid, gid);
2244

4
    FS_SYNC_TRACE_END(lchown);
2245
  }
2246
9
}
2247
2248
2249
33
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2250
33
  Environment* env = Environment::GetCurrent(args);
2251
2252
33
  const int argc = args.Length();
2253
33
  CHECK_GE(argc, 3);
2254
2255
66
  BufferValue path(env->isolate(), args[0]);
2256
33
  CHECK_NOT_NULL(*path);
2257
2258
66
  CHECK(args[1]->IsNumber());
2259
99
  const double atime = args[1].As<Number>()->Value();
2260
2261
66
  CHECK(args[2]->IsNumber());
2262
99
  const double mtime = args[2].As<Number>()->Value();
2263
2264
33
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2265
33
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2266
16
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2267
16
              uv_fs_utime, *path, atime, mtime);
2268
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2269
17
    CHECK_EQ(argc, 5);
2270
34
    FSReqWrapSync req_wrap_sync;
2271

19
    FS_SYNC_TRACE_BEGIN(utimes);
2272
17
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2273
17
             uv_fs_utime, *path, atime, mtime);
2274

19
    FS_SYNC_TRACE_END(utimes);
2275
  }
2276
33
}
2277
2278
1273
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2279
1273
  Environment* env = Environment::GetCurrent(args);
2280
2281
1273
  const int argc = args.Length();
2282
1273
  CHECK_GE(argc, 3);
2283
2284
2546
  CHECK(args[0]->IsInt32());
2285
3819
  const int fd = args[0].As<Int32>()->Value();
2286
2287
2546
  CHECK(args[1]->IsNumber());
2288
3819
  const double atime = args[1].As<Number>()->Value();
2289
2290
2546
  CHECK(args[2]->IsNumber());
2291
3819
  const double mtime = args[2].As<Number>()->Value();
2292
2293
1273
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2294
1273
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2295
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2296
1264
              uv_fs_futime, fd, atime, mtime);
2297
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2298
9
    CHECK_EQ(argc, 5);
2299
18
    FSReqWrapSync req_wrap_sync;
2300

11
    FS_SYNC_TRACE_BEGIN(futimes);
2301
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2302
9
             uv_fs_futime, fd, atime, mtime);
2303

11
    FS_SYNC_TRACE_END(futimes);
2304
  }
2305
1273
}
2306
2307
14
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2308
14
  Environment* env = Environment::GetCurrent(args);
2309
2310
14
  const int argc = args.Length();
2311
14
  CHECK_GE(argc, 3);
2312
2313
28
  BufferValue path(env->isolate(), args[0]);
2314
14
  CHECK_NOT_NULL(*path);
2315
2316
28
  CHECK(args[1]->IsNumber());
2317
42
  const double atime = args[1].As<Number>()->Value();
2318
2319
28
  CHECK(args[2]->IsNumber());
2320
42
  const double mtime = args[2].As<Number>()->Value();
2321
2322
14
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2323
14
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2324
7
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2325
7
              uv_fs_lutime, *path, atime, mtime);
2326
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2327
7
    CHECK_EQ(argc, 5);
2328
14
    FSReqWrapSync req_wrap_sync;
2329

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2330
7
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2331
7
             uv_fs_lutime, *path, atime, mtime);
2332

7
    FS_SYNC_TRACE_END(lutimes);
2333
  }
2334
14
}
2335
2336
14
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2337
14
  Environment* env = Environment::GetCurrent(args);
2338
14
  Isolate* isolate = env->isolate();
2339
2340
14
  const int argc = args.Length();
2341
14
  CHECK_GE(argc, 2);
2342
2343
28
  BufferValue tmpl(isolate, args[0]);
2344
14
  CHECK_NOT_NULL(*tmpl);
2345
2346
14
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2347
2348
14
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2349
14
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2350
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2351
6
              uv_fs_mkdtemp, *tmpl);
2352
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2353
8
    CHECK_EQ(argc, 4);
2354
16
    FSReqWrapSync req_wrap_sync;
2355

10
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2356
8
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2357
8
             uv_fs_mkdtemp, *tmpl);
2358

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

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