GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.cc Lines: 1450 1532 94.6 %
Date: 2022-02-06 04:14:03 Branches: 798 1250 63.8 %

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

22
  if (str_size >= extension.size() &&
102
11
      str.compare(str.size() - extension.size(),
103
        extension.size(), extension) == 0) {
104
    str_size -= extension.size();
105
  }
106
107
11
  return str.substr(start_pos, str_size);
108
}
109
110
185552
inline int64_t GetOffset(Local<Value> value) {
111
186643
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
112
}
113
114
#define TRACE_NAME(name) "fs.sync." #name
115
#define GET_TRACE_ENABLED                                                  \
116
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
117
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
118
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
119
  if (GET_TRACE_ENABLED)                                                   \
120
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
121
  ##__VA_ARGS__);
122
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
123
  if (GET_TRACE_ENABLED)                                                   \
124
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
125
  ##__VA_ARGS__);
126
127
// We sometimes need to convert a C++ lambda function to a raw C-style function.
128
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
129
// functions, and thus does not wrap them properly.
130
typedef void(*uv_fs_callback_t)(uv_fs_t*);
131
132
133
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
134
  tracker->TrackField("paths", paths_);
135
}
136
137
FileHandleReadWrap::~FileHandleReadWrap() = default;
138
139
FSReqBase::~FSReqBase() = default;
140
141
2
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
142
2
  tracker->TrackField("continuation_data", continuation_data_);
143
2
}
144
145
// The FileHandle object wraps a file descriptor and will close it on garbage
146
// collection if necessary. If that happens, a process warning will be
147
// emitted (or a fatal exception will occur if the fd cannot be closed.)
148
1102
FileHandle::FileHandle(BindingData* binding_data,
149
1102
                       Local<Object> obj, int fd)
150
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
151
      StreamBase(env()),
152
      fd_(fd),
153
1102
      binding_data_(binding_data) {
154
1102
  MakeWeak();
155
1102
  StreamBase::AttachToObject(GetObject());
156
1102
}
157
158
1102
FileHandle* FileHandle::New(BindingData* binding_data,
159
                            int fd, Local<Object> obj) {
160
1102
  Environment* env = binding_data->env();
161
2189
  if (obj.IsEmpty() && !env->fd_constructor_template()
162
2189
                            ->NewInstance(env->context())
163
1087
                            .ToLocal(&obj)) {
164
    return nullptr;
165
  }
166
1102
  return new FileHandle(binding_data, obj, fd);
167
}
168
169
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
170
15
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
171
15
  Environment* env = binding_data->env();
172
15
  CHECK(args.IsConstructCall());
173
15
  CHECK(args[0]->IsInt32());
174
175
  FileHandle* handle =
176
30
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
177
15
  if (handle == nullptr) return;
178
15
  if (args[1]->IsNumber())
179
30
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
180
30
  if (args[2]->IsNumber())
181
30
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
182
}
183
184
4288
FileHandle::~FileHandle() {
185
2144
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
186
2144
  Close();           // Close synchronously and emit warning
187
2144
  CHECK(closed_);    // We have to be closed at the point
188
4288
}
189
190
int FileHandle::DoWrite(WriteWrap* w,
191
                        uv_buf_t* bufs,
192
                        size_t count,
193
                        uv_stream_t* send_handle) {
194
  return UV_ENOSYS;  // Not implemented (yet).
195
}
196
197
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
198
  tracker->TrackField("current_read", current_read_);
199
}
200
201
10
FileHandle::TransferMode FileHandle::GetTransferMode() const {
202

10
  return reading_ || closing_ || closed_ ?
203
10
      TransferMode::kUntransferable : TransferMode::kTransferable;
204
}
205
206
6
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
207
6
  CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
208
12
  auto ret = std::make_unique<TransferData>(fd_);
209
6
  closed_ = true;
210
6
  return ret;
211
}
212
213
6
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
214
215
24
FileHandle::TransferData::~TransferData() {
216
12
  if (fd_ > 0) {
217
    uv_fs_t close_req;
218
8
    CHECK_NE(fd_, -1);
219
8
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
220
8
    uv_fs_req_cleanup(&close_req);
221
  }
222
24
}
223
224
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
225
    Environment* env,
226
    v8::Local<v8::Context> context,
227
    std::unique_ptr<worker::TransferData> self) {
228
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
229
2
  if (bd == nullptr) return {};
230
231
2
  int fd = fd_;
232
2
  fd_ = -1;
233
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
234
}
235
236
// Close the file descriptor if it hasn't already been closed. A process
237
// warning will be emitted using a SetImmediate to avoid calling back to
238
// JS during GC. If closing the fd fails at this point, a fatal exception
239
// will crash the process immediately.
240
1072
inline void FileHandle::Close() {
241

1072
  if (closed_ || closing_) return;
242
  uv_fs_t req;
243
16
  CHECK_NE(fd_, -1);
244
16
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
245
16
  uv_fs_req_cleanup(&req);
246
247
  struct err_detail { int ret; int fd; };
248
249
16
  err_detail detail { ret, fd_ };
250
251
16
  AfterClose();
252
253
16
  if (ret < 0) {
254
    // Do not unref this
255
    env()->SetImmediate([detail](Environment* env) {
256
      char msg[70];
257
      snprintf(msg, arraysize(msg),
258
              "Closing file descriptor %d on garbage collection failed",
259
              detail.fd);
260
      // This exception will end up being fatal for the process because
261
      // it is being thrown from within the SetImmediate handler and
262
      // there is no JS stack to bubble it to. In other words, tearing
263
      // down the process is the only reasonable thing we can do here.
264
      HandleScope handle_scope(env->isolate());
265
      env->ThrowUVException(detail.ret, "close", msg);
266
    });
267
    return;
268
  }
269
270
  // If the close was successful, we still want to emit a process warning
271
  // to notify that the file descriptor was gc'd. We want to be noisy about
272
  // this because not explicitly closing the FileHandle is a bug.
273
274
16
  env()->SetImmediate([detail](Environment* env) {
275
    ProcessEmitWarning(env,
276
                       "Closing file descriptor %d on garbage collection",
277
4
                       detail.fd);
278
4
    if (env->filehandle_close_warning()) {
279
3
      env->set_filehandle_close_warning(false);
280
3
      ProcessEmitDeprecationWarning(
281
          env,
282
          "Closing a FileHandle object on garbage collection is deprecated. "
283
          "Please close FileHandle objects explicitly using "
284
          "FileHandle.prototype.close(). In the future, an error will be "
285
          "thrown if a file descriptor is closed during garbage collection.",
286
3
          "DEP0137").IsNothing();
287
    }
288
4
  }, CallbackFlags::kUnrefed);
289
}
290
291
1069
void FileHandle::CloseReq::Resolve() {
292
1069
  Isolate* isolate = env()->isolate();
293
2119
  HandleScope scope(isolate);
294
1069
  Context::Scope context_scope(env()->context());
295
1069
  InternalCallbackScope callback_scope(this);
296
2138
  Local<Promise> promise = promise_.Get(isolate);
297
1069
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
298
3207
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
299
1050
}
300
301
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
302
1
  Isolate* isolate = env()->isolate();
303
2
  HandleScope scope(isolate);
304
1
  Context::Scope context_scope(env()->context());
305
1
  InternalCallbackScope callback_scope(this);
306
2
  Local<Promise> promise = promise_.Get(isolate);
307
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
308
2
  resolver->Reject(env()->context(), reason).Check();
309
1
}
310
311
1070
FileHandle* FileHandle::CloseReq::file_handle() {
312
1070
  Isolate* isolate = env()->isolate();
313
1070
  HandleScope scope(isolate);
314
2140
  Local<Value> val = ref_.Get(isolate);
315
1070
  Local<Object> obj = val.As<Object>();
316
1070
  return Unwrap<FileHandle>(obj);
317
}
318
319
1070
FileHandle::CloseReq::CloseReq(Environment* env,
320
                               Local<Object> obj,
321
                               Local<Promise> promise,
322
1070
                               Local<Value> ref)
323
1070
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
324
1070
  promise_.Reset(env->isolate(), promise);
325
1070
  ref_.Reset(env->isolate(), ref);
326
1070
}
327
328
8408
FileHandle::CloseReq::~CloseReq() {
329
2102
  uv_fs_req_cleanup(req());
330
2102
  promise_.Reset();
331
2102
  ref_.Reset();
332
4204
}
333
334
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
335
  tracker->TrackField("promise", promise_);
336
  tracker->TrackField("ref", ref_);
337
}
338
339
340
341
// Closes this FileHandle asynchronously and returns a Promise that will be
342
// resolved when the callback is invoked, or rejects with a UVException if
343
// there was a problem closing the fd. This is the preferred mechanism for
344
// closing the FD object even tho the object will attempt to close
345
// automatically on gc.
346
1070
MaybeLocal<Promise> FileHandle::ClosePromise() {
347
1070
  Isolate* isolate = env()->isolate();
348
1070
  EscapableHandleScope scope(isolate);
349
1070
  Local<Context> context = env()->context();
350
351
  Local<Value> close_resolver =
352
3210
      object()->GetInternalField(FileHandle::kClosingPromiseSlot);
353

3210
  if (!close_resolver.IsEmpty() && !close_resolver->IsUndefined()) {
354
    CHECK(close_resolver->IsPromise());
355
    return close_resolver.As<Promise>();
356
  }
357
358
1070
  CHECK(!closed_);
359
1070
  CHECK(!closing_);
360
1070
  CHECK(!reading_);
361
362
1070
  auto maybe_resolver = Promise::Resolver::New(context);
363
1070
  CHECK(!maybe_resolver.IsEmpty());
364
1070
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
365
1070
  Local<Promise> promise = resolver.As<Promise>();
366
367
  Local<Object> close_req_obj;
368
1070
  if (!env()->fdclose_constructor_template()
369
2140
          ->NewInstance(env()->context()).ToLocal(&close_req_obj)) {
370
    return MaybeLocal<Promise>();
371
  }
372
1070
  closing_ = true;
373
2140
  object()->SetInternalField(FileHandle::kClosingPromiseSlot, promise);
374
375
2140
  CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
376
2140
  auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
377
2121
    std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
378
1070
    CHECK_NOT_NULL(close);
379
1070
    close->file_handle()->AfterClose();
380
1070
    Isolate* isolate = close->env()->isolate();
381
1070
    if (req->result < 0) {
382
2
      HandleScope handle_scope(isolate);
383
2
      close->Reject(
384
1
          UVException(isolate, static_cast<int>(req->result), "close"));
385
    } else {
386
1069
      close->Resolve();
387
    }
388
1051
  }};
389
1070
  CHECK_NE(fd_, -1);
390
1070
  int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
391
1070
  if (ret < 0) {
392
    req->Reject(UVException(isolate, ret, "close"));
393
    delete req;
394
  }
395
396
1070
  return scope.Escape(promise);
397
}
398
399
1070
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
400
  FileHandle* fd;
401
1070
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
402
  Local<Promise> ret;
403
2140
  if (!fd->ClosePromise().ToLocal(&ret)) return;
404
2140
  args.GetReturnValue().Set(ret);
405
}
406
407
408
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
409
  FileHandle* fd;
410
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
411
  // Just act as if this FileHandle has been closed.
412
8
  fd->AfterClose();
413
}
414
415
416
1094
void FileHandle::AfterClose() {
417
1094
  closing_ = false;
418
1094
  closed_ = true;
419
1094
  fd_ = -1;
420

1094
  if (reading_ && !persistent().IsEmpty())
421
    EmitRead(UV_EOF);
422
1094
}
423
424
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
425
  tracker->TrackField("buffer", buffer_);
426
  tracker->TrackField("file_handle", this->file_handle_);
427
}
428
429
16
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
430
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
431
16
    file_handle_(handle) {}
432
433
217
int FileHandle::ReadStart() {
434

217
  if (!IsAlive() || IsClosing())
435
    return UV_EOF;
436
437
217
  reading_ = true;
438
439
217
  if (current_read_)
440
3
    return 0;
441
442
428
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
443
444
214
  if (read_length_ == 0) {
445
5
    EmitRead(UV_EOF);
446
5
    return 0;
447
  }
448
449
  {
450
    // Create a new FileHandleReadWrap or re-use one.
451
    // Either way, we need these two scopes for AsyncReset() or otherwise
452
    // for creating the new instance.
453
209
    HandleScope handle_scope(env()->isolate());
454
209
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
455
456
209
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
457
209
    if (freelist.size() > 0) {
458
193
      read_wrap = std::move(freelist.back());
459
193
      freelist.pop_back();
460
      // Use a fresh async resource.
461
      // Lifetime is ensured via AsyncWrap::resource_.
462
193
      Local<Object> resource = Object::New(env()->isolate());
463
193
      USE(resource->Set(
464
579
          env()->context(), env()->handle_string(), read_wrap->object()));
465
193
      read_wrap->AsyncReset(resource);
466
193
      read_wrap->file_handle_ = this;
467
    } else {
468
      Local<Object> wrap_obj;
469
32
      if (!env()
470
16
               ->filehandlereadwrap_template()
471
16
               ->NewInstance(env()->context())
472
16
               .ToLocal(&wrap_obj)) {
473
        return UV_EBUSY;
474
      }
475
16
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
476
    }
477
  }
478
209
  int64_t recommended_read = 65536;
479

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

208
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
522
        result = handle->read_length_;
523
524
      // If we read data and we have an expected length, decrease it by
525
      // how much we have read.
526
208
      if (handle->read_length_ >= 0)
527
9
        handle->read_length_ -= result;
528
529
      // If we have an offset, increase it by how much we have read.
530
208
      if (handle->read_offset_ >= 0)
531
204
        handle->read_offset_ += result;
532
    }
533
534
    // Reading 0 bytes from a file always means EOF, or that we reached
535
    // the end of the requested range.
536
209
    if (result == 0)
537
8
      result = UV_EOF;
538
539
209
    handle->EmitRead(result, buffer);
540
541
    // Start over, if EmitRead() didn’t tell us to stop.
542
209
    if (handle->reading_)
543
1
      handle->ReadStart();
544
209
  }});
545
546
209
  return 0;
547
}
548
549
228
int FileHandle::ReadStop() {
550
228
  reading_ = false;
551
228
  return 0;
552
}
553
554
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
555
556
3
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
557
3
  return new FileHandleCloseWrap(this, object);
558
}
559
560
3
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
561

3
  if (closing_ || closed_) {
562
3
    req_wrap->Done(0);
563
3
    return 1;
564
  }
565
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
566
  closing_ = true;
567
  CHECK_NE(fd_, -1);
568
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
569
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
570
        FileHandleCloseWrap::from_req(req));
571
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
572
    handle->AfterClose();
573
574
    int result = static_cast<int>(req->result);
575
    uv_fs_req_cleanup(req);
576
    wrap->Done(result);
577
  }});
578
579
  return 0;
580
}
581
582
583
4647
void FSReqCallback::Reject(Local<Value> reject) {
584
4647
  MakeCallback(env()->oncomplete_string(), 1, &reject);
585
4647
}
586
587
2468
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
588
2468
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
589
2468
}
590
591
46585
void FSReqCallback::Resolve(Local<Value> value) {
592
  Local<Value> argv[2] {
593
    Null(env()->isolate()),
594
    value
595
46585
  };
596
  MakeCallback(env()->oncomplete_string(),
597
86273
               value->IsUndefined() ? 1 : arraysize(argv),
598
132858
               argv);
599
46581
}
600
601
51232
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
602
51232
  args.GetReturnValue().SetUndefined();
603
51232
}
604
605
51232
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
606
51232
  CHECK(args.IsConstructCall());
607
51232
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
608
102464
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
609
51232
}
610
611
55651
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
612
    : wrap_(wrap),
613
      req_(req),
614
      handle_scope_(wrap->env()->isolate()),
615
55651
      context_scope_(wrap->env()->context()) {
616
55651
  CHECK_EQ(wrap_->req(), req);
617
55651
}
618
619
111294
FSReqAfterScope::~FSReqAfterScope() {
620
55647
  Clear();
621
55647
}
622
623
60836
void FSReqAfterScope::Clear() {
624
60836
  if (!wrap_) return;
625
626
55647
  uv_fs_req_cleanup(wrap_->req());
627
55647
  wrap_->Detach();
628
55647
  wrap_.reset();
629
}
630
631
// TODO(joyeecheung): create a normal context object, and
632
// construct the actual errors in the JS land using the context.
633
// The context should include fds for some fs APIs, currently they are
634
// missing in the error messages. The path, dest, syscall, fd, .etc
635
// can be put into the context before the binding is even invoked,
636
// the only information that has to come from the C++ layer is the
637
// error number (and possibly the syscall for abstraction),
638
// which is also why the errors should have been constructed
639
// in JS for more flexibility.
640
5053
void FSReqAfterScope::Reject(uv_fs_t* req) {
641
10106
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
642
5053
  Local<Value> exception = UVException(wrap_->env()->isolate(),
643
5053
                                       static_cast<int>(req->result),
644
                                       wrap_->syscall(),
645
                                       nullptr,
646
                                       req->path,
647
5053
                                       wrap_->data());
648
5053
  Clear();
649
5053
  wrap->Reject(exception);
650
5053
}
651
652
55651
bool FSReqAfterScope::Proceed() {
653
55651
  if (req_->result < 0) {
654
5053
    Reject(req_);
655
5053
    return false;
656
  }
657
50598
  return true;
658
}
659
660
7213
void AfterNoArgs(uv_fs_t* req) {
661
7213
  FSReqBase* req_wrap = FSReqBase::from_req(req);
662
14423
  FSReqAfterScope after(req_wrap, req);
663
664
7213
  if (after.Proceed())
665
14102
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
666
7210
}
667
668
8448
void AfterStat(uv_fs_t* req) {
669
8448
  FSReqBase* req_wrap = FSReqBase::from_req(req);
670
16896
  FSReqAfterScope after(req_wrap, req);
671
672
8448
  if (after.Proceed()) {
673
3879
    req_wrap->ResolveStat(&req->statbuf);
674
  }
675
8448
}
676
677
37831
void AfterInteger(uv_fs_t* req) {
678
37831
  FSReqBase* req_wrap = FSReqBase::from_req(req);
679
75662
  FSReqAfterScope after(req_wrap, req);
680
681
37831
  int result = static_cast<int>(req->result);
682

37831
  if (result >= 0 && req_wrap->is_plain_open())
683
5389
    req_wrap->env()->AddUnmanagedFd(result);
684
685
37831
  if (after.Proceed())
686
75300
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
687
37831
}
688
689
1204
void AfterOpenFileHandle(uv_fs_t* req) {
690
1204
  FSReqBase* req_wrap = FSReqBase::from_req(req);
691
1204
  FSReqAfterScope after(req_wrap, req);
692
693
1204
  if (after.Proceed()) {
694
1084
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
695
1084
                                     static_cast<int>(req->result));
696
1084
    if (fd == nullptr) return;
697
2168
    req_wrap->Resolve(fd->object());
698
  }
699
}
700
701
// Reverse the logic applied by path.toNamespacedPath() to create a
702
// namespace-prefixed path.
703
506
void FromNamespacedPath(std::string* path) {
704
#ifdef _WIN32
705
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
706
    *path = path->substr(8);
707
    path->insert(0, "\\\\");
708
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
709
    *path = path->substr(4);
710
  }
711
#endif
712
506
}
713
714
374
void AfterMkdirp(uv_fs_t* req) {
715
374
  FSReqBase* req_wrap = FSReqBase::from_req(req);
716
374
  FSReqAfterScope after(req_wrap, req);
717
374
  if (after.Proceed()) {
718
736
    std::string first_path(req_wrap->continuation_data()->first_path());
719
368
    if (first_path.empty())
720
264
      return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
721
236
    FromNamespacedPath(&first_path);
722
    Local<Value> path;
723
    Local<Value> error;
724
236
    if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
725
                             req_wrap->encoding(),
726
472
                             &error).ToLocal(&path)) {
727
      return req_wrap->Reject(error);
728
    }
729
236
    return req_wrap->Resolve(path);
730
  }
731
}
732
733
6
void AfterStringPath(uv_fs_t* req) {
734
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
735
12
  FSReqAfterScope after(req_wrap, req);
736
737
  MaybeLocal<Value> link;
738
  Local<Value> error;
739
740
6
  if (after.Proceed()) {
741
    link = StringBytes::Encode(req_wrap->env()->isolate(),
742
                               req->path,
743
                               req_wrap->encoding(),
744
5
                               &error);
745
5
    if (link.IsEmpty())
746
      req_wrap->Reject(error);
747
    else
748
10
      req_wrap->Resolve(link.ToLocalChecked());
749
  }
750
6
}
751
752
64
void AfterStringPtr(uv_fs_t* req) {
753
64
  FSReqBase* req_wrap = FSReqBase::from_req(req);
754
127
  FSReqAfterScope after(req_wrap, req);
755
756
  MaybeLocal<Value> link;
757
  Local<Value> error;
758
759
64
  if (after.Proceed()) {
760
    link = StringBytes::Encode(req_wrap->env()->isolate(),
761
58
                               static_cast<const char*>(req->ptr),
762
                               req_wrap->encoding(),
763
58
                               &error);
764
58
    if (link.IsEmpty())
765
      req_wrap->Reject(error);
766
    else
767
116
      req_wrap->Resolve(link.ToLocalChecked());
768
  }
769
63
}
770
771
89
void AfterScanDir(uv_fs_t* req) {
772
89
  FSReqBase* req_wrap = FSReqBase::from_req(req);
773
89
  FSReqAfterScope after(req_wrap, req);
774
775
89
  if (!after.Proceed()) {
776
6
    return;
777
  }
778
83
  Environment* env = req_wrap->env();
779
  Local<Value> error;
780
  int r;
781
83
  std::vector<Local<Value>> name_v;
782
783
  for (;;) {
784
    uv_dirent_t ent;
785
786
7499
    r = uv_fs_scandir_next(req, &ent);
787
7499
    if (r == UV_EOF)
788
83
      break;
789
7416
    if (r != 0) {
790
      return req_wrap->Reject(UVException(
791
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
792
    }
793
794
    MaybeLocal<Value> filename =
795
      StringBytes::Encode(env->isolate(),
796
          ent.name,
797
          req_wrap->encoding(),
798
7416
          &error);
799
7416
    if (filename.IsEmpty())
800
      return req_wrap->Reject(error);
801
802
7416
    name_v.push_back(filename.ToLocalChecked());
803
7416
  }
804
805
166
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
806
}
807
808
125
void AfterScanDirWithTypes(uv_fs_t* req) {
809
125
  FSReqBase* req_wrap = FSReqBase::from_req(req);
810
125
  FSReqAfterScope after(req_wrap, req);
811
812
125
  if (!after.Proceed()) {
813
1
    return;
814
  }
815
816
124
  Environment* env = req_wrap->env();
817
124
  Isolate* isolate = env->isolate();
818
  Local<Value> error;
819
  int r;
820
821
124
  std::vector<Local<Value>> name_v;
822
124
  std::vector<Local<Value>> type_v;
823
824
  for (;;) {
825
    uv_dirent_t ent;
826
827
141
    r = uv_fs_scandir_next(req, &ent);
828
141
    if (r == UV_EOF)
829
124
      break;
830
17
    if (r != 0) {
831
      return req_wrap->Reject(
832
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
833
    }
834
835
    MaybeLocal<Value> filename =
836
      StringBytes::Encode(isolate,
837
          ent.name,
838
          req_wrap->encoding(),
839
17
          &error);
840
17
    if (filename.IsEmpty())
841
      return req_wrap->Reject(error);
842
843
17
    name_v.push_back(filename.ToLocalChecked());
844
17
    type_v.emplace_back(Integer::New(isolate, ent.type));
845
17
  }
846
847
  Local<Value> result[] = {
848
    Array::New(isolate, name_v.data(), name_v.size()),
849
    Array::New(isolate, type_v.data(), type_v.size())
850
248
  };
851
248
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
852
}
853
854
3892
void Access(const FunctionCallbackInfo<Value>& args) {
855
3892
  Environment* env = Environment::GetCurrent(args);
856
3892
  Isolate* isolate = env->isolate();
857
7784
  HandleScope scope(isolate);
858
859
3892
  const int argc = args.Length();
860
3892
  CHECK_GE(argc, 2);
861
862
3892
  CHECK(args[1]->IsInt32());
863
7784
  int mode = args[1].As<Int32>()->Value();
864
865
7784
  BufferValue path(isolate, args[0]);
866
3892
  CHECK_NOT_NULL(*path);
867
868
3892
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
869
3892
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
870
44
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
871
              uv_fs_access, *path, mode);
872
  } else {  // access(path, mode, undefined, ctx)
873
3848
    CHECK_EQ(argc, 4);
874
7696
    FSReqWrapSync req_wrap_sync;
875

3850
    FS_SYNC_TRACE_BEGIN(access);
876
7696
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
877

3850
    FS_SYNC_TRACE_END(access);
878
  }
879
3892
}
880
881
882
63140
void Close(const FunctionCallbackInfo<Value>& args) {
883
63140
  Environment* env = Environment::GetCurrent(args);
884
885
63140
  const int argc = args.Length();
886
63140
  CHECK_GE(argc, 2);
887
888
63140
  CHECK(args[0]->IsInt32());
889
126280
  int fd = args[0].As<Int32>()->Value();
890
63140
  env->RemoveUnmanagedFd(fd);
891
892
63140
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
893
63140
  if (req_wrap_async != nullptr) {  // close(fd, req)
894
5307
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
895
              uv_fs_close, fd);
896
  } else {  // close(fd, undefined, ctx)
897
57833
    CHECK_EQ(argc, 3);
898
115666
    FSReqWrapSync req_wrap_sync;
899

57889
    FS_SYNC_TRACE_BEGIN(close);
900
57833
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
901

57889
    FS_SYNC_TRACE_END(close);
902
  }
903
63140
}
904
905
906
// Used to speed up module loading. Returns an array [string, boolean]
907
51387
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
908
51387
  Environment* env = Environment::GetCurrent(args);
909
51387
  Isolate* isolate = env->isolate();
910
51387
  uv_loop_t* loop = env->event_loop();
911
912
102774
  CHECK(args[0]->IsString());
913
51387
  node::Utf8Value path(isolate, args[0]);
914
915
51387
  if (strlen(*path) != path.length()) {
916
3
    args.GetReturnValue().Set(Array::New(isolate));
917
3
    return;  // Contains a nul byte.
918
  }
919
  uv_fs_t open_req;
920
51384
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
921
51384
  uv_fs_req_cleanup(&open_req);
922
923
51384
  if (fd < 0) {
924
45770
    args.GetReturnValue().Set(Array::New(isolate));
925
45770
    return;
926
  }
927
928
5614
  auto defer_close = OnScopeLeave([fd, loop]() {
929
    uv_fs_t close_req;
930
5614
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
931
5614
    uv_fs_req_cleanup(&close_req);
932
5614
  });
933
934
5614
  const size_t kBlockSize = 32 << 10;
935
5614
  std::vector<char> chars;
936
5614
  int64_t offset = 0;
937
  ssize_t numchars;
938
  do {
939
5614
    const size_t start = chars.size();
940
5614
    chars.resize(start + kBlockSize);
941
942
    uv_buf_t buf;
943
5614
    buf.base = &chars[start];
944
5614
    buf.len = kBlockSize;
945
946
    uv_fs_t read_req;
947
5614
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
948
5614
    uv_fs_req_cleanup(&read_req);
949
950
5614
    if (numchars < 0) {
951
1
      args.GetReturnValue().Set(Array::New(isolate));
952
1
      return;
953
    }
954
5613
    offset += numchars;
955
5613
  } while (static_cast<size_t>(numchars) == kBlockSize);
956
957
5613
  size_t start = 0;
958

5613
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
959
1
    start = 3;  // Skip UTF-8 BOM.
960
  }
961
962
5613
  const size_t size = offset - start;
963
5613
  char* p = &chars[start];
964
5613
  char* pe = &chars[size];
965
  char* pos[2];
966
5613
  char** ppos = &pos[0];
967
968
79092
  while (p < pe) {
969
79080
    char c = *p++;
970

79080
    if (c == '\\' && p < pe && *p == '"') p++;
971
79080
    if (c != '"') continue;
972
12864
    *ppos++ = p;
973
12864
    if (ppos < &pos[2]) continue;
974
6432
    ppos = &pos[0];
975
976
6432
    char* s = &pos[0][0];
977
6432
    char* se = &pos[1][-1];  // Exclude quote.
978
6432
    size_t n = se - s;
979
980
6432
    if (n == 4) {
981
5594
      if (0 == memcmp(s, "main", 4)) break;
982
5551
      if (0 == memcmp(s, "name", 4)) break;
983
51
      if (0 == memcmp(s, "type", 4)) break;
984
838
    } else if (n == 7) {
985
12
      if (0 == memcmp(s, "exports", 7)) break;
986
6
      if (0 == memcmp(s, "imports", 7)) break;
987
    }
988
  }
989
990
991
  Local<Value> return_value[] = {
992
5613
    String::NewFromUtf8(isolate,
993
5613
                        &chars[start],
994
                        v8::NewStringType::kNormal,
995
5613
                        size).ToLocalChecked(),
996
    Boolean::New(isolate, p < pe ? true : false)
997
16839
  };
998
11226
  args.GetReturnValue().Set(
999
    Array::New(isolate, return_value, arraysize(return_value)));
1000
}
1001
1002
// Used to speed up module loading.  Returns 0 if the path refers to
1003
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
1004
// The speedup comes from not creating thousands of Stat and Error objects.
1005
148428
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
1006
148428
  Environment* env = Environment::GetCurrent(args);
1007
1008
296856
  CHECK(args[0]->IsString());
1009
148428
  node::Utf8Value path(env->isolate(), args[0]);
1010
1011
  uv_fs_t req;
1012
148428
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1013
148428
  if (rc == 0) {
1014
74581
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1015
74581
    rc = !!(s->st_mode & S_IFDIR);
1016
  }
1017
148428
  uv_fs_req_cleanup(&req);
1018
1019
296856
  args.GetReturnValue().Set(rc);
1020
148428
}
1021
1022
17467
static void Stat(const FunctionCallbackInfo<Value>& args) {
1023
17467
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1024
17467
  Environment* env = binding_data->env();
1025
1026
17467
  const int argc = args.Length();
1027
17467
  CHECK_GE(argc, 2);
1028
1029
17467
  BufferValue path(env->isolate(), args[0]);
1030
17467
  CHECK_NOT_NULL(*path);
1031
1032
17467
  bool use_bigint = args[1]->IsTrue();
1033
17467
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1034
17467
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1035
2547
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1036
              uv_fs_stat, *path);
1037
  } else {  // stat(path, use_bigint, undefined, ctx)
1038
14920
    CHECK_EQ(argc, 4);
1039
14920
    FSReqWrapSync req_wrap_sync;
1040

14922
    FS_SYNC_TRACE_BEGIN(stat);
1041
29840
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1042

14922
    FS_SYNC_TRACE_END(stat);
1043
14920
    if (err != 0) {
1044
717
      return;  // error info is in ctx
1045
    }
1046
1047
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1048
14203
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1049
28406
    args.GetReturnValue().Set(arr);
1050
  }
1051
}
1052
1053
113909
static void LStat(const FunctionCallbackInfo<Value>& args) {
1054
113909
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1055
113909
  Environment* env = binding_data->env();
1056
1057
113909
  const int argc = args.Length();
1058
113909
  CHECK_GE(argc, 3);
1059
1060
113909
  BufferValue path(env->isolate(), args[0]);
1061
113909
  CHECK_NOT_NULL(*path);
1062
1063
113909
  bool use_bigint = args[1]->IsTrue();
1064
113909
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1065
113909
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1066
4842
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1067
              uv_fs_lstat, *path);
1068
  } else {  // lstat(path, use_bigint, undefined, ctx)
1069
109067
    CHECK_EQ(argc, 4);
1070
109067
    FSReqWrapSync req_wrap_sync;
1071

109084
    FS_SYNC_TRACE_BEGIN(lstat);
1072
218134
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1073
                       *path);
1074

109084
    FS_SYNC_TRACE_END(lstat);
1075
109067
    if (err != 0) {
1076
425
      return;  // error info is in ctx
1077
    }
1078
1079
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1080
108642
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1081
217284
    args.GetReturnValue().Set(arr);
1082
  }
1083
}
1084
1085
53111
static void FStat(const FunctionCallbackInfo<Value>& args) {
1086
53111
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1087
53111
  Environment* env = binding_data->env();
1088
1089
53111
  const int argc = args.Length();
1090
53111
  CHECK_GE(argc, 2);
1091
1092
53111
  CHECK(args[0]->IsInt32());
1093
106222
  int fd = args[0].As<Int32>()->Value();
1094
1095
53111
  bool use_bigint = args[1]->IsTrue();
1096
53111
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1097
53111
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1098
1061
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1099
              uv_fs_fstat, fd);
1100
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1101
52050
    CHECK_EQ(argc, 4);
1102
52050
    FSReqWrapSync req_wrap_sync;
1103

52058
    FS_SYNC_TRACE_BEGIN(fstat);
1104
52050
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1105

52058
    FS_SYNC_TRACE_END(fstat);
1106
52050
    if (err != 0) {
1107
21
      return;  // error info is in ctx
1108
    }
1109
1110
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1111
52029
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1112
104058
    args.GetReturnValue().Set(arr);
1113
  }
1114
}
1115
1116
349
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1117
349
  Environment* env = Environment::GetCurrent(args);
1118
349
  Isolate* isolate = env->isolate();
1119
1120
349
  const int argc = args.Length();
1121
349
  CHECK_GE(argc, 4);
1122
1123
698
  BufferValue target(isolate, args[0]);
1124
349
  CHECK_NOT_NULL(*target);
1125
698
  BufferValue path(isolate, args[1]);
1126
349
  CHECK_NOT_NULL(*path);
1127
1128
349
  CHECK(args[2]->IsInt32());
1129
698
  int flags = args[2].As<Int32>()->Value();
1130
1131
349
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1132
349
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1133
23
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1134
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1135
  } else {  // symlink(target, path, flags, undefinec, ctx)
1136
326
    CHECK_EQ(argc, 5);
1137
652
    FSReqWrapSync req_wrap_sync;
1138

330
    FS_SYNC_TRACE_BEGIN(symlink);
1139
652
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1140
             uv_fs_symlink, *target, *path, flags);
1141

330
    FS_SYNC_TRACE_END(symlink);
1142
  }
1143
349
}
1144
1145
16
static void Link(const FunctionCallbackInfo<Value>& args) {
1146
16
  Environment* env = Environment::GetCurrent(args);
1147
16
  Isolate* isolate = env->isolate();
1148
1149
16
  const int argc = args.Length();
1150
16
  CHECK_GE(argc, 3);
1151
1152
32
  BufferValue src(isolate, args[0]);
1153
16
  CHECK_NOT_NULL(*src);
1154
1155
32
  BufferValue dest(isolate, args[1]);
1156
16
  CHECK_NOT_NULL(*dest);
1157
1158
16
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1159
16
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1160
11
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1161
                  AfterNoArgs, uv_fs_link, *src, *dest);
1162
  } else {  // link(src, dest)
1163
5
    CHECK_EQ(argc, 4);
1164
10
    FSReqWrapSync req_wrap_sync;
1165

11
    FS_SYNC_TRACE_BEGIN(link);
1166
10
    SyncCall(env, args[3], &req_wrap_sync, "link",
1167
             uv_fs_link, *src, *dest);
1168

11
    FS_SYNC_TRACE_END(link);
1169
  }
1170
16
}
1171
1172
102
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1173
102
  Environment* env = Environment::GetCurrent(args);
1174
102
  Isolate* isolate = env->isolate();
1175
1176
102
  const int argc = args.Length();
1177
102
  CHECK_GE(argc, 3);
1178
1179
102
  BufferValue path(isolate, args[0]);
1180
102
  CHECK_NOT_NULL(*path);
1181
1182
102
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1183
1184
102
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1185
102
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1186
42
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1187
              uv_fs_readlink, *path);
1188
  } else {
1189
60
    CHECK_EQ(argc, 4);
1190
60
    FSReqWrapSync req_wrap_sync;
1191

62
    FS_SYNC_TRACE_BEGIN(readlink);
1192
120
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1193
                       uv_fs_readlink, *path);
1194

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

5
    FS_SYNC_TRACE_BEGIN(rename);
1236
6
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1237
             *old_path, *new_path);
1238

5
    FS_SYNC_TRACE_END(rename);
1239
  }
1240
6
}
1241
1242
69
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1243
69
  Environment* env = Environment::GetCurrent(args);
1244
1245
69
  const int argc = args.Length();
1246
69
  CHECK_GE(argc, 3);
1247
1248
69
  CHECK(args[0]->IsInt32());
1249
138
  const int fd = args[0].As<Int32>()->Value();
1250
1251
69
  CHECK(IsSafeJsInt(args[1]));
1252
138
  const int64_t len = args[1].As<Integer>()->Value();
1253
1254
69
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1255
69
  if (req_wrap_async != nullptr) {
1256
54
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1257
              uv_fs_ftruncate, fd, len);
1258
  } else {
1259
15
    CHECK_EQ(argc, 4);
1260
30
    FSReqWrapSync req_wrap_sync;
1261

17
    FS_SYNC_TRACE_BEGIN(ftruncate);
1262
15
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1263
             len);
1264

17
    FS_SYNC_TRACE_END(ftruncate);
1265
  }
1266
69
}
1267
1268
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1269
7
  Environment* env = Environment::GetCurrent(args);
1270
1271
7
  const int argc = args.Length();
1272
7
  CHECK_GE(argc, 2);
1273
1274
7
  CHECK(args[0]->IsInt32());
1275
14
  const int fd = args[0].As<Int32>()->Value();
1276
1277
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1278
7
  if (req_wrap_async != nullptr) {
1279
4
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1280
              uv_fs_fdatasync, fd);
1281
  } else {
1282
3
    CHECK_EQ(argc, 3);
1283
6
    FSReqWrapSync req_wrap_sync;
1284

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

5
    FS_SYNC_TRACE_END(fdatasync);
1287
  }
1288
7
}
1289
1290
21
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1291
21
  Environment* env = Environment::GetCurrent(args);
1292
1293
21
  const int argc = args.Length();
1294
21
  CHECK_GE(argc, 2);
1295
1296
21
  CHECK(args[0]->IsInt32());
1297
42
  const int fd = args[0].As<Int32>()->Value();
1298
1299
21
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1300
21
  if (req_wrap_async != nullptr) {
1301
4
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1302
              uv_fs_fsync, fd);
1303
  } else {
1304
17
    CHECK_EQ(argc, 3);
1305
34
    FSReqWrapSync req_wrap_sync;
1306

19
    FS_SYNC_TRACE_BEGIN(fsync);
1307
17
    SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1308

19
    FS_SYNC_TRACE_END(fsync);
1309
  }
1310
21
}
1311
1312
2524
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1313
2524
  Environment* env = Environment::GetCurrent(args);
1314
1315
2524
  const int argc = args.Length();
1316
2524
  CHECK_GE(argc, 2);
1317
1318
5048
  BufferValue path(env->isolate(), args[0]);
1319
2524
  CHECK_NOT_NULL(*path);
1320
1321
2524
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1322
2524
  if (req_wrap_async != nullptr) {
1323
1010
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1324
              uv_fs_unlink, *path);
1325
  } else {
1326
1514
    CHECK_EQ(argc, 3);
1327
3028
    FSReqWrapSync req_wrap_sync;
1328

1569
    FS_SYNC_TRACE_BEGIN(unlink);
1329
3028
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1330

1569
    FS_SYNC_TRACE_END(unlink);
1331
  }
1332
2524
}
1333
1334
1793
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1335
1793
  Environment* env = Environment::GetCurrent(args);
1336
1337
1793
  const int argc = args.Length();
1338
1793
  CHECK_GE(argc, 2);
1339
1340
3586
  BufferValue path(env->isolate(), args[0]);
1341
1793
  CHECK_NOT_NULL(*path);
1342
1343
1793
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1344
1793
  if (req_wrap_async != nullptr) {
1345
225
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1346
              uv_fs_rmdir, *path);
1347
  } else {  // rmdir(path, undefined, ctx)
1348
1568
    CHECK_EQ(argc, 3);
1349
3136
    FSReqWrapSync req_wrap_sync;
1350

1574
    FS_SYNC_TRACE_BEGIN(rmdir);
1351
3136
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1352
             uv_fs_rmdir, *path);
1353

1574
    FS_SYNC_TRACE_END(rmdir);
1354
  }
1355
1793
}
1356
1357
5795
int MKDirpSync(uv_loop_t* loop,
1358
               uv_fs_t* req,
1359
               const std::string& path,
1360
               int mode,
1361
               uv_fs_cb cb) {
1362
5795
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1363
1364
  // on the first iteration of algorithm, stash state information.
1365
5795
  if (req_wrap->continuation_data() == nullptr) {
1366
5795
    req_wrap->set_continuation_data(
1367
11590
        std::make_unique<FSContinuationData>(req, mode, cb));
1368
5795
    req_wrap->continuation_data()->PushPath(std::move(path));
1369
  }
1370
1371
11444
  while (req_wrap->continuation_data()->paths().size() > 0) {
1372
5945
    std::string next_path = req_wrap->continuation_data()->PopPath();
1373
5945
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1374
    while (true) {
1375

5946
      switch (err) {
1376
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1377
        // ~FSReqWrapSync():
1378
366
        case 0:
1379
366
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1380
366
          if (req_wrap->continuation_data()->paths().size() == 0) {
1381
292
            return 0;
1382
          }
1383
74
          break;
1384
2
        case UV_EACCES:
1385
        case UV_ENOTDIR:
1386
        case UV_EPERM: {
1387
2
          return err;
1388
        }
1389
76
        case UV_ENOENT: {
1390
          std::string dirname = next_path.substr(0,
1391
76
                                        next_path.find_last_of(kPathSeparator));
1392
76
          if (dirname != next_path) {
1393
75
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1394
75
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1395
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1396
1
            err = UV_EEXIST;
1397
1
            continue;
1398
          }
1399
75
          break;
1400
        }
1401
5502
        default:
1402
5502
          uv_fs_req_cleanup(req);
1403
5502
          int orig_err = err;
1404
5502
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1405

5502
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1406
1
            uv_fs_req_cleanup(req);
1407

2
            if (orig_err == UV_EEXIST &&
1408
1
              req_wrap->continuation_data()->paths().size() > 0) {
1409
              return UV_ENOTDIR;
1410
            }
1411
1
            return UV_EEXIST;
1412
          }
1413
5501
          if (err < 0) return err;
1414
5500
          break;
1415
      }
1416
5649
      break;
1417
1
    }
1418
5649
    uv_fs_req_cleanup(req);
1419
  }
1420
1421
5499
  return 0;
1422
}
1423
1424
630
int MKDirpAsync(uv_loop_t* loop,
1425
                uv_fs_t* req,
1426
                const char* path,
1427
                int mode,
1428
                uv_fs_cb cb) {
1429
630
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1430
  // on the first iteration of algorithm, stash state information.
1431
630
  if (req_wrap->continuation_data() == nullptr) {
1432
374
    req_wrap->set_continuation_data(
1433
748
        std::make_unique<FSContinuationData>(req, mode, cb));
1434
374
    req_wrap->continuation_data()->PushPath(std::move(path));
1435
  }
1436
1437
  // on each iteration of algorithm, mkdir directory on top of stack.
1438
630
  std::string next_path = req_wrap->continuation_data()->PopPath();
1439
630
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1440
630
                        uv_fs_callback_t{[](uv_fs_t* req) {
1441
630
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1442
630
    Environment* env = req_wrap->env();
1443
630
    uv_loop_t* loop = env->event_loop();
1444
1260
    std::string path = req->path;
1445
630
    int err = static_cast<int>(req->result);
1446
1447
    while (true) {
1448

631
      switch (err) {
1449
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1450
        // FSReqAfterScope::~FSReqAfterScope()
1451
249
        case 0: {
1452
249
          if (req_wrap->continuation_data()->paths().size() == 0) {
1453
236
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1454
236
            req_wrap->continuation_data()->Done(0);
1455
          } else {
1456
13
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1457
13
            uv_fs_req_cleanup(req);
1458
13
            MKDirpAsync(loop, req, path.c_str(),
1459
                        req_wrap->continuation_data()->mode(), nullptr);
1460
          }
1461
249
          break;
1462
        }
1463
3
        case UV_EACCES:
1464
        case UV_ENOTDIR:
1465
        case UV_EPERM: {
1466
3
          req_wrap->continuation_data()->Done(err);
1467
3
          break;
1468
        }
1469
129
        case UV_ENOENT: {
1470
          std::string dirname = path.substr(0,
1471
129
                                            path.find_last_of(kPathSeparator));
1472
129
          if (dirname != path) {
1473
128
            req_wrap->continuation_data()->PushPath(std::move(path));
1474
128
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1475
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1476
1
            err = UV_EEXIST;
1477
1
            continue;
1478
          }
1479
128
          uv_fs_req_cleanup(req);
1480
128
          MKDirpAsync(loop, req, path.c_str(),
1481
                      req_wrap->continuation_data()->mode(), nullptr);
1482
128
          break;
1483
        }
1484
250
        default:
1485
250
          uv_fs_req_cleanup(req);
1486
          // Stash err for use in the callback.
1487
250
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1488
250
          int err = uv_fs_stat(loop, req, path.c_str(),
1489
250
                               uv_fs_callback_t{[](uv_fs_t* req) {
1490
250
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1491
250
            int err = static_cast<int>(req->result);
1492

500
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1493
250
                  req_wrap->continuation_data()->paths().size() > 0) {
1494

115
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1495
115
                Environment* env = req_wrap->env();
1496
115
                uv_loop_t* loop = env->event_loop();
1497
115
                std::string path = req->path;
1498
115
                uv_fs_req_cleanup(req);
1499
115
                MKDirpAsync(loop, req, path.c_str(),
1500
                            req_wrap->continuation_data()->mode(), nullptr);
1501
115
                return;
1502
              }
1503
              err = UV_ENOTDIR;
1504
            }
1505
            // verify that the path pointed to is actually a directory.
1506

135
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1507
135
            req_wrap->continuation_data()->Done(err);
1508
250
          }});
1509
250
          if (err < 0) req_wrap->continuation_data()->Done(err);
1510
250
          break;
1511
      }
1512
630
      break;
1513
1
    }
1514
630
  }});
1515
1516
630
  return err;
1517
}
1518
1519
277
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1520
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1521
277
  env->PrintSyncTrace();
1522
277
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1523
                       nullptr);
1524
277
  if (err < 0) {
1525
4
    v8::Local<v8::Context> context = env->context();
1526
4
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1527
4
    v8::Isolate* isolate = env->isolate();
1528
4
    ctx_obj->Set(context,
1529
                 env->errno_string(),
1530
16
                 v8::Integer::New(isolate, err)).Check();
1531
4
    ctx_obj->Set(context,
1532
                 env->syscall_string(),
1533
16
                 OneByteString(isolate, "mkdir")).Check();
1534
  }
1535
277
  return err;
1536
}
1537
1538
1771
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1539
1771
  Environment* env = Environment::GetCurrent(args);
1540
1541
1771
  const int argc = args.Length();
1542
1771
  CHECK_GE(argc, 4);
1543
1544
1771
  BufferValue path(env->isolate(), args[0]);
1545
1771
  CHECK_NOT_NULL(*path);
1546
1547
1771
  CHECK(args[1]->IsInt32());
1548
3542
  const int mode = args[1].As<Int32>()->Value();
1549
1550
1771
  CHECK(args[2]->IsBoolean());
1551
1771
  bool mkdirp = args[2]->IsTrue();
1552
1553
1771
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1554
1771
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1555

595
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1556
              mkdirp ? AfterMkdirp : AfterNoArgs,
1557
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1558
  } else {  // mkdir(path, mode, undefined, ctx)
1559
1176
    CHECK_EQ(argc, 5);
1560
1176
    FSReqWrapSync req_wrap_sync;
1561

1180
    FS_SYNC_TRACE_BEGIN(mkdir);
1562
1176
    if (mkdirp) {
1563
277
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1564

550
      if (err == 0 &&
1565
273
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1566
        Local<Value> error;
1567
270
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1568
270
        FromNamespacedPath(&first_path);
1569
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1570
                                                     first_path.c_str(),
1571
270
                                                     UTF8, &error);
1572
270
        if (path.IsEmpty()) {
1573
          Local<Object> ctx = args[4].As<Object>();
1574
          ctx->Set(env->context(), env->error_string(), error).Check();
1575
          return;
1576
        }
1577
540
        args.GetReturnValue().Set(path.ToLocalChecked());
1578
      }
1579
    } else {
1580
1798
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1581
               uv_fs_mkdir, *path, mode);
1582
    }
1583

1180
    FS_SYNC_TRACE_END(mkdir);
1584
  }
1585
}
1586
1587
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1588
42
  Environment* env = Environment::GetCurrent(args);
1589
42
  Isolate* isolate = env->isolate();
1590
1591
42
  const int argc = args.Length();
1592
42
  CHECK_GE(argc, 3);
1593
1594
42
  BufferValue path(isolate, args[0]);
1595
42
  CHECK_NOT_NULL(*path);
1596
1597
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1598
1599
42
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1600
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1601
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1602
              uv_fs_realpath, *path);
1603
  } else {  // realpath(path, encoding, undefined, ctx)
1604
20
    CHECK_EQ(argc, 4);
1605
20
    FSReqWrapSync req_wrap_sync;
1606

22
    FS_SYNC_TRACE_BEGIN(realpath);
1607
40
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1608
                       uv_fs_realpath, *path);
1609

22
    FS_SYNC_TRACE_END(realpath);
1610
20
    if (err < 0) {
1611
2
      return;  // syscall failed, no need to continue, error info is in ctx
1612
    }
1613
1614
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1615
1616
    Local<Value> error;
1617
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1618
                                               link_path,
1619
                                               encoding,
1620
18
                                               &error);
1621
18
    if (rc.IsEmpty()) {
1622
      Local<Object> ctx = args[3].As<Object>();
1623
      ctx->Set(env->context(), env->error_string(), error).Check();
1624
      return;
1625
    }
1626
1627
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1628
  }
1629
}
1630
1631
13945
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1632
13945
  Environment* env = Environment::GetCurrent(args);
1633
13945
  Isolate* isolate = env->isolate();
1634
1635
13945
  const int argc = args.Length();
1636
13945
  CHECK_GE(argc, 3);
1637
1638
13945
  BufferValue path(isolate, args[0]);
1639
13945
  CHECK_NOT_NULL(*path);
1640
1641
13945
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1642
1643
13945
  bool with_types = args[2]->IsTrue();
1644
1645
13945
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1646
13945
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1647
214
    if (with_types) {
1648
125
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1649
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1650
    } else {
1651
89
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1652
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1653
    }
1654
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1655
13731
    CHECK_EQ(argc, 5);
1656
13731
    FSReqWrapSync req_wrap_sync;
1657

13733
    FS_SYNC_TRACE_BEGIN(readdir);
1658
27462
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1659
                       uv_fs_scandir, *path, 0 /*flags*/);
1660

13733
    FS_SYNC_TRACE_END(readdir);
1661
13731
    if (err < 0) {
1662
133
      return;  // syscall failed, no need to continue, error info is in ctx
1663
    }
1664
1665
13598
    CHECK_GE(req_wrap_sync.req.result, 0);
1666
    int r;
1667
13598
    std::vector<Local<Value>> name_v;
1668
13598
    std::vector<Local<Value>> type_v;
1669
1670
    for (;;) {
1671
      uv_dirent_t ent;
1672
1673
767312
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1674
767312
      if (r == UV_EOF)
1675
13598
        break;
1676
753714
      if (r != 0) {
1677
        Local<Object> ctx = args[4].As<Object>();
1678
        ctx->Set(env->context(), env->errno_string(),
1679
                 Integer::New(isolate, r)).Check();
1680
        ctx->Set(env->context(), env->syscall_string(),
1681
                 OneByteString(isolate, "readdir")).Check();
1682
        return;
1683
      }
1684
1685
      Local<Value> error;
1686
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1687
                                                       ent.name,
1688
                                                       encoding,
1689
753714
                                                       &error);
1690
1691
753714
      if (filename.IsEmpty()) {
1692
        Local<Object> ctx = args[4].As<Object>();
1693
        ctx->Set(env->context(), env->error_string(), error).Check();
1694
        return;
1695
      }
1696
1697
753714
      name_v.push_back(filename.ToLocalChecked());
1698
1699
753714
      if (with_types) {
1700
48473
        type_v.emplace_back(Integer::New(isolate, ent.type));
1701
      }
1702
753714
    }
1703
1704
1705
13598
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1706
13598
    if (with_types) {
1707
      Local<Value> result[] = {
1708
        names,
1709
        Array::New(isolate, type_v.data(), type_v.size())
1710
386
      };
1711
386
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1712
    } else {
1713
26810
      args.GetReturnValue().Set(names);
1714
    }
1715
  }
1716
}
1717
1718
63872
static void Open(const FunctionCallbackInfo<Value>& args) {
1719
63872
  Environment* env = Environment::GetCurrent(args);
1720
1721
63872
  const int argc = args.Length();
1722
63872
  CHECK_GE(argc, 3);
1723
1724
127744
  BufferValue path(env->isolate(), args[0]);
1725
63872
  CHECK_NOT_NULL(*path);
1726
1727
63872
  CHECK(args[1]->IsInt32());
1728
127744
  const int flags = args[1].As<Int32>()->Value();
1729
1730
63872
  CHECK(args[2]->IsInt32());
1731
127744
  const int mode = args[2].As<Int32>()->Value();
1732
1733
63872
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1734
63872
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1735
5563
    req_wrap_async->set_is_plain_open(true);
1736
5563
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1737
              uv_fs_open, *path, flags, mode);
1738
  } else {  // open(path, flags, mode, undefined, ctx)
1739
58309
    CHECK_EQ(argc, 5);
1740
58309
    FSReqWrapSync req_wrap_sync;
1741

58371
    FS_SYNC_TRACE_BEGIN(open);
1742
116618
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1743
                          uv_fs_open, *path, flags, mode);
1744

58371
    FS_SYNC_TRACE_END(open);
1745
58309
    if (result >= 0) env->AddUnmanagedFd(result);
1746
116618
    args.GetReturnValue().Set(result);
1747
  }
1748
63872
}
1749
1750
1207
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1751
1207
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1752
1207
  Environment* env = binding_data->env();
1753
1207
  Isolate* isolate = env->isolate();
1754
1755
1207
  const int argc = args.Length();
1756
1207
  CHECK_GE(argc, 3);
1757
1758
1207
  BufferValue path(isolate, args[0]);
1759
1207
  CHECK_NOT_NULL(*path);
1760
1761
1207
  CHECK(args[1]->IsInt32());
1762
2414
  const int flags = args[1].As<Int32>()->Value();
1763
1764
1207
  CHECK(args[2]->IsInt32());
1765
2414
  const int mode = args[2].As<Int32>()->Value();
1766
1767
1207
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1768
1207
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1769
1206
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1770
              uv_fs_open, *path, flags, mode);
1771
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1772
1
    CHECK_EQ(argc, 5);
1773
1
    FSReqWrapSync req_wrap_sync;
1774

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

1
    FS_SYNC_TRACE_END(open);
1778
1
    if (result < 0) {
1779
      return;  // syscall failed, no need to continue, error info is in ctx
1780
    }
1781
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1782
1
    if (fd == nullptr) return;
1783
2
    args.GetReturnValue().Set(fd->object());
1784
  }
1785
}
1786
1787
214
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1788
214
  Environment* env = Environment::GetCurrent(args);
1789
214
  Isolate* isolate = env->isolate();
1790
1791
214
  const int argc = args.Length();
1792
214
  CHECK_GE(argc, 3);
1793
1794
428
  BufferValue src(isolate, args[0]);
1795
214
  CHECK_NOT_NULL(*src);
1796
1797
428
  BufferValue dest(isolate, args[1]);
1798
214
  CHECK_NOT_NULL(*dest);
1799
1800
214
  CHECK(args[2]->IsInt32());
1801
428
  const int flags = args[2].As<Int32>()->Value();
1802
1803
214
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1804
214
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1805
204
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1806
102
                  *dest, dest.length(), UTF8, AfterNoArgs,
1807
                  uv_fs_copyfile, *src, *dest, flags);
1808
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1809
112
    CHECK_EQ(argc, 5);
1810
224
    FSReqWrapSync req_wrap_sync;
1811

114
    FS_SYNC_TRACE_BEGIN(copyfile);
1812
224
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1813
             uv_fs_copyfile, *src, *dest, flags);
1814

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

44974
    FS_SYNC_TRACE_BEGIN(write);
1867
44924
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1868
44924
                                uv_fs_write, fd, &uvbuf, 1, pos);
1869

44974
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1870
89848
    args.GetReturnValue().Set(bytesWritten);
1871
  }
1872
62438
}
1873
1874
1875
// Wrapper for writev(2).
1876
//
1877
// bytesWritten = writev(fd, chunks, position, callback)
1878
// 0 fd        integer. file descriptor
1879
// 1 chunks    array of buffers to write
1880
// 2 position  if integer, position to write at in the file.
1881
//             if null, write from the current position
1882
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1883
18
  Environment* env = Environment::GetCurrent(args);
1884
1885
18
  const int argc = args.Length();
1886
18
  CHECK_GE(argc, 3);
1887
1888
18
  CHECK(args[0]->IsInt32());
1889
36
  const int fd = args[0].As<Int32>()->Value();
1890
1891
18
  CHECK(args[1]->IsArray());
1892
36
  Local<Array> chunks = args[1].As<Array>();
1893
1894
18
  int64_t pos = GetOffset(args[2]);
1895
1896
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1897
1898
71
  for (uint32_t i = 0; i < iovs.length(); i++) {
1899
53
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1900
53
    CHECK(Buffer::HasInstance(chunk));
1901
53
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1902
  }
1903
1904
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1905
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1906
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1907
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1908
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1909
4
    CHECK_EQ(argc, 5);
1910
4
    FSReqWrapSync req_wrap_sync;
1911

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

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

369097
  if (!is_async && value->IsString()) {
1957
123006
    auto string = value.As<String>();
1958


123007
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1959
1
      auto ext = string->GetExternalOneByteStringResource();
1960
1
      buf = const_cast<char*>(ext->data());
1961
1
      len = ext->length();
1962


123006
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
1963
1
      auto ext = string->GetExternalStringResource();
1964
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1965
1
      len = ext->length() * sizeof(*ext->data());
1966
    }
1967
  }
1968
1969
123085
  if (is_async) {  // write(fd, string, pos, enc, req)
1970
79
    CHECK_NOT_NULL(req_wrap_async);
1971
158
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1972
    FSReqBase::FSReqBuffer& stack_buffer =
1973
79
        req_wrap_async->Init("write", len, enc);
1974
    // StorageSize may return too large a char, so correct the actual length
1975
    // by the write size
1976
79
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1977
79
    stack_buffer.SetLengthAndZeroTerminate(len);
1978
79
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1979
79
    int err = req_wrap_async->Dispatch(uv_fs_write,
1980
                                       fd,
1981
                                       &uvbuf,
1982
                                       1,
1983
                                       pos,
1984
                                       AfterInteger);
1985
79
    if (err < 0) {
1986
      uv_fs_t* uv_req = req_wrap_async->req();
1987
      uv_req->result = err;
1988
      uv_req->path = nullptr;
1989
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1990
                             // an error
1991
    } else {
1992
79
      req_wrap_async->SetReturnValue(args);
1993
    }
1994
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1995
123006
    CHECK_EQ(argc, 6);
1996
123006
    FSReqWrapSync req_wrap_sync;
1997
123006
    FSReqBase::FSReqBuffer stack_buffer;
1998
123006
    if (buf == nullptr) {
1999
246008
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
2000
        return;
2001
123004
      stack_buffer.AllocateSufficientStorage(len + 1);
2002
      // StorageSize may return too large a char, so correct the actual length
2003
      // by the write size
2004
123004
      len = StringBytes::Write(isolate, *stack_buffer,
2005
                               len, args[1], enc);
2006
123004
      stack_buffer.SetLengthAndZeroTerminate(len);
2007
123004
      buf = *stack_buffer;
2008
    }
2009
123006
    uv_buf_t uvbuf = uv_buf_init(buf, len);
2010

123006
    FS_SYNC_TRACE_BEGIN(write);
2011
123006
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2012
123006
                                uv_fs_write, fd, &uvbuf, 1, pos);
2013

123006
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2014
246012
    args.GetReturnValue().Set(bytesWritten);
2015
  }
2016
}
2017
2018
2019
/*
2020
 * Wrapper for read(2).
2021
 *
2022
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2023
 *
2024
 * 0 fd        int32. file descriptor
2025
 * 1 buffer    instance of Buffer
2026
 * 2 offset    int64. offset to start reading into inside buffer
2027
 * 3 length    int32. length to read
2028
 * 4 position  int64. file position - -1 for current position
2029
 */
2030
70661
static void Read(const FunctionCallbackInfo<Value>& args) {
2031
70661
  Environment* env = Environment::GetCurrent(args);
2032
2033
70661
  const int argc = args.Length();
2034
70661
  CHECK_GE(argc, 5);
2035
2036
70661
  CHECK(args[0]->IsInt32());
2037
141322
  const int fd = args[0].As<Int32>()->Value();
2038
2039
70661
  CHECK(Buffer::HasInstance(args[1]));
2040
70661
  Local<Object> buffer_obj = args[1].As<Object>();
2041
70661
  char* buffer_data = Buffer::Data(buffer_obj);
2042
70661
  size_t buffer_length = Buffer::Length(buffer_obj);
2043
2044
70661
  CHECK(IsSafeJsInt(args[2]));
2045
141322
  const int64_t off_64 = args[2].As<Integer>()->Value();
2046
70661
  CHECK_GE(off_64, 0);
2047
70661
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2048
70661
  const size_t off = static_cast<size_t>(off_64);
2049
2050
70661
  CHECK(args[3]->IsInt32());
2051
141322
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2052
70661
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2053
2054

70665
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2055
70661
  const int64_t pos = args[4]->IsNumber() ?
2056
141314
                      args[4].As<Integer>()->Value() :
2057
8
                      args[4].As<BigInt>()->Int64Value();
2058
2059
70661
  char* buf = buffer_data + off;
2060
70661
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2061
2062
70661
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2063
70661
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2064
14654
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2065
              uv_fs_read, fd, &uvbuf, 1, pos);
2066
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2067
56007
    CHECK_EQ(argc, 7);
2068
56007
    FSReqWrapSync req_wrap_sync;
2069

56015
    FS_SYNC_TRACE_BEGIN(read);
2070
56007
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2071
56007
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2072

56015
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2073
112014
    args.GetReturnValue().Set(bytesRead);
2074
  }
2075
70661
}
2076
2077
2078
// Wrapper for readv(2).
2079
//
2080
// bytesRead = fs.readv(fd, buffers[, position], callback)
2081
// 0 fd        integer. file descriptor
2082
// 1 buffers   array of buffers to read
2083
// 2 position  if integer, position to read at in the file.
2084
//             if null, read from the current position
2085
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2086
11
  Environment* env = Environment::GetCurrent(args);
2087
2088
11
  const int argc = args.Length();
2089
11
  CHECK_GE(argc, 3);
2090
2091
11
  CHECK(args[0]->IsInt32());
2092
22
  const int fd = args[0].As<Int32>()->Value();
2093
2094
11
  CHECK(args[1]->IsArray());
2095
22
  Local<Array> buffers = args[1].As<Array>();
2096
2097
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2098
2099
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2100
2101
  // Init uv buffers from ArrayBufferViews
2102
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2103
17
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2104
17
    CHECK(Buffer::HasInstance(buffer));
2105
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2106
  }
2107
2108
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2109
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2110
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2111
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2112
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2113
4
    CHECK_EQ(argc, 5);
2114
4
    FSReqWrapSync req_wrap_sync;
2115

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

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2119
8
    args.GetReturnValue().Set(bytesRead);
2120
  }
2121
11
}
2122
2123
2124
/* fs.chmod(path, mode);
2125
 * Wrapper for chmod(1) / EIO_CHMOD
2126
 */
2127
314
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2128
314
  Environment* env = Environment::GetCurrent(args);
2129
2130
314
  const int argc = args.Length();
2131
314
  CHECK_GE(argc, 2);
2132
2133
628
  BufferValue path(env->isolate(), args[0]);
2134
314
  CHECK_NOT_NULL(*path);
2135
2136
314
  CHECK(args[1]->IsInt32());
2137
628
  int mode = args[1].As<Int32>()->Value();
2138
2139
314
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2140
314
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2141
148
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2142
              uv_fs_chmod, *path, mode);
2143
  } else {  // chmod(path, mode, undefined, ctx)
2144
166
    CHECK_EQ(argc, 4);
2145
332
    FSReqWrapSync req_wrap_sync;
2146

168
    FS_SYNC_TRACE_BEGIN(chmod);
2147
332
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2148
             uv_fs_chmod, *path, mode);
2149

168
    FS_SYNC_TRACE_END(chmod);
2150
  }
2151
314
}
2152
2153
2154
/* fs.fchmod(fd, mode);
2155
 * Wrapper for fchmod(1) / EIO_FCHMOD
2156
 */
2157
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2158
12
  Environment* env = Environment::GetCurrent(args);
2159
2160
12
  const int argc = args.Length();
2161
12
  CHECK_GE(argc, 2);
2162
2163
12
  CHECK(args[0]->IsInt32());
2164
24
  const int fd = args[0].As<Int32>()->Value();
2165
2166
12
  CHECK(args[1]->IsInt32());
2167
24
  const int mode = args[1].As<Int32>()->Value();
2168
2169
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2170
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2171
7
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2172
              uv_fs_fchmod, fd, mode);
2173
  } else {  // fchmod(fd, mode, undefined, ctx)
2174
5
    CHECK_EQ(argc, 4);
2175
10
    FSReqWrapSync req_wrap_sync;
2176

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2177
5
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2178
             uv_fs_fchmod, fd, mode);
2179

7
    FS_SYNC_TRACE_END(fchmod);
2180
  }
2181
12
}
2182
2183
2184
/* fs.chown(path, uid, gid);
2185
 * Wrapper for chown(1) / EIO_CHOWN
2186
 */
2187
8
static void Chown(const FunctionCallbackInfo<Value>& args) {
2188
8
  Environment* env = Environment::GetCurrent(args);
2189
2190
8
  const int argc = args.Length();
2191
8
  CHECK_GE(argc, 3);
2192
2193
16
  BufferValue path(env->isolate(), args[0]);
2194
8
  CHECK_NOT_NULL(*path);
2195
2196
8
  CHECK(IsSafeJsInt(args[1]));
2197
16
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2198
2199
8
  CHECK(IsSafeJsInt(args[2]));
2200
16
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2201
2202
8
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2203
8
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2204
2
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2205
              uv_fs_chown, *path, uid, gid);
2206
  } else {  // chown(path, uid, gid, undefined, ctx)
2207
6
    CHECK_EQ(argc, 5);
2208
12
    FSReqWrapSync req_wrap_sync;
2209

8
    FS_SYNC_TRACE_BEGIN(chown);
2210
12
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2211
             uv_fs_chown, *path, uid, gid);
2212

8
    FS_SYNC_TRACE_END(chown);
2213
  }
2214
8
}
2215
2216
2217
/* fs.fchown(fd, uid, gid);
2218
 * Wrapper for fchown(1) / EIO_FCHOWN
2219
 */
2220
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2221
4
  Environment* env = Environment::GetCurrent(args);
2222
2223
4
  const int argc = args.Length();
2224
4
  CHECK_GE(argc, 3);
2225
2226
4
  CHECK(args[0]->IsInt32());
2227
8
  const int fd = args[0].As<Int32>()->Value();
2228
2229
4
  CHECK(IsSafeJsInt(args[1]));
2230
8
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2231
2232
4
  CHECK(IsSafeJsInt(args[2]));
2233
8
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2234
2235
4
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2236
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2237
2
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2238
              uv_fs_fchown, fd, uid, gid);
2239
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2240
2
    CHECK_EQ(argc, 5);
2241
4
    FSReqWrapSync req_wrap_sync;
2242

4
    FS_SYNC_TRACE_BEGIN(fchown);
2243
2
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2244
             uv_fs_fchown, fd, uid, gid);
2245

4
    FS_SYNC_TRACE_END(fchown);
2246
  }
2247
4
}
2248
2249
2250
5
static void LChown(const FunctionCallbackInfo<Value>& args) {
2251
5
  Environment* env = Environment::GetCurrent(args);
2252
2253
5
  const int argc = args.Length();
2254
5
  CHECK_GE(argc, 3);
2255
2256
10
  BufferValue path(env->isolate(), args[0]);
2257
5
  CHECK_NOT_NULL(*path);
2258
2259
5
  CHECK(IsSafeJsInt(args[1]));
2260
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2261
2262
5
  CHECK(IsSafeJsInt(args[2]));
2263
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2264
2265
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2266
5
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2267
3
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2268
              uv_fs_lchown, *path, uid, gid);
2269
  } else {  // lchown(path, uid, gid, undefined, ctx)
2270
2
    CHECK_EQ(argc, 5);
2271
4
    FSReqWrapSync req_wrap_sync;
2272

4
    FS_SYNC_TRACE_BEGIN(lchown);
2273
4
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2274
             uv_fs_lchown, *path, uid, gid);
2275

4
    FS_SYNC_TRACE_END(lchown);
2276
  }
2277
5
}
2278
2279
2280
53
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2281
53
  Environment* env = Environment::GetCurrent(args);
2282
2283
53
  const int argc = args.Length();
2284
53
  CHECK_GE(argc, 3);
2285
2286
106
  BufferValue path(env->isolate(), args[0]);
2287
53
  CHECK_NOT_NULL(*path);
2288
2289
53
  CHECK(args[1]->IsNumber());
2290
106
  const double atime = args[1].As<Number>()->Value();
2291
2292
53
  CHECK(args[2]->IsNumber());
2293
106
  const double mtime = args[2].As<Number>()->Value();
2294
2295
53
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2296
53
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2297
26
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2298
              uv_fs_utime, *path, atime, mtime);
2299
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2300
27
    CHECK_EQ(argc, 5);
2301
54
    FSReqWrapSync req_wrap_sync;
2302

29
    FS_SYNC_TRACE_BEGIN(utimes);
2303
54
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2304
             uv_fs_utime, *path, atime, mtime);
2305

29
    FS_SYNC_TRACE_END(utimes);
2306
  }
2307
53
}
2308
2309
18
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2310
18
  Environment* env = Environment::GetCurrent(args);
2311
2312
18
  const int argc = args.Length();
2313
18
  CHECK_GE(argc, 3);
2314
2315
18
  CHECK(args[0]->IsInt32());
2316
36
  const int fd = args[0].As<Int32>()->Value();
2317
2318
18
  CHECK(args[1]->IsNumber());
2319
36
  const double atime = args[1].As<Number>()->Value();
2320
2321
18
  CHECK(args[2]->IsNumber());
2322
36
  const double mtime = args[2].As<Number>()->Value();
2323
2324
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2325
18
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2326
9
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2327
              uv_fs_futime, fd, atime, mtime);
2328
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2329
9
    CHECK_EQ(argc, 5);
2330
18
    FSReqWrapSync req_wrap_sync;
2331

11
    FS_SYNC_TRACE_BEGIN(futimes);
2332
9
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2333
             uv_fs_futime, fd, atime, mtime);
2334

11
    FS_SYNC_TRACE_END(futimes);
2335
  }
2336
18
}
2337
2338
15
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2339
15
  Environment* env = Environment::GetCurrent(args);
2340
2341
15
  const int argc = args.Length();
2342
15
  CHECK_GE(argc, 3);
2343
2344
30
  BufferValue path(env->isolate(), args[0]);
2345
15
  CHECK_NOT_NULL(*path);
2346
2347
15
  CHECK(args[1]->IsNumber());
2348
30
  const double atime = args[1].As<Number>()->Value();
2349
2350
15
  CHECK(args[2]->IsNumber());
2351
30
  const double mtime = args[2].As<Number>()->Value();
2352
2353
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2354
15
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2355
8
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2356
              uv_fs_lutime, *path, atime, mtime);
2357
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2358
7
    CHECK_EQ(argc, 5);
2359
14
    FSReqWrapSync req_wrap_sync;
2360

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2361
14
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2362
             uv_fs_lutime, *path, atime, mtime);
2363

7
    FS_SYNC_TRACE_END(lutimes);
2364
  }
2365
15
}
2366
2367
15
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2368
15
  Environment* env = Environment::GetCurrent(args);
2369
15
  Isolate* isolate = env->isolate();
2370
2371
15
  const int argc = args.Length();
2372
15
  CHECK_GE(argc, 2);
2373
2374
15
  BufferValue tmpl(isolate, args[0]);
2375
15
  CHECK_NOT_NULL(*tmpl);
2376
2377
15
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2378
2379
15
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2380
15
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2381
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2382
              uv_fs_mkdtemp, *tmpl);
2383
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2384
9
    CHECK_EQ(argc, 4);
2385
9
    FSReqWrapSync req_wrap_sync;
2386

11
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2387
18
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2388
             uv_fs_mkdtemp, *tmpl);
2389

11
    FS_SYNC_TRACE_END(mkdtemp);
2390
9
    const char* path = req_wrap_sync.req.path;
2391
2392
    Local<Value> error;
2393
    MaybeLocal<Value> rc =
2394
9
        StringBytes::Encode(isolate, path, encoding, &error);
2395
9
    if (rc.IsEmpty()) {
2396
      Local<Object> ctx = args[3].As<Object>();
2397
      ctx->Set(env->context(), env->error_string(), error).Check();
2398
      return;
2399
    }
2400
18
    args.GetReturnValue().Set(rc.ToLocalChecked());
2401
  }
2402
}
2403
2404
22
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2405
22
  tracker->TrackField("stats_field_array", stats_field_array);
2406
22
  tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2407
22
  tracker->TrackField("file_handle_read_wrap_freelist",
2408
22
                      file_handle_read_wrap_freelist);
2409
22
}
2410
2411
5547
BindingData::BindingData(Environment* env, v8::Local<v8::Object> wrap)
2412
    : SnapshotableObject(env, wrap, type_int),
2413
      stats_field_array(env->isolate(), kFsStatsBufferLength),
2414
5547
      stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {
2415
5547
  wrap->Set(env->context(),
2416
            FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"),
2417
22188
            stats_field_array.GetJSArray())
2418
      .Check();
2419
2420
5547
  wrap->Set(env->context(),
2421
            FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"),
2422
16641
            stats_field_bigint_array.GetJSArray())
2423
      .Check();
2424
5547
}
2425
2426
4923
void BindingData::Deserialize(Local<Context> context,
2427
                              Local<Object> holder,
2428
                              int index,
2429
                              InternalFieldInfo* info) {
2430
  DCHECK_EQ(index, BaseObject::kSlot);
2431
9846
  HandleScope scope(context->GetIsolate());
2432
4923
  Environment* env = Environment::GetCurrent(context);
2433
4923
  BindingData* binding = env->AddBindingData<BindingData>(context, holder);
2434
4923
  CHECK_NOT_NULL(binding);
2435
4923
}
2436
2437
6
void BindingData::PrepareForSerialization(Local<Context> context,
2438
                                          v8::SnapshotCreator* creator) {
2439
6
  CHECK(file_handle_read_wrap_freelist.empty());
2440
  // We'll just re-initialize the buffers in the constructor since their
2441
  // contents can be thrown away once consumed in the previous call.
2442
6
  stats_field_array.Release();
2443
6
  stats_field_bigint_array.Release();
2444
6
}
2445
2446
6
InternalFieldInfo* BindingData::Serialize(int index) {
2447
  DCHECK_EQ(index, BaseObject::kSlot);
2448
6
  InternalFieldInfo* info = InternalFieldInfo::New(type());
2449
6
  return info;
2450
}
2451
2452
// TODO(addaleax): Remove once we're on C++17.
2453
constexpr FastStringKey BindingData::type_name;
2454
2455
624
void Initialize(Local<Object> target,
2456
                Local<Value> unused,
2457
                Local<Context> context,
2458
                void* priv) {
2459
624
  Environment* env = Environment::GetCurrent(context);
2460
624
  Isolate* isolate = env->isolate();
2461
  BindingData* const binding_data =
2462
624
      env->AddBindingData<BindingData>(context, target);
2463
624
  if (binding_data == nullptr) return;
2464
2465
624
  env->SetMethod(target, "access", Access);
2466
624
  env->SetMethod(target, "close", Close);
2467
624
  env->SetMethod(target, "open", Open);
2468
624
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2469
624
  env->SetMethod(target, "read", Read);
2470
624
  env->SetMethod(target, "readBuffers", ReadBuffers);
2471
624
  env->SetMethod(target, "fdatasync", Fdatasync);
2472
624
  env->SetMethod(target, "fsync", Fsync);
2473
624
  env->SetMethod(target, "rename", Rename);
2474
624
  env->SetMethod(target, "ftruncate", FTruncate);
2475
624
  env->SetMethod(target, "rmdir", RMDir);
2476
624
  env->SetMethod(target, "mkdir", MKDir);
2477
624
  env->SetMethod(target, "readdir", ReadDir);
2478
624
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2479
624
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2480
624
  env->SetMethod(target, "stat", Stat);
2481
624
  env->SetMethod(target, "lstat", LStat);
2482
624
  env->SetMethod(target, "fstat", FStat);
2483
624
  env->SetMethod(target, "link", Link);
2484
624
  env->SetMethod(target, "symlink", Symlink);
2485
624
  env->SetMethod(target, "readlink", ReadLink);
2486
624
  env->SetMethod(target, "unlink", Unlink);
2487
624
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2488
624
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2489
624
  env->SetMethod(target, "writeString", WriteString);
2490
624
  env->SetMethod(target, "realpath", RealPath);
2491
624
  env->SetMethod(target, "copyFile", CopyFile);
2492
2493
624
  env->SetMethod(target, "chmod", Chmod);
2494
624
  env->SetMethod(target, "fchmod", FChmod);
2495
2496
624
  env->SetMethod(target, "chown", Chown);
2497
624
  env->SetMethod(target, "fchown", FChown);
2498
624
  env->SetMethod(target, "lchown", LChown);
2499
2500
624
  env->SetMethod(target, "utimes", UTimes);
2501
624
  env->SetMethod(target, "futimes", FUTimes);
2502
624
  env->SetMethod(target, "lutimes", LUTimes);
2503
2504
624
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2505
2506
  target
2507
624
      ->Set(context,
2508
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2509
            Integer::New(
2510
                isolate,
2511
1872
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2512
      .Check();
2513
2514
624
  StatWatcher::Initialize(env, target);
2515
2516
  // Create FunctionTemplate for FSReqCallback
2517
624
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2518
1248
  fst->InstanceTemplate()->SetInternalFieldCount(
2519
      FSReqBase::kInternalFieldCount);
2520
624
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2521
624
  env->SetConstructorFunction(target, "FSReqCallback", fst);
2522
2523
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2524
  // to do anything in the constructor, so we only store the instance template.
2525
624
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2526
1248
  fh_rw->InstanceTemplate()->SetInternalFieldCount(
2527
      FSReqBase::kInternalFieldCount);
2528
624
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2529
  Local<String> fhWrapString =
2530
624
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2531
624
  fh_rw->SetClassName(fhWrapString);
2532
624
  env->set_filehandlereadwrap_template(
2533
      fst->InstanceTemplate());
2534
2535
  // Create Function Template for FSReqPromise
2536
624
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2537
624
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2538
  Local<String> promiseString =
2539
624
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2540
624
  fpt->SetClassName(promiseString);
2541
624
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2542
624
  fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2543
624
  env->set_fsreqpromise_constructor_template(fpo);
2544
2545
  // Create FunctionTemplate for FileHandle
2546
624
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2547
624
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2548
624
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2549
624
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2550
624
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2551
624
  fdt->SetInternalFieldCount(FileHandle::kInternalFieldCount);
2552
624
  StreamBase::AddMethods(env, fd);
2553
624
  env->SetConstructorFunction(target, "FileHandle", fd);
2554
624
  env->set_fd_constructor_template(fdt);
2555
2556
  // Create FunctionTemplate for FileHandle::CloseReq
2557
624
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2558
624
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2559
                        "FileHandleCloseReq"));
2560
624
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2561
624
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2562
624
  fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2563
624
  env->set_fdclose_constructor_template(fdcloset);
2564
2565
  Local<Symbol> use_promises_symbol =
2566
    Symbol::New(isolate,
2567
624
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2568
624
  env->set_fs_use_promises_symbol(use_promises_symbol);
2569
624
  target->Set(context,
2570
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2571
1872
              use_promises_symbol).Check();
2572
}
2573
2574
3552
BindingData* FSReqBase::binding_data() {
2575
3552
  return binding_data_.get();
2576
}
2577
2578
4929
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2579
4929
  registry->Register(Access);
2580
4929
  StatWatcher::RegisterExternalReferences(registry);
2581
2582
4929
  registry->Register(Close);
2583
4929
  registry->Register(Open);
2584
4929
  registry->Register(OpenFileHandle);
2585
4929
  registry->Register(Read);
2586
4929
  registry->Register(ReadBuffers);
2587
4929
  registry->Register(Fdatasync);
2588
4929
  registry->Register(Fsync);
2589
4929
  registry->Register(Rename);
2590
4929
  registry->Register(FTruncate);
2591
4929
  registry->Register(RMDir);
2592
4929
  registry->Register(MKDir);
2593
4929
  registry->Register(ReadDir);
2594
4929
  registry->Register(InternalModuleReadJSON);
2595
4929
  registry->Register(InternalModuleStat);
2596
4929
  registry->Register(Stat);
2597
4929
  registry->Register(LStat);
2598
4929
  registry->Register(FStat);
2599
4929
  registry->Register(Link);
2600
4929
  registry->Register(Symlink);
2601
4929
  registry->Register(ReadLink);
2602
4929
  registry->Register(Unlink);
2603
4929
  registry->Register(WriteBuffer);
2604
4929
  registry->Register(WriteBuffers);
2605
4929
  registry->Register(WriteString);
2606
4929
  registry->Register(RealPath);
2607
4929
  registry->Register(CopyFile);
2608
2609
4929
  registry->Register(Chmod);
2610
4929
  registry->Register(FChmod);
2611
2612
4929
  registry->Register(Chown);
2613
4929
  registry->Register(FChown);
2614
4929
  registry->Register(LChown);
2615
2616
4929
  registry->Register(UTimes);
2617
4929
  registry->Register(FUTimes);
2618
4929
  registry->Register(LUTimes);
2619
2620
4929
  registry->Register(Mkdtemp);
2621
4929
  registry->Register(NewFSReqCallback);
2622
2623
4929
  registry->Register(FileHandle::New);
2624
4929
  registry->Register(FileHandle::Close);
2625
4929
  registry->Register(FileHandle::ReleaseFD);
2626
4929
  StreamBase::RegisterExternalReferences(registry);
2627
4929
}
2628
2629
}  // namespace fs
2630
2631
}  // end namespace node
2632
2633
4990
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2634
4929
NODE_MODULE_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)