GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.cc Lines: 1452 1534 94.7 %
Date: 2022-06-20 04:16:14 Branches: 802 1254 64.0 %

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
12
std::string Basename(const std::string& str, const std::string& extension) {
88
  // Remove everything leading up to and including the final path separator.
89
12
  std::string::size_type pos = str.find_last_of(kPathSeparator);
90
91
  // Starting index for the resulting string
92
12
  std::size_t start_pos = 0;
93
  // String size to return
94
12
  std::size_t str_size = str.size();
95
12
  if (pos != std::string::npos) {
96
12
    start_pos = pos + 1;
97
12
    str_size -= start_pos;
98
  }
99
100
  // Strip away the extension, if any.
101

24
  if (str_size >= extension.size() &&
102
12
      str.compare(str.size() - extension.size(),
103
        extension.size(), extension) == 0) {
104
    str_size -= extension.size();
105
  }
106
107
12
  return str.substr(start_pos, str_size);
108
}
109
110
189981
inline int64_t GetOffset(Local<Value> value) {
111
191081
  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
1448
FileHandle::FileHandle(BindingData* binding_data,
149
1448
                       Local<Object> obj, int fd)
150
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
151
      StreamBase(env()),
152
      fd_(fd),
153
1448
      binding_data_(binding_data) {
154
1448
  MakeWeak();
155
1448
  StreamBase::AttachToObject(GetObject());
156
1448
}
157
158
1448
FileHandle* FileHandle::New(BindingData* binding_data,
159
                            int fd, Local<Object> obj) {
160
1448
  Environment* env = binding_data->env();
161
2881
  if (obj.IsEmpty() && !env->fd_constructor_template()
162
2881
                            ->NewInstance(env->context())
163
1433
                            .ToLocal(&obj)) {
164
    return nullptr;
165
  }
166
1448
  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
30
  if (args[1]->IsNumber())
179
30
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
180
15
  if (args[2]->IsNumber())
181
30
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
182
}
183
184
5624
FileHandle::~FileHandle() {
185
2812
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
186
2812
  Close();           // Close synchronously and emit warning
187
2812
  CHECK(closed_);    // We have to be closed at the point
188
5624
}
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
1406
inline void FileHandle::Close() {
241

1406
  if (closed_ || closing_) return;
242
  uv_fs_t req;
243
21
  CHECK_NE(fd_, -1);
244
21
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
245
21
  uv_fs_req_cleanup(&req);
246
247
  struct err_detail { int ret; int fd; };
248
249
21
  err_detail detail { ret, fd_ };
250
251
21
  AfterClose();
252
253
21
  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
21
  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
      USE(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"));
287
    }
288
4
  }, CallbackFlags::kUnrefed);
289
}
290
291
1401
void FileHandle::CloseReq::Resolve() {
292
1401
  Isolate* isolate = env()->isolate();
293
2770
  HandleScope scope(isolate);
294
1401
  Context::Scope context_scope(env()->context());
295
1401
  InternalCallbackScope callback_scope(this);
296
2802
  Local<Promise> promise = promise_.Get(isolate);
297
1401
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
298
4203
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
299
1369
}
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
1411
FileHandle* FileHandle::CloseReq::file_handle() {
312
1411
  Isolate* isolate = env()->isolate();
313
1411
  HandleScope scope(isolate);
314
2822
  Local<Value> val = ref_.Get(isolate);
315
1411
  Local<Object> obj = val.As<Object>();
316
1411
  return Unwrap<FileHandle>(obj);
317
}
318
319
1411
FileHandle::CloseReq::CloseReq(Environment* env,
320
                               Local<Object> obj,
321
                               Local<Promise> promise,
322
1411
                               Local<Value> ref)
323
1411
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
324
1411
  promise_.Reset(env->isolate(), promise);
325
1411
  ref_.Reset(env->isolate(), ref);
326
1411
}
327
328
11032
FileHandle::CloseReq::~CloseReq() {
329
2758
  uv_fs_req_cleanup(req());
330
2758
  promise_.Reset();
331
2758
  ref_.Reset();
332
5516
}
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
1411
MaybeLocal<Promise> FileHandle::ClosePromise() {
347
1411
  Isolate* isolate = env()->isolate();
348
1411
  EscapableHandleScope scope(isolate);
349
1411
  Local<Context> context = env()->context();
350
351
  Local<Value> close_resolver =
352
4233
      object()->GetInternalField(FileHandle::kClosingPromiseSlot);
353

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

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

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

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

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

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

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

3951
    FS_SYNC_TRACE_BEGIN(access);
881
7898
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
882

3951
    FS_SYNC_TRACE_END(access);
883
  }
884
3993
}
885
886
887
67033
void Close(const FunctionCallbackInfo<Value>& args) {
888
67033
  Environment* env = Environment::GetCurrent(args);
889
890
67033
  const int argc = args.Length();
891
67033
  CHECK_GE(argc, 2);
892
893
67033
  CHECK(args[0]->IsInt32());
894
134066
  int fd = args[0].As<Int32>()->Value();
895
67033
  env->RemoveUnmanagedFd(fd);
896
897
67033
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
898
67033
  if (req_wrap_async != nullptr) {  // close(fd, req)
899
5344
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
900
              uv_fs_close, fd);
901
  } else {  // close(fd, undefined, ctx)
902
61689
    CHECK_EQ(argc, 3);
903
123378
    FSReqWrapSync req_wrap_sync;
904

61746
    FS_SYNC_TRACE_BEGIN(close);
905
61689
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
906

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

5602
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
964
1
    start = 3;  // Skip UTF-8 BOM.
965
  }
966
967
5602
  const size_t size = offset - start;
968
5602
  char* p = &chars[start];
969
5602
  char* pe = &chars[size];
970
  char* pos[2];
971
5602
  char** ppos = &pos[0];
972
973
92460
  while (p < pe) {
974
92448
    char c = *p++;
975

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

15293
    FS_SYNC_TRACE_BEGIN(stat);
1046
30582
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1047

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

116235
    FS_SYNC_TRACE_BEGIN(lstat);
1077
232436
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1078
                       *path);
1079

116235
    FS_SYNC_TRACE_END(lstat);
1080
116218
    if (err != 0) {
1081
440
      return;  // error info is in ctx
1082
    }
1083
1084
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1085
115778
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1086
231556
    args.GetReturnValue().Set(arr);
1087
  }
1088
}
1089
1090
57011
static void FStat(const FunctionCallbackInfo<Value>& args) {
1091
57011
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1092
57011
  Environment* env = binding_data->env();
1093
1094
57011
  const int argc = args.Length();
1095
57011
  CHECK_GE(argc, 2);
1096
1097
57011
  CHECK(args[0]->IsInt32());
1098
114022
  int fd = args[0].As<Int32>()->Value();
1099
1100
57011
  bool use_bigint = args[1]->IsTrue();
1101
57011
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1102
57011
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1103
1196
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1104
              uv_fs_fstat, fd);
1105
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1106
55815
    CHECK_EQ(argc, 4);
1107
55815
    FSReqWrapSync req_wrap_sync;
1108

55824
    FS_SYNC_TRACE_BEGIN(fstat);
1109
55815
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1110

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

336
    FS_SYNC_TRACE_BEGIN(symlink);
1144
664
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1145
             uv_fs_symlink, *target, *path, flags);
1146

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

11
    FS_SYNC_TRACE_BEGIN(link);
1171
10
    SyncCall(env, args[3], &req_wrap_sync, "link",
1172
             uv_fs_link, *src, *dest);
1173

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

69
    FS_SYNC_TRACE_BEGIN(readlink);
1197
134
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1198
                       uv_fs_readlink, *path);
1199

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

5
    FS_SYNC_TRACE_BEGIN(rename);
1241
6
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1242
             *old_path, *new_path);
1243

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

17
    FS_SYNC_TRACE_BEGIN(ftruncate);
1267
15
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1268
             len);
1269

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

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

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

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

19
    FS_SYNC_TRACE_END(fsync);
1314
  }
1315
21
}
1316
1317
2588
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1318
2588
  Environment* env = Environment::GetCurrent(args);
1319
1320
2588
  const int argc = args.Length();
1321
2588
  CHECK_GE(argc, 2);
1322
1323
5176
  BufferValue path(env->isolate(), args[0]);
1324
2588
  CHECK_NOT_NULL(*path);
1325
1326
2588
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1327
2588
  if (req_wrap_async != nullptr) {
1328
1029
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1329
              uv_fs_unlink, *path);
1330
  } else {
1331
1559
    CHECK_EQ(argc, 3);
1332
3118
    FSReqWrapSync req_wrap_sync;
1333

1614
    FS_SYNC_TRACE_BEGIN(unlink);
1334
3118
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1335

1614
    FS_SYNC_TRACE_END(unlink);
1336
  }
1337
2588
}
1338
1339
1881
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1340
1881
  Environment* env = Environment::GetCurrent(args);
1341
1342
1881
  const int argc = args.Length();
1343
1881
  CHECK_GE(argc, 2);
1344
1345
3762
  BufferValue path(env->isolate(), args[0]);
1346
1881
  CHECK_NOT_NULL(*path);
1347
1348
1881
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1349
1881
  if (req_wrap_async != nullptr) {
1350
259
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1351
              uv_fs_rmdir, *path);
1352
  } else {  // rmdir(path, undefined, ctx)
1353
1622
    CHECK_EQ(argc, 3);
1354
3244
    FSReqWrapSync req_wrap_sync;
1355

1628
    FS_SYNC_TRACE_BEGIN(rmdir);
1356
3244
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1357
             uv_fs_rmdir, *path);
1358

1628
    FS_SYNC_TRACE_END(rmdir);
1359
  }
1360
1881
}
1361
1362
6731
int MKDirpSync(uv_loop_t* loop,
1363
               uv_fs_t* req,
1364
               const std::string& path,
1365
               int mode,
1366
               uv_fs_cb cb) {
1367
6731
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1368
1369
  // on the first iteration of algorithm, stash state information.
1370
6731
  if (req_wrap->continuation_data() == nullptr) {
1371
6731
    req_wrap->set_continuation_data(
1372
13462
        std::make_unique<FSContinuationData>(req, mode, cb));
1373
6731
    req_wrap->continuation_data()->PushPath(std::move(path));
1374
  }
1375
1376
13309
  while (req_wrap->continuation_data()->paths().size() > 0) {
1377
6881
    std::string next_path = req_wrap->continuation_data()->PopPath();
1378
6881
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1379
    while (true) {
1380

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

6431
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1412
1
            uv_fs_req_cleanup(req);
1413

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

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

490
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1499
245
                  req_wrap->continuation_data()->paths().size() > 0) {
1500

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

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

583
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1562
              mkdirp ? AfterMkdirp : AfterNoArgs,
1563
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1564
  } else {  // mkdir(path, mode, undefined, ctx)
1565
1208
    CHECK_EQ(argc, 5);
1566
1208
    FSReqWrapSync req_wrap_sync;
1567

1212
    FS_SYNC_TRACE_BEGIN(mkdir);
1568
1208
    if (mkdirp) {
1569
283
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1570

562
      if (err == 0 &&
1571
279
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1572
        Local<Value> error;
1573
277
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1574
277
        FromNamespacedPath(&first_path);
1575
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1576
                                                     first_path.c_str(),
1577
277
                                                     UTF8, &error);
1578
277
        if (path.IsEmpty()) {
1579
          Local<Object> ctx = args[4].As<Object>();
1580
          ctx->Set(env->context(), env->error_string(), error).Check();
1581
          return;
1582
        }
1583
554
        args.GetReturnValue().Set(path.ToLocalChecked());
1584
      }
1585
    } else {
1586
1850
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1587
               uv_fs_mkdir, *path, mode);
1588
    }
1589

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

22
    FS_SYNC_TRACE_BEGIN(realpath);
1613
40
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1614
                       uv_fs_realpath, *path);
1615

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

13773
    FS_SYNC_TRACE_BEGIN(readdir);
1664
27542
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1665
                       uv_fs_scandir, *path, 0 /*flags*/);
1666

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

62223
    FS_SYNC_TRACE_BEGIN(open);
1748
124320
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1749
                          uv_fs_open, *path, flags, mode);
1750

62223
    FS_SYNC_TRACE_END(open);
1751
62160
    if (result >= 0) env->AddUnmanagedFd(result);
1752
124320
    args.GetReturnValue().Set(result);
1753
  }
1754
67753
}
1755
1756
2652
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1757
2652
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1758
2652
  Environment* env = binding_data->env();
1759
2652
  Isolate* isolate = env->isolate();
1760
1761
2652
  const int argc = args.Length();
1762
2652
  CHECK_GE(argc, 3);
1763
1764
2652
  BufferValue path(isolate, args[0]);
1765
2652
  CHECK_NOT_NULL(*path);
1766
1767
2652
  CHECK(args[1]->IsInt32());
1768
5304
  const int flags = args[1].As<Int32>()->Value();
1769
1770
2652
  CHECK(args[2]->IsInt32());
1771
5304
  const int mode = args[2].As<Int32>()->Value();
1772
1773
2652
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1774
2652
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1775
2651
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1776
              uv_fs_open, *path, flags, mode);
1777
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1778
1
    CHECK_EQ(argc, 5);
1779
1
    FSReqWrapSync req_wrap_sync;
1780

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

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

118
    FS_SYNC_TRACE_BEGIN(copyfile);
1818
232
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1819
             uv_fs_copyfile, *src, *dest, flags);
1820

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

44509
    FS_SYNC_TRACE_BEGIN(write);
1873
44459
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1874
44459
                                uv_fs_write, fd, &uvbuf, 1, pos);
1875

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

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

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

383536
  if (!is_async && value->IsString()) {
1963
127819
    auto string = value.As<String>();
1964


127820
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1965
1
      auto ext = string->GetExternalOneByteStringResource();
1966
1
      buf = const_cast<char*>(ext->data());
1967
1
      len = ext->length();
1968


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

127819
    FS_SYNC_TRACE_BEGIN(write);
2017
127819
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2018
127819
                                uv_fs_write, fd, &uvbuf, 1, pos);
2019

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

224194
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2061
224164
  const int64_t pos = args[4]->IsNumber() ?
2062
448268
                      args[4].As<Integer>()->Value() :
2063
60
                      args[4].As<BigInt>()->Int64Value();
2064
2065
224164
  char* buf = buffer_data + off;
2066
224164
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2067
2068
224164
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2069
224164
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2070
14812
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2071
              uv_fs_read, fd, &uvbuf, 1, pos);
2072
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2073
209352
    CHECK_EQ(argc, 7);
2074
209352
    FSReqWrapSync req_wrap_sync;
2075

209391
    FS_SYNC_TRACE_BEGIN(read);
2076
209352
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2077
209352
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2078

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

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

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

171
    FS_SYNC_TRACE_BEGIN(chmod);
2153
338
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2154
             uv_fs_chmod, *path, mode);
2155

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

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2183
5
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2184
             uv_fs_fchmod, fd, mode);
2185

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

4
    FS_SYNC_TRACE_BEGIN(chown);
2216
4
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2217
             uv_fs_chown, *path, uid, gid);
2218

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

4
    FS_SYNC_TRACE_BEGIN(fchown);
2249
2
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2250
             uv_fs_fchown, fd, uid, gid);
2251

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

4
    FS_SYNC_TRACE_BEGIN(lchown);
2279
4
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2280
             uv_fs_lchown, *path, uid, gid);
2281

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

29
    FS_SYNC_TRACE_BEGIN(utimes);
2309
54
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2310
             uv_fs_utime, *path, atime, mtime);
2311

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

11
    FS_SYNC_TRACE_BEGIN(futimes);
2338
9
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2339
             uv_fs_futime, fd, atime, mtime);
2340

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

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2367
14
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2368
             uv_fs_lutime, *path, atime, mtime);
2369

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

11
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2393
18
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2394
             uv_fs_mkdtemp, *tmpl);
2395

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