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: 1300 1392 93.4 %
Date: 2020-02-19 22:14:06 Branches: 754 1138 66.3 %

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
#include "string_search.h"
36
37
#include <fcntl.h>
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
#include <cstring>
41
#include <cerrno>
42
#include <climits>
43
44
#if defined(__MINGW32__) || defined(_MSC_VER)
45
# include <io.h>
46
#endif
47
48
#include <memory>
49
50
namespace node {
51
52
namespace fs {
53
54
using v8::Array;
55
using v8::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
42324
inline int64_t GetOffset(Local<Value> value) {
87
43394
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
88
}
89
90
#define TRACE_NAME(name) "fs.sync." #name
91
#define GET_TRACE_ENABLED                                                  \
92
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
93
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
94
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
95
  if (GET_TRACE_ENABLED)                                                   \
96
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
97
  ##__VA_ARGS__);
98
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
99
  if (GET_TRACE_ENABLED)                                                   \
100
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
101
  ##__VA_ARGS__);
102
103
// We sometimes need to convert a C++ lambda function to a raw C-style function.
104
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
105
// functions, and thus does not wrap them properly.
106
typedef void(*uv_fs_callback_t)(uv_fs_t*);
107
108
109
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
110
  tracker->TrackField("paths", paths_);
111
}
112
113
28
FileHandleReadWrap::~FileHandleReadWrap() {}
114
115
49679
FSReqBase::~FSReqBase() {}
116
117
2
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
118
2
  tracker->TrackField("continuation_data", continuation_data_);
119
2
}
120
121
// The FileHandle object wraps a file descriptor and will close it on garbage
122
// collection if necessary. If that happens, a process warning will be
123
// emitted (or a fatal exception will occur if the fd cannot be closed.)
124
284
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
125
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
126
      StreamBase(env),
127
284
      fd_(fd) {
128
284
  MakeWeak();
129
284
  StreamBase::AttachToObject(GetObject());
130
284
}
131
132
284
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
133

1108
  if (obj.IsEmpty() && !env->fd_constructor_template()
134
824
                            ->NewInstance(env->context())
135
270
                            .ToLocal(&obj)) {
136
    return nullptr;
137
  }
138
284
  return new FileHandle(env, obj, fd);
139
}
140
141
14
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
142
14
  Environment* env = Environment::GetCurrent(args);
143
14
  CHECK(args.IsConstructCall());
144
28
  CHECK(args[0]->IsInt32());
145
146
  FileHandle* handle =
147
42
      FileHandle::New(env, args[0].As<Int32>()->Value(), args.This());
148
14
  if (handle == nullptr) return;
149
28
  if (args[1]->IsNumber())
150
56
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
151
28
  if (args[2]->IsNumber())
152
56
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
153
}
154
155
852
FileHandle::~FileHandle() {
156
284
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
157
284
  Close();           // Close synchronously and emit warning
158
284
  CHECK(closed_);    // We have to be closed at the point
159
568
}
160
161
int FileHandle::DoWrite(WriteWrap* w,
162
                        uv_buf_t* bufs,
163
                        size_t count,
164
                        uv_stream_t* send_handle) {
165
  return UV_ENOSYS;  // Not implemented (yet).
166
}
167
168
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
169
  tracker->TrackField("current_read", current_read_);
170
}
171
172
// Close the file descriptor if it hasn't already been closed. A process
173
// warning will be emitted using a SetImmediate to avoid calling back to
174
// JS during GC. If closing the fd fails at this point, a fatal exception
175
// will crash the process immediately.
176
284
inline void FileHandle::Close() {
177
560
  if (closed_) return;
178
  uv_fs_t req;
179
8
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
180
8
  uv_fs_req_cleanup(&req);
181
182
  struct err_detail { int ret; int fd; };
183
184
8
  err_detail detail { ret, fd_ };
185
186
8
  AfterClose();
187
188
8
  if (ret < 0) {
189
    // Do not unref this
190
    env()->SetImmediate([detail](Environment* env) {
191
      char msg[70];
192
      snprintf(msg, arraysize(msg),
193
              "Closing file descriptor %d on garbage collection failed",
194
              detail.fd);
195
      // This exception will end up being fatal for the process because
196
      // it is being thrown from within the SetImmediate handler and
197
      // there is no JS stack to bubble it to. In other words, tearing
198
      // down the process is the only reasonable thing we can do here.
199
      HandleScope handle_scope(env->isolate());
200
      env->ThrowUVException(detail.ret, "close", msg);
201
    });
202
    return;
203
  }
204
205
  // If the close was successful, we still want to emit a process warning
206
  // to notify that the file descriptor was gc'd. We want to be noisy about
207
  // this because not explicitly closing the FileHandle is a bug.
208
209
18
  env()->SetUnrefImmediate([detail](Environment* env) {
210
    ProcessEmitWarning(env,
211
                       "Closing file descriptor %d on garbage collection",
212
2
                       detail.fd);
213
2
    if (env->filehandle_close_warning()) {
214
2
      env->set_filehandle_close_warning(false);
215
4
      ProcessEmitDeprecationWarning(
216
          env,
217
          "Closing a FileHandle object on garbage collection is deprecated. "
218
          "Please close FileHandle objects explicitly using "
219
          "FileHandle.prototype.close(). In the future, an error will be "
220
          "thrown if a file descriptor is closed during garbage collection.",
221
          "DEP0137").IsNothing();
222
    }
223
10
  });
224
}
225
226
268
void FileHandle::CloseReq::Resolve() {
227
268
  Isolate* isolate = env()->isolate();
228
536
  HandleScope scope(isolate);
229
536
  InternalCallbackScope callback_scope(this);
230
536
  Local<Promise> promise = promise_.Get(isolate);
231
268
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
232
804
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
233
268
}
234
235
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
236
1
  Isolate* isolate = env()->isolate();
237
2
  HandleScope scope(isolate);
238
2
  InternalCallbackScope callback_scope(this);
239
2
  Local<Promise> promise = promise_.Get(isolate);
240
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
241
3
  resolver->Reject(env()->context(), reason).Check();
242
1
}
243
244
269
FileHandle* FileHandle::CloseReq::file_handle() {
245
269
  Isolate* isolate = env()->isolate();
246
538
  HandleScope scope(isolate);
247
538
  Local<Value> val = ref_.Get(isolate);
248
269
  Local<Object> obj = val.As<Object>();
249
538
  return Unwrap<FileHandle>(obj);
250
}
251
252
269
FileHandle::CloseReq::CloseReq(Environment* env,
253
                               Local<Object> obj,
254
                               Local<Promise> promise,
255
269
                               Local<Value> ref)
256
538
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
257
269
  promise_.Reset(env->isolate(), promise);
258
269
  ref_.Reset(env->isolate(), ref);
259
269
}
260
261
1345
FileHandle::CloseReq::~CloseReq() {
262
269
  uv_fs_req_cleanup(req());
263
269
  promise_.Reset();
264
269
  ref_.Reset();
265
538
}
266
267
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
268
  tracker->TrackField("promise", promise_);
269
  tracker->TrackField("ref", ref_);
270
}
271
272
273
274
// Closes this FileHandle asynchronously and returns a Promise that will be
275
// resolved when the callback is invoked, or rejects with a UVException if
276
// there was a problem closing the fd. This is the preferred mechanism for
277
// closing the FD object even tho the object will attempt to close
278
// automatically on gc.
279
269
MaybeLocal<Promise> FileHandle::ClosePromise() {
280
269
  Isolate* isolate = env()->isolate();
281
269
  EscapableHandleScope scope(isolate);
282
269
  Local<Context> context = env()->context();
283
269
  auto maybe_resolver = Promise::Resolver::New(context);
284
269
  CHECK(!maybe_resolver.IsEmpty());
285
269
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
286
269
  Local<Promise> promise = resolver.As<Promise>();
287
269
  CHECK(!reading_);
288

269
  if (!closed_ && !closing_) {
289
269
    closing_ = true;
290
    Local<Object> close_req_obj;
291
538
    if (!env()
292
538
             ->fdclose_constructor_template()
293
807
             ->NewInstance(env()->context())
294
269
             .ToLocal(&close_req_obj)) {
295
      return MaybeLocal<Promise>();
296
    }
297
538
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
298
807
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
299
538
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
300
269
      CHECK_NOT_NULL(close);
301
269
      close->file_handle()->AfterClose();
302
269
      Isolate* isolate = close->env()->isolate();
303
269
      if (req->result < 0) {
304
2
        HandleScope handle_scope(isolate);
305
1
        close->Reject(UVException(isolate, req->result, "close"));
306
      } else {
307
268
        close->Resolve();
308
      }
309
1076
    }};
310
269
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
311
269
    if (ret < 0) {
312
      req->Reject(UVException(isolate, ret, "close"));
313
      delete req;
314
269
    }
315
  } else {
316
    // Already closed. Just reject the promise immediately
317
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
318
        .Check();
319
  }
320
269
  return scope.Escape(promise);
321
}
322
323
269
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
324
  FileHandle* fd;
325
269
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
326
  Local<Promise> ret;
327
538
  if (!fd->ClosePromise().ToLocal(&ret)) return;
328
538
  args.GetReturnValue().Set(ret);
329
}
330
331
332
7
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
333
  FileHandle* fd;
334
7
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
335
  // Just act as if this FileHandle has been closed.
336
7
  fd->AfterClose();
337
}
338
339
340
284
void FileHandle::AfterClose() {
341
284
  closing_ = false;
342
284
  closed_ = true;
343
284
  fd_ = -1;
344

284
  if (reading_ && !persistent().IsEmpty())
345
    EmitRead(UV_EOF);
346
284
}
347
348
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
349
  tracker->TrackField("buffer", buffer_);
350
  tracker->TrackField("file_handle", this->file_handle_);
351
}
352
353
14
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
354
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
355
14
    file_handle_(handle) {}
356
357
217
int FileHandle::ReadStart() {
358

217
  if (!IsAlive() || IsClosing())
359
    return UV_EOF;
360
361
217
  reading_ = true;
362
363
217
  if (current_read_)
364
    return 0;
365
366
434
  std::unique_ptr<FileHandleReadWrap> read_wrap;
367
368
217
  if (read_length_ == 0) {
369
5
    EmitRead(UV_EOF);
370
5
    return 0;
371
  }
372
373
  {
374
    // Create a new FileHandleReadWrap or re-use one.
375
    // Either way, we need these two scopes for AsyncReset() or otherwise
376
    // for creating the new instance.
377
424
    HandleScope handle_scope(env()->isolate());
378
424
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
379
380
212
    auto& freelist = env()->file_handle_read_wrap_freelist();
381
212
    if (freelist.size() > 0) {
382
198
      read_wrap = std::move(freelist.back());
383
198
      freelist.pop_back();
384
198
      read_wrap->AsyncReset();
385
198
      read_wrap->file_handle_ = this;
386
    } else {
387
      Local<Object> wrap_obj;
388
28
      if (!env()
389
28
               ->filehandlereadwrap_template()
390
42
               ->NewInstance(env()->context())
391
14
               .ToLocal(&wrap_obj)) {
392
        return UV_EBUSY;
393
      }
394
14
      read_wrap = std::make_unique<FileHandleReadWrap>(this, wrap_obj);
395
    }
396
  }
397
212
  int64_t recommended_read = 65536;
398

212
  if (read_length_ >= 0 && read_length_ <= recommended_read)
399
9
    recommended_read = read_length_;
400
401
212
  read_wrap->buffer_ = EmitAlloc(recommended_read);
402
403
212
  current_read_ = std::move(read_wrap);
404
405
424
  current_read_->Dispatch(uv_fs_read,
406
                          fd_,
407
212
                          &current_read_->buffer_,
408
                          1,
409
                          read_offset_,
410
636
                          uv_fs_callback_t{[](uv_fs_t* req) {
411
    FileHandle* handle;
412
    {
413
212
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
414
212
      handle = req_wrap->file_handle_;
415
212
      CHECK_EQ(handle->current_read_.get(), req_wrap);
416
    }
417
418
    // ReadStart() checks whether current_read_ is set to determine whether
419
    // a read is in progress. Moving it into a local variable makes sure that
420
    // the ReadStart() call below doesn't think we're still actively reading.
421
    std::unique_ptr<FileHandleReadWrap> read_wrap =
422
424
        std::move(handle->current_read_);
423
424
212
    int result = req->result;
425
212
    uv_buf_t buffer = read_wrap->buffer_;
426
427
212
    uv_fs_req_cleanup(req);
428
429
    // Push the read wrap back to the freelist, or let it be destroyed
430
    // once we’re exiting the current scope.
431
212
    constexpr size_t wanted_freelist_fill = 100;
432
212
    auto& freelist = handle->env()->file_handle_read_wrap_freelist();
433
212
    if (freelist.size() < wanted_freelist_fill) {
434
212
      read_wrap->Reset();
435
212
      freelist.emplace_back(std::move(read_wrap));
436
    }
437
438
212
    if (result >= 0) {
439
      // Read at most as many bytes as we originally planned to.
440

211
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
441
        result = handle->read_length_;
442
443
      // If we read data and we have an expected length, decrease it by
444
      // how much we have read.
445
211
      if (handle->read_length_ >= 0)
446
15
        handle->read_length_ -= result;
447
448
      // If we have an offset, increase it by how much we have read.
449
211
      if (handle->read_offset_ >= 0)
450
209
        handle->read_offset_ += result;
451
    }
452
453
    // Reading 0 bytes from a file always means EOF, or that we reached
454
    // the end of the requested range.
455
212
    if (result == 0)
456
6
      result = UV_EOF;
457
458
212
    handle->EmitRead(result, buffer);
459
460
    // Start over, if EmitRead() didn’t tell us to stop.
461
212
    if (handle->reading_)
462
      handle->ReadStart();
463
848
  }});
464
465
212
  return 0;
466
}
467
468
231
int FileHandle::ReadStop() {
469
231
  reading_ = false;
470
231
  return 0;
471
}
472
473
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
474
475
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
476
  return new FileHandleCloseWrap(this, object);
477
}
478
479
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
480
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
481
  closing_ = true;
482
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
483
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
484
        FileHandleCloseWrap::from_req(req));
485
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
486
    handle->AfterClose();
487
488
    int result = req->result;
489
    uv_fs_req_cleanup(req);
490
    wrap->Done(result);
491
  }});
492
493
  return 0;
494
}
495
496
497
3938
void FSReqCallback::Reject(Local<Value> reject) {
498
3938
  MakeCallback(env()->oncomplete_string(), 1, &reject);
499
3938
}
500
501
3852
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
502
3852
  Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
503
3852
}
504
505
44494
void FSReqCallback::Resolve(Local<Value> value) {
506
  Local<Value> argv[2] {
507
    Null(env()->isolate()),
508
    value
509
88988
  };
510
  MakeCallback(env()->oncomplete_string(),
511
125735
               value->IsUndefined() ? 1 : arraysize(argv),
512
81241
               argv);
513
44479
}
514
515
48435
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
516
96870
  args.GetReturnValue().SetUndefined();
517
48435
}
518
519
48458
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
520
48458
  CHECK(args.IsConstructCall());
521
48458
  Environment* env = Environment::GetCurrent(args);
522
145374
  new FSReqCallback(env, args.This(), args[0]->IsTrue());
523
48458
}
524
525
49671
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
526
    : wrap_(wrap),
527
      req_(req),
528
      handle_scope_(wrap->env()->isolate()),
529
49671
      context_scope_(wrap->env()->context()) {
530
49671
  CHECK_EQ(wrap_->req(), req);
531
49671
}
532
533
148968
FSReqAfterScope::~FSReqAfterScope() {
534
49656
  uv_fs_req_cleanup(wrap_->req());
535
49656
  delete wrap_;
536
49656
}
537
538
// TODO(joyeecheung): create a normal context object, and
539
// construct the actual errors in the JS land using the context.
540
// The context should include fds for some fs APIs, currently they are
541
// missing in the error messages. The path, dest, syscall, fd, .etc
542
// can be put into the context before the binding is even invoked,
543
// the only information that has to come from the C++ layer is the
544
// error number (and possibly the syscall for abstraction),
545
// which is also why the errors should have been constructed
546
// in JS for more flexibility.
547
3980
void FSReqAfterScope::Reject(uv_fs_t* req) {
548
15920
  wrap_->Reject(UVException(wrap_->env()->isolate(),
549
3980
                            req->result,
550
3980
                            wrap_->syscall(),
551
                            nullptr,
552
                            req->path,
553
7960
                            wrap_->data()));
554
3980
}
555
556
49671
bool FSReqAfterScope::Proceed() {
557
49671
  if (req_->result < 0) {
558
3980
    Reject(req_);
559
3980
    return false;
560
  }
561
45691
  return true;
562
}
563
564
8396
void AfterNoArgs(uv_fs_t* req) {
565
8396
  FSReqBase* req_wrap = FSReqBase::from_req(req);
566
16779
  FSReqAfterScope after(req_wrap, req);
567
568
8396
  if (after.Proceed())
569
15594
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
570
8383
}
571
572
7335
void AfterStat(uv_fs_t* req) {
573
7335
  FSReqBase* req_wrap = FSReqBase::from_req(req);
574
14670
  FSReqAfterScope after(req_wrap, req);
575
576
7335
  if (after.Proceed()) {
577
4179
    req_wrap->ResolveStat(&req->statbuf);
578
  }
579
7335
}
580
581
33408
void AfterInteger(uv_fs_t* req) {
582
33408
  FSReqBase* req_wrap = FSReqBase::from_req(req);
583
66815
  FSReqAfterScope after(req_wrap, req);
584
585
33408
  if (after.Proceed())
586
66454
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
587
33407
}
588
589
288
void AfterOpenFileHandle(uv_fs_t* req) {
590
288
  FSReqBase* req_wrap = FSReqBase::from_req(req);
591
576
  FSReqAfterScope after(req_wrap, req);
592
593
288
  if (after.Proceed()) {
594
269
    FileHandle* fd = FileHandle::New(req_wrap->env(), req->result);
595
269
    if (fd == nullptr) return;
596
538
    req_wrap->Resolve(fd->object());
597
  }
598
}
599
600
// Reverse the logic applied by path.toNamespacedPath() to create a
601
// namespace-prefixed path.
602
109
void FromNamespacedPath(std::string* path) {
603
#ifdef _WIN32
604
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
605
    *path = path->substr(8);
606
    path->insert(0, "\\\\");
607
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
608
    *path = path->substr(4);
609
  }
610
#endif
611
109
}
612
613
14
void AfterMkdirp(uv_fs_t* req) {
614
14
  FSReqBase* req_wrap = FSReqBase::from_req(req);
615
28
  FSReqAfterScope after(req_wrap, req);
616
617
  MaybeLocal<Value> path;
618
  Local<Value> error;
619
620
14
  if (after.Proceed()) {
621
8
    if (!req_wrap->continuation_data()->first_path().empty()) {
622
14
      std::string first_path(req_wrap->continuation_data()->first_path());
623
7
      FromNamespacedPath(&first_path);
624
      path = StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
625
                                 req_wrap->encoding(),
626
7
                                 &error);
627
7
      if (path.IsEmpty())
628
        req_wrap->Reject(error);
629
      else
630
14
        req_wrap->Resolve(path.ToLocalChecked());
631
    } else {
632
2
      req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
633
    }
634
  }
635
14
}
636
637
6
void AfterStringPath(uv_fs_t* req) {
638
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
639
12
  FSReqAfterScope after(req_wrap, req);
640
641
  MaybeLocal<Value> link;
642
  Local<Value> error;
643
644
6
  if (after.Proceed()) {
645
    link = StringBytes::Encode(req_wrap->env()->isolate(),
646
                               req->path,
647
                               req_wrap->encoding(),
648
5
                               &error);
649
5
    if (link.IsEmpty())
650
      req_wrap->Reject(error);
651
    else
652
10
      req_wrap->Resolve(link.ToLocalChecked());
653
  }
654
6
}
655
656
63
void AfterStringPtr(uv_fs_t* req) {
657
63
  FSReqBase* req_wrap = FSReqBase::from_req(req);
658
125
  FSReqAfterScope after(req_wrap, req);
659
660
  MaybeLocal<Value> link;
661
  Local<Value> error;
662
663
63
  if (after.Proceed()) {
664
    link = StringBytes::Encode(req_wrap->env()->isolate(),
665
50
                               static_cast<const char*>(req->ptr),
666
                               req_wrap->encoding(),
667
100
                               &error);
668
50
    if (link.IsEmpty())
669
      req_wrap->Reject(error);
670
    else
671
100
      req_wrap->Resolve(link.ToLocalChecked());
672
  }
673
62
}
674
675
129
void AfterScanDir(uv_fs_t* req) {
676
129
  FSReqBase* req_wrap = FSReqBase::from_req(req);
677
255
  FSReqAfterScope after(req_wrap, req);
678
679
129
  if (!after.Proceed()) {
680
3
    return;
681
  }
682
126
  Environment* env = req_wrap->env();
683
  Local<Value> error;
684
  int r;
685
252
  std::vector<Local<Value>> name_v;
686
687
6469
  for (int i = 0; ; i++) {
688
    uv_dirent_t ent;
689
690
6469
    r = uv_fs_scandir_next(req, &ent);
691
6469
    if (r == UV_EOF)
692
126
      break;
693
6343
    if (r != 0) {
694
      return req_wrap->Reject(UVException(
695
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
696
    }
697
698
    MaybeLocal<Value> filename =
699
      StringBytes::Encode(env->isolate(),
700
          ent.name,
701
          req_wrap->encoding(),
702
6343
          &error);
703
6343
    if (filename.IsEmpty())
704
      return req_wrap->Reject(error);
705
706
6343
    name_v.push_back(filename.ToLocalChecked());
707
6343
  }
708
709
252
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
710
}
711
712
7
void AfterScanDirWithTypes(uv_fs_t* req) {
713
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
714
13
  FSReqAfterScope after(req_wrap, req);
715
716
7
  if (!after.Proceed()) {
717
1
    return;
718
  }
719
720
6
  Environment* env = req_wrap->env();
721
6
  Isolate* isolate = env->isolate();
722
  Local<Value> error;
723
  int r;
724
725
12
  std::vector<Local<Value>> name_v;
726
12
  std::vector<Local<Value>> type_v;
727
728
22
  for (int i = 0; ; i++) {
729
    uv_dirent_t ent;
730
731
22
    r = uv_fs_scandir_next(req, &ent);
732
22
    if (r == UV_EOF)
733
6
      break;
734
16
    if (r != 0) {
735
      return req_wrap->Reject(
736
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
737
    }
738
739
    MaybeLocal<Value> filename =
740
      StringBytes::Encode(isolate,
741
          ent.name,
742
          req_wrap->encoding(),
743
16
          &error);
744
16
    if (filename.IsEmpty())
745
      return req_wrap->Reject(error);
746
747
16
    name_v.push_back(filename.ToLocalChecked());
748
16
    type_v.emplace_back(Integer::New(isolate, ent.type));
749
16
  }
750
751
  Local<Value> result[] = {
752
    Array::New(isolate, name_v.data(), name_v.size()),
753
    Array::New(isolate, type_v.data(), type_v.size())
754
18
  };
755
12
  req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
756
}
757
758
197
void Access(const FunctionCallbackInfo<Value>& args) {
759
197
  Environment* env = Environment::GetCurrent(args);
760
197
  Isolate* isolate = env->isolate();
761
394
  HandleScope scope(isolate);
762
763
197
  const int argc = args.Length();
764
197
  CHECK_GE(argc, 2);
765
766
394
  CHECK(args[1]->IsInt32());
767
591
  int mode = args[1].As<Int32>()->Value();
768
769
394
  BufferValue path(isolate, args[0]);
770
197
  CHECK_NOT_NULL(*path);
771
772
197
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
773
197
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
774
51
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
775
51
              uv_fs_access, *path, mode);
776
  } else {  // access(path, mode, undefined, ctx)
777
146
    CHECK_EQ(argc, 4);
778
292
    FSReqWrapSync req_wrap_sync;
779

148
    FS_SYNC_TRACE_BEGIN(access);
780
292
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
781

148
    FS_SYNC_TRACE_END(access);
782
  }
783
197
}
784
785
786
42382
void Close(const FunctionCallbackInfo<Value>& args) {
787
42382
  Environment* env = Environment::GetCurrent(args);
788
789
42382
  const int argc = args.Length();
790
42382
  CHECK_GE(argc, 2);
791
792
84764
  CHECK(args[0]->IsInt32());
793
127146
  int fd = args[0].As<Int32>()->Value();
794
795
42382
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
796
42382
  if (req_wrap_async != nullptr) {  // close(fd, req)
797
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
798
5033
              uv_fs_close, fd);
799
  } else {  // close(fd, undefined, ctx)
800
37349
    CHECK_EQ(argc, 3);
801
74698
    FSReqWrapSync req_wrap_sync;
802

37409
    FS_SYNC_TRACE_BEGIN(close);
803
37349
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
804

37409
    FS_SYNC_TRACE_END(close);
805
  }
806
42382
}
807
808
809
// Used to speed up module loading.  Returns the contents of the file as
810
// a string or undefined when the file cannot be opened or "main" is not found
811
// in the file.
812
45619
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
813
45619
  Environment* env = Environment::GetCurrent(args);
814
45619
  Isolate* isolate = env->isolate();
815
45619
  uv_loop_t* loop = env->event_loop();
816
817
136857
  CHECK(args[0]->IsString());
818
51107
  node::Utf8Value path(isolate, args[0]);
819
820
45619
  if (strlen(*path) != path.length())
821
3
    return;  // Contains a nul byte.
822
823
  uv_fs_t open_req;
824
45616
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
825
45616
  uv_fs_req_cleanup(&open_req);
826
827
45616
  if (fd < 0) {
828
40127
    return;
829
  }
830
831
5489
  std::shared_ptr<void> defer_close(nullptr, [fd, loop] (...) {
832
    uv_fs_t close_req;
833
5489
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
834
5489
    uv_fs_req_cleanup(&close_req);
835
16466
  });
836
837
5489
  const size_t kBlockSize = 32 << 10;
838
10977
  std::vector<char> chars;
839
5489
  int64_t offset = 0;
840
  ssize_t numchars;
841
  do {
842
5489
    const size_t start = chars.size();
843
5489
    chars.resize(start + kBlockSize);
844
845
    uv_buf_t buf;
846
5489
    buf.base = &chars[start];
847
5489
    buf.len = kBlockSize;
848
849
    uv_fs_t read_req;
850
5489
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
851
5489
    uv_fs_req_cleanup(&read_req);
852
853
5489
    if (numchars < 0)
854
1
      return;
855
856
5488
    offset += numchars;
857
5488
  } while (static_cast<size_t>(numchars) == kBlockSize);
858
859
5488
  size_t start = 0;
860

5488
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
861
1
    start = 3;  // Skip UTF-8 BOM.
862
  }
863
864
5488
  const size_t size = offset - start;
865
5488
  char* p = &chars[start];
866
5488
  char* pe = &chars[size];
867
  char* pos[2];
868
5488
  char** ppos = &pos[0];
869
870
2712024
  while (p < pe) {
871
1358751
    char c = *p++;
872
1358751
    if (c == '"') goto quote;  // Keeps code flat and inner loop small.
873

1227653
    if (c == '\\' && p < pe && *p == '"') p++;
874
1227653
    continue;
875
quote:
876
131098
    *ppos++ = p;
877
131098
    if (ppos < &pos[2]) continue;
878
65549
    ppos = &pos[0];
879
880
65549
    char* s = &pos[0][0];
881
65549
    char* se = &pos[1][-1];  // Exclude quote.
882
65549
    size_t n = se - s;
883
884
65549
    if (n == 4) {
885
5730
      if (0 == memcmp(s, "main", 4)) break;
886
5630
      if (0 == memcmp(s, "name", 4)) break;
887
5082
      if (0 == memcmp(s, "type", 4)) break;
888
59819
    } else if (n == 7) {
889
931
      if (0 == memcmp(s, "exports", 7)) break;
890
    }
891
  }
892
893
  Local<String> return_value;
894
5488
  if (p < pe) {
895
    return_value =
896
10966
        String::NewFromUtf8(isolate,
897
5483
                            &chars[start],
898
                            v8::NewStringType::kNormal,
899
10966
                            size).ToLocalChecked();
900
  } else {
901
5
    return_value = env->empty_object_string();
902
  }
903
904
10976
  args.GetReturnValue().Set(return_value);
905
}
906
907
// Used to speed up module loading.  Returns 0 if the path refers to
908
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
909
// The speedup comes from not creating thousands of Stat and Error objects.
910
102410
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
911
102410
  Environment* env = Environment::GetCurrent(args);
912
913
307230
  CHECK(args[0]->IsString());
914
204820
  node::Utf8Value path(env->isolate(), args[0]);
915
916
  uv_fs_t req;
917
102410
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
918
102410
  if (rc == 0) {
919
48904
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
920
48904
    rc = !!(s->st_mode & S_IFDIR);
921
  }
922
102410
  uv_fs_req_cleanup(&req);
923
924
204820
  args.GetReturnValue().Set(rc);
925
102410
}
926
927
34855
static void Stat(const FunctionCallbackInfo<Value>& args) {
928
34855
  Environment* env = Environment::GetCurrent(args);
929
930
34855
  const int argc = args.Length();
931
34855
  CHECK_GE(argc, 2);
932
933
69679
  BufferValue path(env->isolate(), args[0]);
934
34855
  CHECK_NOT_NULL(*path);
935
936
69710
  bool use_bigint = args[1]->IsTrue();
937
69710
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
938
34855
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
939
1813
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
940
1813
              uv_fs_stat, *path);
941
  } else {  // stat(path, use_bigint, undefined, ctx)
942
33042
    CHECK_EQ(argc, 4);
943
66053
    FSReqWrapSync req_wrap_sync;
944

33044
    FS_SYNC_TRACE_BEGIN(stat);
945
66084
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
946

33044
    FS_SYNC_TRACE_END(stat);
947
33042
    if (err != 0) {
948
31
      return;  // error info is in ctx
949
    }
950
951
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
952
33011
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
953
66022
    args.GetReturnValue().Set(arr);
954
  }
955
}
956
957
91861
static void LStat(const FunctionCallbackInfo<Value>& args) {
958
91861
  Environment* env = Environment::GetCurrent(args);
959
960
91861
  const int argc = args.Length();
961
91861
  CHECK_GE(argc, 3);
962
963
183459
  BufferValue path(env->isolate(), args[0]);
964
91861
  CHECK_NOT_NULL(*path);
965
966
183722
  bool use_bigint = args[1]->IsTrue();
967
183722
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
968
91861
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
969
4381
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
970
4381
              uv_fs_lstat, *path);
971
  } else {  // lstat(path, use_bigint, undefined, ctx)
972
87480
    CHECK_EQ(argc, 4);
973
174697
    FSReqWrapSync req_wrap_sync;
974

87514
    FS_SYNC_TRACE_BEGIN(lstat);
975
87480
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
976
87480
                       *path);
977

87514
    FS_SYNC_TRACE_END(lstat);
978
87480
    if (err != 0) {
979
263
      return;  // error info is in ctx
980
    }
981
982
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
983
87217
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
984
174434
    args.GetReturnValue().Set(arr);
985
  }
986
}
987
988
34404
static void FStat(const FunctionCallbackInfo<Value>& args) {
989
34404
  Environment* env = Environment::GetCurrent(args);
990
991
34404
  const int argc = args.Length();
992
34404
  CHECK_GE(argc, 2);
993
994
68808
  CHECK(args[0]->IsInt32());
995
103212
  int fd = args[0].As<Int32>()->Value();
996
997
68808
  bool use_bigint = args[1]->IsTrue();
998
68808
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
999
34404
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1000
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1001
1141
              uv_fs_fstat, fd);
1002
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1003
33263
    CHECK_EQ(argc, 4);
1004
66509
    FSReqWrapSync req_wrap_sync;
1005

33273
    FS_SYNC_TRACE_BEGIN(fstat);
1006
33263
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1007

33273
    FS_SYNC_TRACE_END(fstat);
1008
33263
    if (err != 0) {
1009
17
      return;  // error info is in ctx
1010
    }
1011
1012
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
1013
33246
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1014
66492
    args.GetReturnValue().Set(arr);
1015
  }
1016
}
1017
1018
206
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1019
206
  Environment* env = Environment::GetCurrent(args);
1020
206
  Isolate* isolate = env->isolate();
1021
1022
206
  int argc = args.Length();
1023
206
  CHECK_GE(argc, 4);
1024
1025
412
  BufferValue target(isolate, args[0]);
1026
206
  CHECK_NOT_NULL(*target);
1027
412
  BufferValue path(isolate, args[1]);
1028
206
  CHECK_NOT_NULL(*path);
1029
1030
412
  CHECK(args[2]->IsInt32());
1031
618
  int flags = args[2].As<Int32>()->Value();
1032
1033
206
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1034
206
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1035
24
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1036
24
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1037
  } else {  // symlink(target, path, flags, undefinec, ctx)
1038
182
    CHECK_EQ(argc, 5);
1039
364
    FSReqWrapSync req_wrap_sync;
1040

186
    FS_SYNC_TRACE_BEGIN(symlink);
1041
182
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1042
182
             uv_fs_symlink, *target, *path, flags);
1043

186
    FS_SYNC_TRACE_END(symlink);
1044
  }
1045
206
}
1046
1047
76
static void Link(const FunctionCallbackInfo<Value>& args) {
1048
76
  Environment* env = Environment::GetCurrent(args);
1049
76
  Isolate* isolate = env->isolate();
1050
1051
76
  int argc = args.Length();
1052
76
  CHECK_GE(argc, 3);
1053
1054
152
  BufferValue src(isolate, args[0]);
1055
76
  CHECK_NOT_NULL(*src);
1056
1057
152
  BufferValue dest(isolate, args[1]);
1058
76
  CHECK_NOT_NULL(*dest);
1059
1060
76
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1061
76
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1062
71
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1063
71
                  AfterNoArgs, uv_fs_link, *src, *dest);
1064
  } else {  // link(src, dest)
1065
5
    CHECK_EQ(argc, 4);
1066
10
    FSReqWrapSync req_wrap_sync;
1067

11
    FS_SYNC_TRACE_BEGIN(link);
1068
5
    SyncCall(env, args[3], &req_wrap_sync, "link",
1069
5
             uv_fs_link, *src, *dest);
1070

11
    FS_SYNC_TRACE_END(link);
1071
  }
1072
76
}
1073
1074
89
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1075
89
  Environment* env = Environment::GetCurrent(args);
1076
89
  Isolate* isolate = env->isolate();
1077
1078
89
  int argc = args.Length();
1079
89
  CHECK_GE(argc, 3);
1080
1081
177
  BufferValue path(isolate, args[0]);
1082
89
  CHECK_NOT_NULL(*path);
1083
1084
89
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1085
1086
89
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1087
89
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1088
41
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1089
41
              uv_fs_readlink, *path);
1090
  } else {
1091
48
    CHECK_EQ(argc, 4);
1092
95
    FSReqWrapSync req_wrap_sync;
1093

50
    FS_SYNC_TRACE_BEGIN(readlink);
1094
48
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1095
48
                       uv_fs_readlink, *path);
1096

50
    FS_SYNC_TRACE_END(readlink);
1097
48
    if (err < 0) {
1098
1
      return;  // syscall failed, no need to continue, error info is in ctx
1099
    }
1100
47
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1101
1102
    Local<Value> error;
1103
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1104
                                               link_path,
1105
                                               encoding,
1106
47
                                               &error);
1107
47
    if (rc.IsEmpty()) {
1108
      Local<Object> ctx = args[3].As<Object>();
1109
      ctx->Set(env->context(), env->error_string(), error).Check();
1110
      return;
1111
    }
1112
1113
94
    args.GetReturnValue().Set(rc.ToLocalChecked());
1114
  }
1115
}
1116
1117
144
static void Rename(const FunctionCallbackInfo<Value>& args) {
1118
144
  Environment* env = Environment::GetCurrent(args);
1119
144
  Isolate* isolate = env->isolate();
1120
1121
144
  int argc = args.Length();
1122
144
  CHECK_GE(argc, 3);
1123
1124
288
  BufferValue old_path(isolate, args[0]);
1125
144
  CHECK_NOT_NULL(*old_path);
1126
288
  BufferValue new_path(isolate, args[1]);
1127
144
  CHECK_NOT_NULL(*new_path);
1128
1129
144
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1130
144
  if (req_wrap_async != nullptr) {
1131
139
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1132
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1133
139
                  *old_path, *new_path);
1134
  } else {
1135
5
    CHECK_EQ(argc, 4);
1136
10
    FSReqWrapSync req_wrap_sync;
1137

7
    FS_SYNC_TRACE_BEGIN(rename);
1138
5
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1139
5
             *old_path, *new_path);
1140

7
    FS_SYNC_TRACE_END(rename);
1141
  }
1142
144
}
1143
1144
50
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1145
50
  Environment* env = Environment::GetCurrent(args);
1146
1147
50
  const int argc = args.Length();
1148
50
  CHECK_GE(argc, 3);
1149
1150
100
  CHECK(args[0]->IsInt32());
1151
150
  const int fd = args[0].As<Int32>()->Value();
1152
1153
50
  CHECK(IsSafeJsInt(args[1]));
1154
150
  const int64_t len = args[1].As<Integer>()->Value();
1155
1156
50
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1157
50
  if (req_wrap_async != nullptr) {
1158
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1159
37
              uv_fs_ftruncate, fd, len);
1160
  } else {
1161
13
    CHECK_EQ(argc, 4);
1162
26
    FSReqWrapSync req_wrap_sync;
1163

15
    FS_SYNC_TRACE_BEGIN(ftruncate);
1164
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1165
13
             len);
1166

15
    FS_SYNC_TRACE_END(ftruncate);
1167
  }
1168
50
}
1169
1170
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1171
7
  Environment* env = Environment::GetCurrent(args);
1172
1173
7
  const int argc = args.Length();
1174
7
  CHECK_GE(argc, 2);
1175
1176
14
  CHECK(args[0]->IsInt32());
1177
21
  const int fd = args[0].As<Int32>()->Value();
1178
1179
7
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1180
7
  if (req_wrap_async != nullptr) {
1181
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1182
4
              uv_fs_fdatasync, fd);
1183
  } else {
1184
3
    CHECK_EQ(argc, 3);
1185
6
    FSReqWrapSync req_wrap_sync;
1186

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

5
    FS_SYNC_TRACE_END(fdatasync);
1189
  }
1190
7
}
1191
1192
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1193
23
  Environment* env = Environment::GetCurrent(args);
1194
1195
23
  const int argc = args.Length();
1196
23
  CHECK_GE(argc, 2);
1197
1198
46
  CHECK(args[0]->IsInt32());
1199
69
  const int fd = args[0].As<Int32>()->Value();
1200
1201
23
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1202
23
  if (req_wrap_async != nullptr) {
1203
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1204
6
              uv_fs_fsync, fd);
1205
  } else {
1206
17
    CHECK_EQ(argc, 3);
1207
34
    FSReqWrapSync req_wrap_sync;
1208

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

19
    FS_SYNC_TRACE_END(fsync);
1211
  }
1212
23
}
1213
1214
1302
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1215
1302
  Environment* env = Environment::GetCurrent(args);
1216
1217
1302
  const int argc = args.Length();
1218
1302
  CHECK_GE(argc, 2);
1219
1220
2604
  BufferValue path(env->isolate(), args[0]);
1221
1302
  CHECK_NOT_NULL(*path);
1222
1223
1302
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1224
1302
  if (req_wrap_async != nullptr) {
1225
550
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1226
550
              uv_fs_unlink, *path);
1227
  } else {
1228
752
    CHECK_EQ(argc, 3);
1229
1504
    FSReqWrapSync req_wrap_sync;
1230

812
    FS_SYNC_TRACE_BEGIN(unlink);
1231
1504
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1232

812
    FS_SYNC_TRACE_END(unlink);
1233
  }
1234
1302
}
1235
1236
1019
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1237
1019
  Environment* env = Environment::GetCurrent(args);
1238
1239
1019
  const int argc = args.Length();
1240
1019
  CHECK_GE(argc, 2);
1241
1242
2038
  BufferValue path(env->isolate(), args[0]);
1243
1019
  CHECK_NOT_NULL(*path);
1244
1245
1019
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1246
1019
  if (req_wrap_async != nullptr) {
1247
121
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1248
121
              uv_fs_rmdir, *path);
1249
  } else {  // rmdir(path, undefined, ctx)
1250
898
    CHECK_EQ(argc, 3);
1251
1796
    FSReqWrapSync req_wrap_sync;
1252

904
    FS_SYNC_TRACE_BEGIN(rmdir);
1253
898
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1254
898
             uv_fs_rmdir, *path);
1255

904
    FS_SYNC_TRACE_END(rmdir);
1256
  }
1257
1019
}
1258
1259
4440
int MKDirpSync(uv_loop_t* loop,
1260
               uv_fs_t* req,
1261
               const std::string& path,
1262
               int mode,
1263
               uv_fs_cb cb) {
1264
4440
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1265
1266
  // on the first iteration of algorithm, stash state information.
1267
4441
  if (req_wrap->continuation_data() == nullptr) {
1268
    req_wrap->set_continuation_data(
1269
4441
        std::make_unique<FSContinuationData>(req, mode, cb));
1270
4441
    req_wrap->continuation_data()->PushPath(std::move(path));
1271
  }
1272
1273
13151
  while (req_wrap->continuation_data()->paths().size() > 0) {
1274
8834
    std::string next_path = req_wrap->continuation_data()->PopPath();
1275
4479
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1276
    while (true) {
1277

4480
      switch (err) {
1278
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1279
        // ~FSReqWrapSync():
1280
        case 0:
1281
138
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1282
138
          if (req_wrap->continuation_data()->paths().size() == 0) {
1283
120
            return 0;
1284
          }
1285
18
          break;
1286
        case UV_EACCES:
1287
        case UV_ENOTDIR:
1288
        case UV_EPERM: {
1289
2
          return err;
1290
        }
1291
        case UV_ENOENT: {
1292
          std::string dirname = next_path.substr(0,
1293
20
                                        next_path.find_last_of(kPathSeparator));
1294
20
          if (dirname != next_path) {
1295
19
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1296
19
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1297
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1298
1
            err = UV_EEXIST;
1299
1
            continue;
1300
          }
1301
19
          break;
1302
        }
1303
        default:
1304
4320
          uv_fs_req_cleanup(req);
1305
4320
          int orig_err = err;
1306
4320
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1307

4320
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1308
1
            uv_fs_req_cleanup(req);
1309

2
            if (orig_err == UV_EEXIST &&
1310
1
              req_wrap->continuation_data()->paths().size() > 0) {
1311
              return UV_ENOTDIR;
1312
            }
1313
1
            return UV_EEXIST;
1314
          }
1315
4319
          if (err < 0) return err;
1316
4318
          break;
1317
      }
1318
4355
      break;
1319
1
    }
1320
4355
    uv_fs_req_cleanup(req);
1321
  }
1322
1323
4317
  return 0;
1324
}
1325
1326
24
int MKDirpAsync(uv_loop_t* loop,
1327
                uv_fs_t* req,
1328
                const char* path,
1329
                int mode,
1330
                uv_fs_cb cb) {
1331
24
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1332
  // on the first iteration of algorithm, stash state information.
1333
24
  if (req_wrap->continuation_data() == nullptr) {
1334
    req_wrap->set_continuation_data(
1335
14
        std::make_unique<FSContinuationData>(req, mode, cb));
1336
14
    req_wrap->continuation_data()->PushPath(std::move(path));
1337
  }
1338
1339
  // on each iteration of algorithm, mkdir directory on top of stack.
1340
48
  std::string next_path = req_wrap->continuation_data()->PopPath();
1341
24
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1342
72
                        uv_fs_callback_t{[](uv_fs_t* req) {
1343
24
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1344
24
    Environment* env = req_wrap->env();
1345
24
    uv_loop_t* loop = env->event_loop();
1346
48
    std::string path = req->path;
1347
24
    int err = req->result;
1348
1349
    while (true) {
1350

25
      switch (err) {
1351
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1352
        // FSReqAfterScope::~FSReqAfterScope()
1353
        case 0: {
1354
12
          if (req_wrap->continuation_data()->paths().size() == 0) {
1355
7
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1356
7
            req_wrap->continuation_data()->Done(0);
1357
          } else {
1358
5
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1359
5
            uv_fs_req_cleanup(req);
1360
5
            MKDirpAsync(loop, req, path.c_str(),
1361
5
                        req_wrap->continuation_data()->mode(), nullptr);
1362
          }
1363
12
          break;
1364
        }
1365
        case UV_EACCES:
1366
        case UV_ENOTDIR:
1367
        case UV_EPERM: {
1368
3
          req_wrap->continuation_data()->Done(err);
1369
3
          break;
1370
        }
1371
        case UV_ENOENT: {
1372
          std::string dirname = path.substr(0,
1373
6
                                            path.find_last_of(kPathSeparator));
1374
6
          if (dirname != path) {
1375
5
            req_wrap->continuation_data()->PushPath(std::move(path));
1376
5
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1377
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1378
1
            err = UV_EEXIST;
1379
1
            continue;
1380
          }
1381
5
          uv_fs_req_cleanup(req);
1382
5
          MKDirpAsync(loop, req, path.c_str(),
1383
5
                      req_wrap->continuation_data()->mode(), nullptr);
1384
5
          break;
1385
        }
1386
        default:
1387
4
          uv_fs_req_cleanup(req);
1388
          // Stash err for use in the callback.
1389
4
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1390
4
          int err = uv_fs_stat(loop, req, path.c_str(),
1391
12
                               uv_fs_callback_t{[](uv_fs_t* req) {
1392
4
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1393
4
            int err = req->result;
1394

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1395
4
                  req_wrap->continuation_data()->paths().size() > 0) {
1396
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1397
                Environment* env = req_wrap->env();
1398
                uv_loop_t* loop = env->event_loop();
1399
                std::string path = req->path;
1400
                uv_fs_req_cleanup(req);
1401
                MKDirpAsync(loop, req, path.c_str(),
1402
                            req_wrap->continuation_data()->mode(), nullptr);
1403
                return;
1404
              }
1405
              err = UV_ENOTDIR;
1406
            }
1407
            // verify that the path pointed to is actually a directory.
1408

4
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1409
4
            req_wrap->continuation_data()->Done(err);
1410
12
          }});
1411
4
          if (err < 0) req_wrap->continuation_data()->Done(err);
1412
4
          break;
1413
      }
1414
24
      break;
1415
1
    }
1416
96
  }});
1417
1418
48
  return err;
1419
}
1420
1421
108
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1422
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1423
108
  env->PrintSyncTrace();
1424
216
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1425
108
                       nullptr);
1426
108
  if (err < 0) {
1427
4
    v8::Local<v8::Context> context = env->context();
1428
8
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1429
4
    v8::Isolate* isolate = env->isolate();
1430
8
    ctx_obj->Set(context,
1431
                 env->errno_string(),
1432
16
                 v8::Integer::New(isolate, err)).Check();
1433
8
    ctx_obj->Set(context,
1434
                 env->syscall_string(),
1435
16
                 OneByteString(isolate, "mkdir")).Check();
1436
  }
1437
108
  return err;
1438
}
1439
1440
1607
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1441
1607
  Environment* env = Environment::GetCurrent(args);
1442
1443
1607
  const int argc = args.Length();
1444
1607
  CHECK_GE(argc, 4);
1445
1446
3214
  BufferValue path(env->isolate(), args[0]);
1447
1607
  CHECK_NOT_NULL(*path);
1448
1449
3214
  CHECK(args[1]->IsInt32());
1450
4821
  const int mode = args[1].As<Int32>()->Value();
1451
1452
3214
  CHECK(args[2]->IsBoolean());
1453
3214
  bool mkdirp = args[2]->IsTrue();
1454
1455
1607
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1456
1607
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1457

853
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1458
              mkdirp ? AfterMkdirp : AfterNoArgs,
1459
853
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1460
  } else {  // mkdir(path, mode, undefined, ctx)
1461
754
    CHECK_EQ(argc, 5);
1462
1508
    FSReqWrapSync req_wrap_sync;
1463

758
    FS_SYNC_TRACE_BEGIN(mkdir);
1464
754
    if (mkdirp) {
1465
108
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1466

212
      if (err == 0 &&
1467
104
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1468
        Local<Value> error;
1469
204
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1470
102
        FromNamespacedPath(&first_path);
1471
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1472
                                                     first_path.c_str(),
1473
102
                                                     UTF8, &error);
1474
102
        if (path.IsEmpty()) {
1475
          Local<Object> ctx = args[4].As<Object>();
1476
          ctx->Set(env->context(), env->error_string(), error).Check();
1477
          return;
1478
        }
1479
204
        args.GetReturnValue().Set(path.ToLocalChecked());
1480
      }
1481
    } else {
1482
646
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1483
646
               uv_fs_mkdir, *path, mode);
1484
    }
1485


758
    FS_SYNC_TRACE_END(mkdir);
1486
  }
1487
}
1488
1489
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1490
42
  Environment* env = Environment::GetCurrent(args);
1491
42
  Isolate* isolate = env->isolate();
1492
1493
42
  const int argc = args.Length();
1494
42
  CHECK_GE(argc, 3);
1495
1496
82
  BufferValue path(isolate, args[0]);
1497
42
  CHECK_NOT_NULL(*path);
1498
1499
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1500
1501
42
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1502
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1503
22
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1504
22
              uv_fs_realpath, *path);
1505
  } else {  // realpath(path, encoding, undefined, ctx)
1506
20
    CHECK_EQ(argc, 4);
1507
38
    FSReqWrapSync req_wrap_sync;
1508

22
    FS_SYNC_TRACE_BEGIN(realpath);
1509
20
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1510
20
                       uv_fs_realpath, *path);
1511

22
    FS_SYNC_TRACE_END(realpath);
1512
20
    if (err < 0) {
1513
2
      return;  // syscall failed, no need to continue, error info is in ctx
1514
    }
1515
1516
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1517
1518
    Local<Value> error;
1519
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1520
                                               link_path,
1521
                                               encoding,
1522
18
                                               &error);
1523
18
    if (rc.IsEmpty()) {
1524
      Local<Object> ctx = args[3].As<Object>();
1525
      ctx->Set(env->context(), env->error_string(), error).Check();
1526
      return;
1527
    }
1528
1529
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1530
  }
1531
}
1532
1533
13489
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1534
13489
  Environment* env = Environment::GetCurrent(args);
1535
13489
  Isolate* isolate = env->isolate();
1536
1537
13489
  const int argc = args.Length();
1538
13489
  CHECK_GE(argc, 3);
1539
1540
26929
  BufferValue path(isolate, args[0]);
1541
13489
  CHECK_NOT_NULL(*path);
1542
1543
13489
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1544
1545
26978
  bool with_types = args[2]->IsTrue();
1546
1547
13489
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1548
13489
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1549
136
    if (with_types) {
1550
7
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1551
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1552
    } else {
1553
129
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1554
129
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1555
    }
1556
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1557
13353
    CHECK_EQ(argc, 5);
1558
26657
    FSReqWrapSync req_wrap_sync;
1559

13355
    FS_SYNC_TRACE_BEGIN(readdir);
1560
13353
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1561
13353
                       uv_fs_scandir, *path, 0 /*flags*/);
1562

13355
    FS_SYNC_TRACE_END(readdir);
1563
13353
    if (err < 0) {
1564
49
      return;  // syscall failed, no need to continue, error info is in ctx
1565
    }
1566
1567
13304
    CHECK_GE(req_wrap_sync.req.result, 0);
1568
    int r;
1569
26608
    std::vector<Local<Value>> name_v;
1570
26608
    std::vector<Local<Value>> type_v;
1571
1572
724369
    for (int i = 0; ; i++) {
1573
      uv_dirent_t ent;
1574
1575
724369
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1576
724369
      if (r == UV_EOF)
1577
13304
        break;
1578
711065
      if (r != 0) {
1579
        Local<Object> ctx = args[4].As<Object>();
1580
        ctx->Set(env->context(), env->errno_string(),
1581
                 Integer::New(isolate, r)).Check();
1582
        ctx->Set(env->context(), env->syscall_string(),
1583
                 OneByteString(isolate, "readdir")).Check();
1584
        return;
1585
      }
1586
1587
      Local<Value> error;
1588
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1589
                                                       ent.name,
1590
                                                       encoding,
1591
711065
                                                       &error);
1592
1593
711065
      if (filename.IsEmpty()) {
1594
        Local<Object> ctx = args[4].As<Object>();
1595
        ctx->Set(env->context(), env->error_string(), error).Check();
1596
        return;
1597
      }
1598
1599
711065
      name_v.push_back(filename.ToLocalChecked());
1600
1601
711065
      if (with_types) {
1602
390
        type_v.emplace_back(Integer::New(isolate, ent.type));
1603
      }
1604
711065
    }
1605
1606
1607
13304
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1608
13304
    if (with_types) {
1609
      Local<Value> result[] = {
1610
        names,
1611
        Array::New(isolate, type_v.data(), type_v.size())
1612
30
      };
1613
30
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1614
    } else {
1615
26588
      args.GetReturnValue().Set(names);
1616
    }
1617
  }
1618
}
1619
1620
42956
static void Open(const FunctionCallbackInfo<Value>& args) {
1621
42956
  Environment* env = Environment::GetCurrent(args);
1622
1623
42956
  const int argc = args.Length();
1624
42956
  CHECK_GE(argc, 3);
1625
1626
85912
  BufferValue path(env->isolate(), args[0]);
1627
42956
  CHECK_NOT_NULL(*path);
1628
1629
85912
  CHECK(args[1]->IsInt32());
1630
128868
  const int flags = args[1].As<Int32>()->Value();
1631
1632
85912
  CHECK(args[2]->IsInt32());
1633
128868
  const int mode = args[2].As<Int32>()->Value();
1634
1635
42956
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1636
42956
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1637
5272
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1638
5272
              uv_fs_open, *path, flags, mode);
1639
  } else {  // open(path, flags, mode, undefined, ctx)
1640
37684
    CHECK_EQ(argc, 5);
1641
75368
    FSReqWrapSync req_wrap_sync;
1642

37756
    FS_SYNC_TRACE_BEGIN(open);
1643
37684
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1644
37684
                          uv_fs_open, *path, flags, mode);
1645

37756
    FS_SYNC_TRACE_END(open);
1646
75368
    args.GetReturnValue().Set(result);
1647
  }
1648
42956
}
1649
1650
289
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1651
289
  Environment* env = Environment::GetCurrent(args);
1652
289
  Isolate* isolate = env->isolate();
1653
1654
289
  const int argc = args.Length();
1655
289
  CHECK_GE(argc, 3);
1656
1657
578
  BufferValue path(isolate, args[0]);
1658
289
  CHECK_NOT_NULL(*path);
1659
1660
578
  CHECK(args[1]->IsInt32());
1661
867
  const int flags = args[1].As<Int32>()->Value();
1662
1663
578
  CHECK(args[2]->IsInt32());
1664
867
  const int mode = args[2].As<Int32>()->Value();
1665
1666
289
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1667
289
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1668
288
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1669
288
              uv_fs_open, *path, flags, mode);
1670
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1671
1
    CHECK_EQ(argc, 5);
1672
2
    FSReqWrapSync req_wrap_sync;
1673

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

1
    FS_SYNC_TRACE_END(open);
1677
1
    if (result < 0) {
1678
      return;  // syscall failed, no need to continue, error info is in ctx
1679
    }
1680
1
    FileHandle* fd = FileHandle::New(env, result);
1681
1
    if (fd == nullptr) return;
1682
3
    args.GetReturnValue().Set(fd->object());
1683
  }
1684
}
1685
1686
33
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1687
33
  Environment* env = Environment::GetCurrent(args);
1688
33
  Isolate* isolate = env->isolate();
1689
1690
33
  const int argc = args.Length();
1691
33
  CHECK_GE(argc, 3);
1692
1693
66
  BufferValue src(isolate, args[0]);
1694
33
  CHECK_NOT_NULL(*src);
1695
1696
66
  BufferValue dest(isolate, args[1]);
1697
33
  CHECK_NOT_NULL(*dest);
1698
1699
66
  CHECK(args[2]->IsInt32());
1700
99
  const int flags = args[2].As<Int32>()->Value();
1701
1702
33
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1703
33
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1704
14
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1705
14
                  *dest, dest.length(), UTF8, AfterNoArgs,
1706
14
                  uv_fs_copyfile, *src, *dest, flags);
1707
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1708
19
    CHECK_EQ(argc, 5);
1709
38
    FSReqWrapSync req_wrap_sync;
1710

21
    FS_SYNC_TRACE_BEGIN(copyfile);
1711
19
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1712
19
             uv_fs_copyfile, *src, *dest, flags);
1713

21
    FS_SYNC_TRACE_END(copyfile);
1714
  }
1715
33
}
1716
1717
1718
// Wrapper for write(2).
1719
//
1720
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1721
// 0 fd        integer. file descriptor
1722
// 1 buffer    the data to write
1723
// 2 offset    where in the buffer to start from
1724
// 3 length    how much to write
1725
// 4 position  if integer, position to write at in the file.
1726
//             if null, write from the current position
1727
40863
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1728
40863
  Environment* env = Environment::GetCurrent(args);
1729
1730
40863
  const int argc = args.Length();
1731
40863
  CHECK_GE(argc, 4);
1732
1733
81726
  CHECK(args[0]->IsInt32());
1734
122589
  const int fd = args[0].As<Int32>()->Value();
1735
1736
40863
  CHECK(Buffer::HasInstance(args[1]));
1737
81726
  Local<Object> buffer_obj = args[1].As<Object>();
1738
40863
  char* buffer_data = Buffer::Data(buffer_obj);
1739
40863
  size_t buffer_length = Buffer::Length(buffer_obj);
1740
1741
40863
  CHECK(IsSafeJsInt(args[2]));
1742
122589
  const int64_t off_64 = args[2].As<Integer>()->Value();
1743
40863
  CHECK_GE(off_64, 0);
1744
40863
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1745
40863
  const size_t off = static_cast<size_t>(off_64);
1746
1747
81726
  CHECK(args[3]->IsInt32());
1748
122589
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1749
40863
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1750
40863
  CHECK_LE(len, buffer_length);
1751
40863
  CHECK_GE(off + len, off);
1752
1753
40863
  const int64_t pos = GetOffset(args[4]);
1754
1755
40863
  char* buf = buffer_data + off;
1756
40863
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1757
1758
40863
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1759
40863
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1760
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1761
14334
              uv_fs_write, fd, &uvbuf, 1, pos);
1762
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1763
26529
    CHECK_EQ(argc, 7);
1764
53058
    FSReqWrapSync req_wrap_sync;
1765

26579
    FS_SYNC_TRACE_BEGIN(write);
1766
26529
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1767
26529
                                uv_fs_write, fd, &uvbuf, 1, pos);
1768

26579
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1769
79587
    args.GetReturnValue().Set(bytesWritten);
1770
  }
1771
40863
}
1772
1773
1774
// Wrapper for writev(2).
1775
//
1776
// bytesWritten = writev(fd, chunks, position, callback)
1777
// 0 fd        integer. file descriptor
1778
// 1 chunks    array of buffers to write
1779
// 2 position  if integer, position to write at in the file.
1780
//             if null, write from the current position
1781
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1782
18
  Environment* env = Environment::GetCurrent(args);
1783
1784
18
  const int argc = args.Length();
1785
18
  CHECK_GE(argc, 3);
1786
1787
36
  CHECK(args[0]->IsInt32());
1788
54
  const int fd = args[0].As<Int32>()->Value();
1789
1790
36
  CHECK(args[1]->IsArray());
1791
36
  Local<Array> chunks = args[1].As<Array>();
1792
1793
18
  int64_t pos = GetOffset(args[2]);
1794
1795
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1796
1797
68
  for (uint32_t i = 0; i < iovs.length(); i++) {
1798
150
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1799
50
    CHECK(Buffer::HasInstance(chunk));
1800
50
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1801
  }
1802
1803
18
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1804
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1805
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1806
14
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1807
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1808
4
    CHECK_EQ(argc, 5);
1809
8
    FSReqWrapSync req_wrap_sync;
1810

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1814
12
    args.GetReturnValue().Set(bytesWritten);
1815
  }
1816
18
}
1817
1818
1819
// Wrapper for write(2).
1820
//
1821
// bytesWritten = write(fd, string, position, enc, callback)
1822
// 0 fd        integer. file descriptor
1823
// 1 string    non-buffer values are converted to strings
1824
// 2 position  if integer, position to write at in the file.
1825
//             if null, write from the current position
1826
// 3 enc       encoding of string
1827
1443
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1828
1443
  Environment* env = Environment::GetCurrent(args);
1829
1443
  Isolate* isolate = env->isolate();
1830
1831
1443
  const int argc = args.Length();
1832
1443
  CHECK_GE(argc, 4);
1833
1834
2886
  CHECK(args[0]->IsInt32());
1835
4329
  const int fd = args[0].As<Int32>()->Value();
1836
1837
1443
  const int64_t pos = GetOffset(args[2]);
1838
1839
1443
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1840
1841
1443
  Local<Value> value = args[1];
1842
1443
  char* buf = nullptr;
1843
  size_t len;
1844
1845
1443
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1846
1443
  const bool is_async = req_wrap_async != nullptr;
1847
1848
  // Avoid copying the string when it is externalized but only when:
1849
  // 1. The target encoding is compatible with the string's encoding, and
1850
  // 2. The write is synchronous, otherwise the string might get neutered
1851
  //    while the request is in flight, and
1852
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1853
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1854
  // The const_casts are conceptually sound: memory is read but not written.
1855

4113
  if (!is_async && value->IsString()) {
1856
1335
    auto string = value.As<String>();
1857


1336
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1858
1
      auto ext = string->GetExternalOneByteStringResource();
1859
1
      buf = const_cast<char*>(ext->data());
1860
1
      len = ext->length();
1861


1335
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1862
2
      auto ext = string->GetExternalStringResource();
1863
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1864
1
      len = ext->length() * sizeof(*ext->data());
1865
    }
1866
  }
1867
1868
1443
  if (is_async) {  // write(fd, string, pos, enc, req)
1869
108
    CHECK_NOT_NULL(req_wrap_async);
1870
216
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1871
    FSReqBase::FSReqBuffer& stack_buffer =
1872
108
        req_wrap_async->Init("write", len, enc);
1873
    // StorageSize may return too large a char, so correct the actual length
1874
    // by the write size
1875
108
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1876
108
    stack_buffer.SetLengthAndZeroTerminate(len);
1877
108
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1878
108
    int err = req_wrap_async->Dispatch(uv_fs_write,
1879
                                       fd,
1880
                                       &uvbuf,
1881
                                       1,
1882
                                       pos,
1883
108
                                       AfterInteger);
1884
108
    if (err < 0) {
1885
      uv_fs_t* uv_req = req_wrap_async->req();
1886
      uv_req->result = err;
1887
      uv_req->path = nullptr;
1888
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1889
                             // an error
1890
    } else {
1891
108
      req_wrap_async->SetReturnValue(args);
1892
    }
1893
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1894
1335
    CHECK_EQ(argc, 6);
1895
2670
    FSReqWrapSync req_wrap_sync;
1896
2670
    FSReqBase::FSReqBuffer stack_buffer;
1897
1335
    if (buf == nullptr) {
1898
2666
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1899
        return;
1900
1333
      stack_buffer.AllocateSufficientStorage(len + 1);
1901
      // StorageSize may return too large a char, so correct the actual length
1902
      // by the write size
1903
1333
      len = StringBytes::Write(isolate, *stack_buffer,
1904
                               len, args[1], enc);
1905
1333
      stack_buffer.SetLengthAndZeroTerminate(len);
1906
1333
      buf = *stack_buffer;
1907
    }
1908
1335
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1909

1335
    FS_SYNC_TRACE_BEGIN(write);
1910
1335
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1911
1335
                                uv_fs_write, fd, &uvbuf, 1, pos);
1912

1335
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1913
4005
    args.GetReturnValue().Set(bytesWritten);
1914
  }
1915
}
1916
1917
1918
/*
1919
 * Wrapper for read(2).
1920
 *
1921
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1922
 *
1923
 * 0 fd        int32. file descriptor
1924
 * 1 buffer    instance of Buffer
1925
 * 2 offset    int64. offset to start reading into inside buffer
1926
 * 3 length    int32. length to read
1927
 * 4 position  int64. file position - -1 for current position
1928
 */
1929
50003
static void Read(const FunctionCallbackInfo<Value>& args) {
1930
50003
  Environment* env = Environment::GetCurrent(args);
1931
1932
50003
  const int argc = args.Length();
1933
50003
  CHECK_GE(argc, 5);
1934
1935
100006
  CHECK(args[0]->IsInt32());
1936
150009
  const int fd = args[0].As<Int32>()->Value();
1937
1938
50003
  CHECK(Buffer::HasInstance(args[1]));
1939
100006
  Local<Object> buffer_obj = args[1].As<Object>();
1940
50003
  char* buffer_data = Buffer::Data(buffer_obj);
1941
50003
  size_t buffer_length = Buffer::Length(buffer_obj);
1942
1943
50003
  CHECK(IsSafeJsInt(args[2]));
1944
150009
  const int64_t off_64 = args[2].As<Integer>()->Value();
1945
50003
  CHECK_GE(off_64, 0);
1946
50003
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
1947
50003
  const size_t off = static_cast<size_t>(off_64);
1948
1949
100006
  CHECK(args[3]->IsInt32());
1950
150009
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1951
50003
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1952
1953
50003
  CHECK(IsSafeJsInt(args[4]));
1954
150009
  const int64_t pos = args[4].As<Integer>()->Value();
1955
1956
50003
  char* buf = buffer_data + off;
1957
50003
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1958
1959
50003
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1960
50003
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1961
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1962
13682
              uv_fs_read, fd, &uvbuf, 1, pos);
1963
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1964
36321
    CHECK_EQ(argc, 7);
1965
72642
    FSReqWrapSync req_wrap_sync;
1966

36331
    FS_SYNC_TRACE_BEGIN(read);
1967
36321
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1968
36321
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1969

36331
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1970
108963
    args.GetReturnValue().Set(bytesRead);
1971
  }
1972
50003
}
1973
1974
1975
/* fs.chmod(path, mode);
1976
 * Wrapper for chmod(1) / EIO_CHMOD
1977
 */
1978
165
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1979
165
  Environment* env = Environment::GetCurrent(args);
1980
1981
165
  const int argc = args.Length();
1982
165
  CHECK_GE(argc, 2);
1983
1984
330
  BufferValue path(env->isolate(), args[0]);
1985
165
  CHECK_NOT_NULL(*path);
1986
1987
330
  CHECK(args[1]->IsInt32());
1988
495
  int mode = args[1].As<Int32>()->Value();
1989
1990
165
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1991
165
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1992
149
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1993
149
              uv_fs_chmod, *path, mode);
1994
  } else {  // chmod(path, mode, undefined, ctx)
1995
16
    CHECK_EQ(argc, 4);
1996
32
    FSReqWrapSync req_wrap_sync;
1997

18
    FS_SYNC_TRACE_BEGIN(chmod);
1998
16
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1999
16
             uv_fs_chmod, *path, mode);
2000

18
    FS_SYNC_TRACE_END(chmod);
2001
  }
2002
165
}
2003
2004
2005
/* fs.fchmod(fd, mode);
2006
 * Wrapper for fchmod(1) / EIO_FCHMOD
2007
 */
2008
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2009
12
  Environment* env = Environment::GetCurrent(args);
2010
2011
12
  const int argc = args.Length();
2012
12
  CHECK_GE(argc, 2);
2013
2014
24
  CHECK(args[0]->IsInt32());
2015
36
  const int fd = args[0].As<Int32>()->Value();
2016
2017
24
  CHECK(args[1]->IsInt32());
2018
36
  const int mode = args[1].As<Int32>()->Value();
2019
2020
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2021
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2022
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2023
7
              uv_fs_fchmod, fd, mode);
2024
  } else {  // fchmod(fd, mode, undefined, ctx)
2025
5
    CHECK_EQ(argc, 4);
2026
10
    FSReqWrapSync req_wrap_sync;
2027

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2028
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2029
5
             uv_fs_fchmod, fd, mode);
2030

7
    FS_SYNC_TRACE_END(fchmod);
2031
  }
2032
12
}
2033
2034
2035
/* fs.chown(path, uid, gid);
2036
 * Wrapper for chown(1) / EIO_CHOWN
2037
 */
2038
73
static void Chown(const FunctionCallbackInfo<Value>& args) {
2039
73
  Environment* env = Environment::GetCurrent(args);
2040
2041
73
  const int argc = args.Length();
2042
73
  CHECK_GE(argc, 3);
2043
2044
146
  BufferValue path(env->isolate(), args[0]);
2045
73
  CHECK_NOT_NULL(*path);
2046
2047
146
  CHECK(args[1]->IsUint32());
2048
219
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2049
2050
146
  CHECK(args[2]->IsUint32());
2051
219
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2052
2053
73
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2054
73
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2055
70
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2056
70
              uv_fs_chown, *path, uid, gid);
2057
  } else {  // chown(path, uid, gid, undefined, ctx)
2058
3
    CHECK_EQ(argc, 5);
2059
6
    FSReqWrapSync req_wrap_sync;
2060

5
    FS_SYNC_TRACE_BEGIN(chown);
2061
3
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2062
3
             uv_fs_chown, *path, uid, gid);
2063

5
    FS_SYNC_TRACE_END(chown);
2064
  }
2065
73
}
2066
2067
2068
/* fs.fchown(fd, uid, gid);
2069
 * Wrapper for fchown(1) / EIO_FCHOWN
2070
 */
2071
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2072
4
  Environment* env = Environment::GetCurrent(args);
2073
2074
4
  const int argc = args.Length();
2075
4
  CHECK_GE(argc, 3);
2076
2077
8
  CHECK(args[0]->IsInt32());
2078
12
  const int fd = args[0].As<Int32>()->Value();
2079
2080
8
  CHECK(args[1]->IsUint32());
2081
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2082
2083
8
  CHECK(args[2]->IsUint32());
2084
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2085
2086
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2087
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2088
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2089
2
              uv_fs_fchown, fd, uid, gid);
2090
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2091
2
    CHECK_EQ(argc, 5);
2092
4
    FSReqWrapSync req_wrap_sync;
2093

4
    FS_SYNC_TRACE_BEGIN(fchown);
2094
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2095
2
             uv_fs_fchown, fd, uid, gid);
2096

4
    FS_SYNC_TRACE_END(fchown);
2097
  }
2098
4
}
2099
2100
2101
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2102
9
  Environment* env = Environment::GetCurrent(args);
2103
2104
9
  const int argc = args.Length();
2105
9
  CHECK_GE(argc, 3);
2106
2107
18
  BufferValue path(env->isolate(), args[0]);
2108
9
  CHECK_NOT_NULL(*path);
2109
2110
18
  CHECK(args[1]->IsUint32());
2111
27
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2112
2113
18
  CHECK(args[2]->IsUint32());
2114
27
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2115
2116
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2117
9
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2118
7
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2119
7
              uv_fs_lchown, *path, uid, gid);
2120
  } else {  // lchown(path, uid, gid, undefined, ctx)
2121
2
    CHECK_EQ(argc, 5);
2122
4
    FSReqWrapSync req_wrap_sync;
2123

4
    FS_SYNC_TRACE_BEGIN(lchown);
2124
2
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2125
2
             uv_fs_lchown, *path, uid, gid);
2126

4
    FS_SYNC_TRACE_END(lchown);
2127
  }
2128
9
}
2129
2130
2131
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2132
29
  Environment* env = Environment::GetCurrent(args);
2133
2134
29
  const int argc = args.Length();
2135
29
  CHECK_GE(argc, 3);
2136
2137
58
  BufferValue path(env->isolate(), args[0]);
2138
29
  CHECK_NOT_NULL(*path);
2139
2140
58
  CHECK(args[1]->IsNumber());
2141
87
  const double atime = args[1].As<Number>()->Value();
2142
2143
58
  CHECK(args[2]->IsNumber());
2144
87
  const double mtime = args[2].As<Number>()->Value();
2145
2146
29
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2147
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2148
14
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2149
14
              uv_fs_utime, *path, atime, mtime);
2150
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2151
15
    CHECK_EQ(argc, 5);
2152
30
    FSReqWrapSync req_wrap_sync;
2153

17
    FS_SYNC_TRACE_BEGIN(utimes);
2154
15
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2155
15
             uv_fs_utime, *path, atime, mtime);
2156

17
    FS_SYNC_TRACE_END(utimes);
2157
  }
2158
29
}
2159
2160
1267
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2161
1267
  Environment* env = Environment::GetCurrent(args);
2162
2163
1267
  const int argc = args.Length();
2164
1267
  CHECK_GE(argc, 3);
2165
2166
2534
  CHECK(args[0]->IsInt32());
2167
3801
  const int fd = args[0].As<Int32>()->Value();
2168
2169
2534
  CHECK(args[1]->IsNumber());
2170
3801
  const double atime = args[1].As<Number>()->Value();
2171
2172
2534
  CHECK(args[2]->IsNumber());
2173
3801
  const double mtime = args[2].As<Number>()->Value();
2174
2175
1267
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2176
1267
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2177
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2178
1259
              uv_fs_futime, fd, atime, mtime);
2179
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2180
8
    CHECK_EQ(argc, 5);
2181
16
    FSReqWrapSync req_wrap_sync;
2182

10
    FS_SYNC_TRACE_BEGIN(futimes);
2183
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2184
8
             uv_fs_futime, fd, atime, mtime);
2185

10
    FS_SYNC_TRACE_END(futimes);
2186
  }
2187
1267
}
2188
2189
14
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2190
14
  Environment* env = Environment::GetCurrent(args);
2191
14
  Isolate* isolate = env->isolate();
2192
2193
14
  const int argc = args.Length();
2194
14
  CHECK_GE(argc, 2);
2195
2196
28
  BufferValue tmpl(isolate, args[0]);
2197
14
  CHECK_NOT_NULL(*tmpl);
2198
2199
14
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2200
2201
14
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2202
14
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2203
6
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2204
6
              uv_fs_mkdtemp, *tmpl);
2205
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2206
8
    CHECK_EQ(argc, 4);
2207
16
    FSReqWrapSync req_wrap_sync;
2208

10
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2209
8
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2210
8
             uv_fs_mkdtemp, *tmpl);
2211

10
    FS_SYNC_TRACE_END(mkdtemp);
2212
8
    const char* path = req_wrap_sync.req.path;
2213
2214
    Local<Value> error;
2215
    MaybeLocal<Value> rc =
2216
8
        StringBytes::Encode(isolate, path, encoding, &error);
2217
8
    if (rc.IsEmpty()) {
2218
      Local<Object> ctx = args[3].As<Object>();
2219
      ctx->Set(env->context(), env->error_string(), error).Check();
2220
      return;
2221
    }
2222
16
    args.GetReturnValue().Set(rc.ToLocalChecked());
2223
  }
2224
}
2225
2226
4377
void Initialize(Local<Object> target,
2227
                Local<Value> unused,
2228
                Local<Context> context,
2229
                void* priv) {
2230
4377
  Environment* env = Environment::GetCurrent(context);
2231
4377
  Isolate* isolate = env->isolate();
2232
2233
4377
  env->SetMethod(target, "access", Access);
2234
4377
  env->SetMethod(target, "close", Close);
2235
4377
  env->SetMethod(target, "open", Open);
2236
4377
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2237
4377
  env->SetMethod(target, "read", Read);
2238
4377
  env->SetMethod(target, "fdatasync", Fdatasync);
2239
4377
  env->SetMethod(target, "fsync", Fsync);
2240
4377
  env->SetMethod(target, "rename", Rename);
2241
4377
  env->SetMethod(target, "ftruncate", FTruncate);
2242
4377
  env->SetMethod(target, "rmdir", RMDir);
2243
4377
  env->SetMethod(target, "mkdir", MKDir);
2244
4377
  env->SetMethod(target, "readdir", ReadDir);
2245
4377
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2246
4377
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2247
4377
  env->SetMethod(target, "stat", Stat);
2248
4377
  env->SetMethod(target, "lstat", LStat);
2249
4377
  env->SetMethod(target, "fstat", FStat);
2250
4377
  env->SetMethod(target, "link", Link);
2251
4377
  env->SetMethod(target, "symlink", Symlink);
2252
4377
  env->SetMethod(target, "readlink", ReadLink);
2253
4377
  env->SetMethod(target, "unlink", Unlink);
2254
4377
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2255
4377
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2256
4377
  env->SetMethod(target, "writeString", WriteString);
2257
4377
  env->SetMethod(target, "realpath", RealPath);
2258
4377
  env->SetMethod(target, "copyFile", CopyFile);
2259
2260
4377
  env->SetMethod(target, "chmod", Chmod);
2261
4377
  env->SetMethod(target, "fchmod", FChmod);
2262
  // env->SetMethod(target, "lchmod", LChmod);
2263
2264
4377
  env->SetMethod(target, "chown", Chown);
2265
4377
  env->SetMethod(target, "fchown", FChown);
2266
4377
  env->SetMethod(target, "lchown", LChown);
2267
2268
4377
  env->SetMethod(target, "utimes", UTimes);
2269
4377
  env->SetMethod(target, "futimes", FUTimes);
2270
2271
4377
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2272
2273
  target
2274
8754
      ->Set(context,
2275
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2276
            Integer::New(
2277
                isolate,
2278
17508
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2279
      .Check();
2280
2281
8754
  target->Set(context,
2282
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2283
17508
              env->fs_stats_field_array()->GetJSArray()).Check();
2284
2285
8754
  target->Set(context,
2286
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2287
17508
              env->fs_stats_field_bigint_array()->GetJSArray()).Check();
2288
2289
4377
  StatWatcher::Initialize(env, target);
2290
2291
  // Create FunctionTemplate for FSReqCallback
2292
4377
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2293
8754
  fst->InstanceTemplate()->SetInternalFieldCount(1);
2294
8754
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2295
  Local<String> wrapString =
2296
4377
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2297
4377
  fst->SetClassName(wrapString);
2298
  target
2299
8754
      ->Set(context, wrapString,
2300
17508
            fst->GetFunction(env->context()).ToLocalChecked())
2301
      .Check();
2302
2303
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2304
  // to do anything in the constructor, so we only store the instance template.
2305
4377
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2306
8754
  fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2307
8754
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2308
  Local<String> fhWrapString =
2309
4377
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2310
4377
  fh_rw->SetClassName(fhWrapString);
2311
4377
  env->set_filehandlereadwrap_template(
2312
4377
      fst->InstanceTemplate());
2313
2314
  // Create Function Template for FSReqPromise
2315
4377
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2316
8754
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2317
  Local<String> promiseString =
2318
4377
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2319
4377
  fpt->SetClassName(promiseString);
2320
4377
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2321
4377
  fpo->SetInternalFieldCount(1);
2322
4377
  env->set_fsreqpromise_constructor_template(fpo);
2323
2324
  // Create FunctionTemplate for FileHandle
2325
4377
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2326
8754
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2327
4377
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2328
4377
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2329
4377
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2330
4377
  fdt->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
2331
  Local<String> handleString =
2332
4377
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2333
4377
  fd->SetClassName(handleString);
2334
4377
  StreamBase::AddMethods(env, fd);
2335
  target
2336
8754
      ->Set(context, handleString,
2337
17508
            fd->GetFunction(env->context()).ToLocalChecked())
2338
      .Check();
2339
4377
  env->set_fd_constructor_template(fdt);
2340
2341
  // Create FunctionTemplate for FileHandle::CloseReq
2342
4377
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2343
8754
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2344
4377
                        "FileHandleCloseReq"));
2345
8754
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2346
4377
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2347
4377
  fdcloset->SetInternalFieldCount(1);
2348
4377
  env->set_fdclose_constructor_template(fdcloset);
2349
2350
  Local<Symbol> use_promises_symbol =
2351
    Symbol::New(isolate,
2352
4377
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2353
4377
  env->set_fs_use_promises_symbol(use_promises_symbol);
2354
8754
  target->Set(context,
2355
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2356
13131
              use_promises_symbol).Check();
2357
4377
}
2358
2359
}  // namespace fs
2360
2361
}  // end namespace node
2362
2363

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