GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_file.cc Lines: 1403 1496 93.8 %
Date: 2020-09-06 22:14:11 Branches: 797 1222 65.2 %

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

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

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

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

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

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

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

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

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

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

155
    FS_SYNC_TRACE_BEGIN(access);
854
306
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
855

155
    FS_SYNC_TRACE_END(access);
856
  }
857
204
}
858
859
860
44749
void Close(const FunctionCallbackInfo<Value>& args) {
861
44749
  Environment* env = Environment::GetCurrent(args);
862
863
44749
  const int argc = args.Length();
864
44749
  CHECK_GE(argc, 2);
865
866
89498
  CHECK(args[0]->IsInt32());
867
134247
  int fd = args[0].As<Int32>()->Value();
868
44749
  env->RemoveUnmanagedFd(fd);
869
870
44749
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
871
44749
  if (req_wrap_async != nullptr) {  // close(fd, req)
872
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
873
5553
              uv_fs_close, fd);
874
  } else {  // close(fd, undefined, ctx)
875
39196
    CHECK_EQ(argc, 3);
876
78392
    FSReqWrapSync req_wrap_sync;
877

39256
    FS_SYNC_TRACE_BEGIN(close);
878
39196
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
879

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

5722
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
937
1
    start = 3;  // Skip UTF-8 BOM.
938
  }
939
940
5722
  const size_t size = offset - start;
941
5722
  char* p = &chars[start];
942
5722
  char* pe = &chars[size];
943
  char* pos[2];
944
5722
  char** ppos = &pos[0];
945
946
2812088
  while (p < pe) {
947
1408895
    char c = *p++;
948

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

14146
    FS_SYNC_TRACE_BEGIN(stat);
1019
28288
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1020

14146
    FS_SYNC_TRACE_END(stat);
1021
14144
    if (err != 0) {
1022
207
      return;  // error info is in ctx
1023
    }
1024
1025
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1026
13937
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1027
27874
    args.GetReturnValue().Set(arr);
1028
  }
1029
}
1030
1031
99063
static void LStat(const FunctionCallbackInfo<Value>& args) {
1032
99063
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1033
99063
  Environment* env = binding_data->env();
1034
1035
99063
  const int argc = args.Length();
1036
99063
  CHECK_GE(argc, 3);
1037
1038
197839
  BufferValue path(env->isolate(), args[0]);
1039
99063
  CHECK_NOT_NULL(*path);
1040
1041
198126
  bool use_bigint = args[1]->IsTrue();
1042
99063
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1043
99063
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1044
4808
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1045
4808
              uv_fs_lstat, *path);
1046
  } else {  // lstat(path, use_bigint, undefined, ctx)
1047
94255
    CHECK_EQ(argc, 4);
1048
188223
    FSReqWrapSync req_wrap_sync;
1049

94289
    FS_SYNC_TRACE_BEGIN(lstat);
1050
94255
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1051
94255
                       *path);
1052

94289
    FS_SYNC_TRACE_END(lstat);
1053
94255
    if (err != 0) {
1054
287
      return;  // error info is in ctx
1055
    }
1056
1057
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1058
93968
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1059
187936
    args.GetReturnValue().Set(arr);
1060
  }
1061
}
1062
1063
36182
static void FStat(const FunctionCallbackInfo<Value>& args) {
1064
36182
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1065
36182
  Environment* env = binding_data->env();
1066
1067
36182
  const int argc = args.Length();
1068
36182
  CHECK_GE(argc, 2);
1069
1070
72364
  CHECK(args[0]->IsInt32());
1071
108546
  int fd = args[0].As<Int32>()->Value();
1072
1073
72364
  bool use_bigint = args[1]->IsTrue();
1074
36182
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1075
36182
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1076
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1077
1233
              uv_fs_fstat, fd);
1078
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1079
34949
    CHECK_EQ(argc, 4);
1080
69879
    FSReqWrapSync req_wrap_sync;
1081

34959
    FS_SYNC_TRACE_BEGIN(fstat);
1082
34949
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1083

34959
    FS_SYNC_TRACE_END(fstat);
1084
34949
    if (err != 0) {
1085
19
      return;  // error info is in ctx
1086
    }
1087
1088
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1089
34930
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1090
69860
    args.GetReturnValue().Set(arr);
1091
  }
1092
}
1093
1094
210
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1095
210
  Environment* env = Environment::GetCurrent(args);
1096
210
  Isolate* isolate = env->isolate();
1097
1098
210
  const int argc = args.Length();
1099
210
  CHECK_GE(argc, 4);
1100
1101
420
  BufferValue target(isolate, args[0]);
1102
210
  CHECK_NOT_NULL(*target);
1103
420
  BufferValue path(isolate, args[1]);
1104
210
  CHECK_NOT_NULL(*path);
1105
1106
420
  CHECK(args[2]->IsInt32());
1107
630
  int flags = args[2].As<Int32>()->Value();
1108
1109
210
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1110
210
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1111
26
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1112
26
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1113
  } else {  // symlink(target, path, flags, undefinec, ctx)
1114
184
    CHECK_EQ(argc, 5);
1115
368
    FSReqWrapSync req_wrap_sync;
1116

188
    FS_SYNC_TRACE_BEGIN(symlink);
1117
184
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1118
184
             uv_fs_symlink, *target, *path, flags);
1119

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

11
    FS_SYNC_TRACE_BEGIN(link);
1144
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1145
5
             uv_fs_link, *src, *dest);
1146

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

50
    FS_SYNC_TRACE_BEGIN(readlink);
1170
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1171
48
                       uv_fs_readlink, *path);
1172

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

7
    FS_SYNC_TRACE_BEGIN(rename);
1214
5
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1215
5
             *old_path, *new_path);
1216

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

15
    FS_SYNC_TRACE_BEGIN(ftruncate);
1240
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1241
13
             len);
1242

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

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

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

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

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

840
    FS_SYNC_TRACE_BEGIN(unlink);
1307
1560
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1308

840
    FS_SYNC_TRACE_END(unlink);
1309
  }
1310
1330
}
1311
1312
1138
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1313
1138
  Environment* env = Environment::GetCurrent(args);
1314
1315
1138
  const int argc = args.Length();
1316
1138
  CHECK_GE(argc, 2);
1317
1318
2276
  BufferValue path(env->isolate(), args[0]);
1319
1138
  CHECK_NOT_NULL(*path);
1320
1321
1138
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1322
1138
  if (req_wrap_async != nullptr) {
1323
121
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1324
121
              uv_fs_rmdir, *path);
1325
  } else {  // rmdir(path, undefined, ctx)
1326
1017
    CHECK_EQ(argc, 3);
1327
2034
    FSReqWrapSync req_wrap_sync;
1328

1023
    FS_SYNC_TRACE_BEGIN(rmdir);
1329
1017
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1330
1017
             uv_fs_rmdir, *path);
1331

1023
    FS_SYNC_TRACE_END(rmdir);
1332
  }
1333
1138
}
1334
1335
4935
int MKDirpSync(uv_loop_t* loop,
1336
               uv_fs_t* req,
1337
               const std::string& path,
1338
               int mode,
1339
               uv_fs_cb cb) {
1340
4935
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1341
1342
  // on the first iteration of algorithm, stash state information.
1343
4935
  if (req_wrap->continuation_data() == nullptr) {
1344
    req_wrap->set_continuation_data(
1345
4935
        std::make_unique<FSContinuationData>(req, mode, cb));
1346
4935
    req_wrap->continuation_data()->PushPath(std::move(path));
1347
  }
1348
1349
14737
  while (req_wrap->continuation_data()->paths().size() > 0) {
1350
9932
    std::string next_path = req_wrap->continuation_data()->PopPath();
1351
5031
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1352
    while (true) {
1353

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

4808
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1384
1
            uv_fs_req_cleanup(req);
1385

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

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

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

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

862
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1534
              mkdirp ? AfterMkdirp : AfterNoArgs,
1535
862
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1536
  } else {  // mkdir(path, mode, undefined, ctx)
1537
799
    CHECK_EQ(argc, 5);
1538
1598
    FSReqWrapSync req_wrap_sync;
1539

803
    FS_SYNC_TRACE_BEGIN(mkdir);
1540
799
    if (mkdirp) {
1541
110
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1542

216
      if (err == 0 &&
1543
106
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1544
        Local<Value> error;
1545
208
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1546
104
        FromNamespacedPath(&first_path);
1547
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1548
                                                     first_path.c_str(),
1549
104
                                                     UTF8, &error);
1550
104
        if (path.IsEmpty()) {
1551
          Local<Object> ctx = args[4].As<Object>();
1552
          ctx->Set(env->context(), env->error_string(), error).Check();
1553
          return;
1554
        }
1555
208
        args.GetReturnValue().Set(path.ToLocalChecked());
1556
      }
1557
    } else {
1558
689
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1559
689
               uv_fs_mkdir, *path, mode);
1560
    }
1561


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

22
    FS_SYNC_TRACE_BEGIN(realpath);
1585
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1586
20
                       uv_fs_realpath, *path);
1587

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

13800
    FS_SYNC_TRACE_BEGIN(readdir);
1636
13798
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1637
13798
                       uv_fs_scandir, *path, 0 /*flags*/);
1638

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

39626
    FS_SYNC_TRACE_BEGIN(open);
1720
39554
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1721
39554
                          uv_fs_open, *path, flags, mode);
1722

39626
    FS_SYNC_TRACE_END(open);
1723
39554
    if (result >= 0) env->AddUnmanagedFd(result);
1724
79108
    args.GetReturnValue().Set(result);
1725
  }
1726
45346
}
1727
1728
322
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1729
322
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1730
322
  Environment* env = binding_data->env();
1731
322
  Isolate* isolate = env->isolate();
1732
1733
322
  const int argc = args.Length();
1734
322
  CHECK_GE(argc, 3);
1735
1736
644
  BufferValue path(isolate, args[0]);
1737
322
  CHECK_NOT_NULL(*path);
1738
1739
644
  CHECK(args[1]->IsInt32());
1740
966
  const int flags = args[1].As<Int32>()->Value();
1741
1742
644
  CHECK(args[2]->IsInt32());
1743
966
  const int mode = args[2].As<Int32>()->Value();
1744
1745
322
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1746
322
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1747
321
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1748
321
              uv_fs_open, *path, flags, mode);
1749
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1750
1
    CHECK_EQ(argc, 5);
1751
2
    FSReqWrapSync req_wrap_sync;
1752

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

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

21
    FS_SYNC_TRACE_BEGIN(copyfile);
1790
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1791
19
             uv_fs_copyfile, *src, *dest, flags);
1792

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

39894
    FS_SYNC_TRACE_BEGIN(write);
1845
39844
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1846
39844
                                uv_fs_write, fd, &uvbuf, 1, pos);
1847

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

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

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

4393
  if (!is_async && value->IsString()) {
1935
1421
    auto string = value.As<String>();
1936


1422
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1937
1
      auto ext = string->GetExternalOneByteStringResource();
1938
1
      buf = const_cast<char*>(ext->data());
1939
1
      len = ext->length();
1940


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

1421
    FS_SYNC_TRACE_BEGIN(write);
1989
1421
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1990
1421
                                uv_fs_write, fd, &uvbuf, 1, pos);
1991

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

38199
    FS_SYNC_TRACE_BEGIN(read);
2046
38189
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2047
38189
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2048

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

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

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

18
    FS_SYNC_TRACE_BEGIN(chmod);
2123
16
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2124
16
             uv_fs_chmod, *path, mode);
2125

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

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2153
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2154
5
             uv_fs_fchmod, fd, mode);
2155

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

5
    FS_SYNC_TRACE_BEGIN(chown);
2186
3
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2187
3
             uv_fs_chown, *path, uid, gid);
2188

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

4
    FS_SYNC_TRACE_BEGIN(fchown);
2219
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2220
2
             uv_fs_fchown, fd, uid, gid);
2221

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

4
    FS_SYNC_TRACE_BEGIN(lchown);
2249
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2250
2
             uv_fs_lchown, *path, uid, gid);
2251

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

19
    FS_SYNC_TRACE_BEGIN(utimes);
2279
17
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2280
17
             uv_fs_utime, *path, atime, mtime);
2281

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

11
    FS_SYNC_TRACE_BEGIN(futimes);
2308
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2309
9
             uv_fs_futime, fd, atime, mtime);
2310

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

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2337
7
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2338
7
             uv_fs_lutime, *path, atime, mtime);
2339

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

10
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2363
8
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2364
8
             uv_fs_mkdtemp, *tmpl);
2365

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

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