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: 1233 1312 94.0 %
Date: 2019-08-17 22:35:23 Branches: 799 1208 66.1 %

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
22
#include "node_file.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::BigUint64Array;
56
using v8::Context;
57
using v8::DontDelete;
58
using v8::EscapableHandleScope;
59
using v8::Float64Array;
60
using v8::Function;
61
using v8::FunctionCallbackInfo;
62
using v8::FunctionTemplate;
63
using v8::HandleScope;
64
using v8::Int32;
65
using v8::Integer;
66
using v8::Isolate;
67
using v8::Local;
68
using v8::MaybeLocal;
69
using v8::Number;
70
using v8::Object;
71
using v8::ObjectTemplate;
72
using v8::Promise;
73
using v8::PropertyAttribute;
74
using v8::ReadOnly;
75
using v8::String;
76
using v8::Symbol;
77
using v8::Uint32;
78
using v8::Undefined;
79
using v8::Value;
80
81
#ifndef S_ISDIR
82
# define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
83
#endif
84
85
#ifdef __POSIX__
86
constexpr char kPathSeparator = '/';
87
#else
88
const char* const kPathSeparator = "\\/";
89
#endif
90
91
#define GET_OFFSET(a) (IsSafeJsInt(a) ? (a).As<Integer>()->Value() : -1)
92
#define TRACE_NAME(name) "fs.sync." #name
93
#define GET_TRACE_ENABLED                                                  \
94
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
95
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
96
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
97
  if (GET_TRACE_ENABLED)                                                   \
98
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
99
  ##__VA_ARGS__);
100
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
101
  if (GET_TRACE_ENABLED)                                                   \
102
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
103
  ##__VA_ARGS__);
104
105
// We sometimes need to convert a C++ lambda function to a raw C-style function.
106
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
107
// functions, and thus does not wrap them properly.
108
typedef void(*uv_fs_callback_t)(uv_fs_t*);
109
110
// The FileHandle object wraps a file descriptor and will close it on garbage
111
// collection if necessary. If that happens, a process warning will be
112
// emitted (or a fatal exception will occur if the fd cannot be closed.)
113
79
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
114
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
115
      StreamBase(env),
116
79
      fd_(fd) {
117
79
  MakeWeak();
118
79
  StreamBase::AttachToObject(GetObject());
119
79
}
120
121
79
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
122

380
  if (obj.IsEmpty() && !env->fd_constructor_template()
123
271
                            ->NewInstance(env->context())
124
271
                            .ToLocal(&obj)) {
125
    return nullptr;
126
  }
127
  PropertyAttribute attr =
128
79
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
129
158
  if (obj->DefineOwnProperty(env->context(),
130
                             env->fd_string(),
131
                             Integer::New(env->isolate(), fd),
132
395
                             attr)
133
158
          .IsNothing()) {
134
    return nullptr;
135
  }
136
79
  return new FileHandle(env, obj, fd);
137
}
138
139
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
140
15
  Environment* env = Environment::GetCurrent(args);
141
15
  CHECK(args.IsConstructCall());
142
30
  CHECK(args[0]->IsInt32());
143
144
  FileHandle* handle =
145
45
      FileHandle::New(env, args[0].As<Int32>()->Value(), args.This());
146
30
  if (handle == nullptr) return;
147
30
  if (args[1]->IsNumber())
148
60
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
149
30
  if (args[2]->IsNumber())
150
60
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
151
}
152
153
237
FileHandle::~FileHandle() {
154
79
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
155
79
  Close();           // Close synchronously and emit warning
156
79
  CHECK(closed_);    // We have to be closed at the point
157
158
}
158
159
160
// Close the file descriptor if it hasn't already been closed. A process
161
// warning will be emitted using a SetImmediate to avoid calling back to
162
// JS during GC. If closing the fd fails at this point, a fatal exception
163
// will crash the process immediately.
164
79
inline void FileHandle::Close() {
165
151
  if (closed_) return;
166
  uv_fs_t req;
167
7
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
168
7
  uv_fs_req_cleanup(&req);
169
7
  AfterClose();
170
171
  struct err_detail { int ret; int fd; };
172
173
7
  err_detail detail { ret, fd_ };
174
175
7
  if (ret < 0) {
176
    // Do not unref this
177
    env()->SetImmediate([detail](Environment* env) {
178
      char msg[70];
179
      snprintf(msg, arraysize(msg),
180
              "Closing file descriptor %d on garbage collection failed",
181
              detail.fd);
182
      // This exception will end up being fatal for the process because
183
      // it is being thrown from within the SetImmediate handler and
184
      // there is no JS stack to bubble it to. In other words, tearing
185
      // down the process is the only reasonable thing we can do here.
186
      HandleScope handle_scope(env->isolate());
187
      env->ThrowUVException(detail.ret, "close", msg);
188
    });
189
    return;
190
  }
191
192
  // If the close was successful, we still want to emit a process warning
193
  // to notify that the file descriptor was gc'd. We want to be noisy about
194
  // this because not explicitly closing the FileHandle is a bug.
195
1
  env()->SetUnrefImmediate([detail](Environment* env) {
196
    ProcessEmitWarning(env,
197
                       "Closing file descriptor %d on garbage collection",
198
1
                       detail.fd);
199
8
  });
200
}
201
202
65
void FileHandle::CloseReq::Resolve() {
203
65
  Isolate* isolate = env()->isolate();
204
65
  HandleScope scope(isolate);
205
130
  InternalCallbackScope callback_scope(this);
206
130
  Local<Promise> promise = promise_.Get(isolate);
207
65
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
208
260
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
209
65
}
210
211
void FileHandle::CloseReq::Reject(Local<Value> reason) {
212
  Isolate* isolate = env()->isolate();
213
  HandleScope scope(isolate);
214
  InternalCallbackScope callback_scope(this);
215
  Local<Promise> promise = promise_.Get(isolate);
216
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
217
  resolver->Reject(env()->context(), reason).Check();
218
}
219
220
65
FileHandle* FileHandle::CloseReq::file_handle() {
221
65
  Isolate* isolate = env()->isolate();
222
65
  HandleScope scope(isolate);
223
130
  Local<Value> val = ref_.Get(isolate);
224
65
  Local<Object> obj = val.As<Object>();
225
65
  return Unwrap<FileHandle>(obj);
226
}
227
228
// Closes this FileHandle asynchronously and returns a Promise that will be
229
// resolved when the callback is invoked, or rejects with a UVException if
230
// there was a problem closing the fd. This is the preferred mechanism for
231
// closing the FD object even tho the object will attempt to close
232
// automatically on gc.
233
65
inline MaybeLocal<Promise> FileHandle::ClosePromise() {
234
65
  Isolate* isolate = env()->isolate();
235
65
  EscapableHandleScope scope(isolate);
236
65
  Local<Context> context = env()->context();
237
65
  auto maybe_resolver = Promise::Resolver::New(context);
238
65
  CHECK(!maybe_resolver.IsEmpty());
239
65
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
240
65
  Local<Promise> promise = resolver.As<Promise>();
241
65
  CHECK(!reading_);
242

65
  if (!closed_ && !closing_) {
243
65
    closing_ = true;
244
    Local<Object> close_req_obj;
245
130
    if (!env()
246
65
             ->fdclose_constructor_template()
247
260
             ->NewInstance(env()->context())
248
195
             .ToLocal(&close_req_obj)) {
249
      return MaybeLocal<Promise>();
250
    }
251
130
    CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
252
195
    auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
253
65
      std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
254
65
      CHECK_NOT_NULL(close);
255
65
      close->file_handle()->AfterClose();
256
65
      Isolate* isolate = close->env()->isolate();
257
65
      if (req->result < 0) {
258
        close->Reject(UVException(isolate, req->result, "close"));
259
      } else {
260
65
        close->Resolve();
261
      }
262
260
    }};
263
65
    int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
264
65
    if (ret < 0) {
265
      req->Reject(UVException(isolate, ret, "close"));
266
      delete req;
267
65
    }
268
  } else {
269
    // Already closed. Just reject the promise immediately
270
    resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
271
        .Check();
272
  }
273
65
  return scope.Escape(promise);
274
}
275
276
65
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
277
  FileHandle* fd;
278
65
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
279
  Local<Promise> ret;
280
130
  if (!fd->ClosePromise().ToLocal(&ret)) return;
281
130
  args.GetReturnValue().Set(ret);
282
}
283
284
285
7
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
286
  FileHandle* fd;
287
14
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
288
  // Just act as if this FileHandle has been closed.
289
7
  fd->AfterClose();
290
}
291
292
293
79
void FileHandle::AfterClose() {
294
79
  closing_ = false;
295
79
  closed_ = true;
296

79
  if (reading_ && !persistent().IsEmpty())
297
    EmitRead(UV_EOF);
298
79
}
299
300
2
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
301
2
  tracker->TrackField("buffer", buffer_);
302
2
  tracker->TrackField("file_handle", this->file_handle_);
303
2
}
304
305
15
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
306
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
307
15
    file_handle_(handle) {}
308
309
227
int FileHandle::ReadStart() {
310

227
  if (!IsAlive() || IsClosing())
311
    return UV_EOF;
312
313
227
  reading_ = true;
314
315
227
  if (current_read_)
316
    return 0;
317
318
227
  std::unique_ptr<FileHandleReadWrap> read_wrap;
319
320
227
  if (read_length_ == 0) {
321
6
    EmitRead(UV_EOF);
322
6
    return 0;
323
  }
324
325
  {
326
    // Create a new FileHandleReadWrap or re-use one.
327
    // Either way, we need these two scopes for AsyncReset() or otherwise
328
    // for creating the new instance.
329
221
    HandleScope handle_scope(env()->isolate());
330
442
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
331
332
221
    auto& freelist = env()->file_handle_read_wrap_freelist();
333
221
    if (freelist.size() > 0) {
334
206
      read_wrap = std::move(freelist.back());
335
206
      freelist.pop_back();
336
206
      read_wrap->AsyncReset();
337
206
      read_wrap->file_handle_ = this;
338
    } else {
339
      Local<Object> wrap_obj;
340
30
      if (!env()
341
15
               ->filehandlereadwrap_template()
342
60
               ->NewInstance(env()->context())
343
45
               .ToLocal(&wrap_obj)) {
344
        return UV_EBUSY;
345
      }
346
15
      read_wrap = std::make_unique<FileHandleReadWrap>(this, wrap_obj);
347
221
    }
348
  }
349
221
  int64_t recommended_read = 65536;
350

221
  if (read_length_ >= 0 && read_length_ <= recommended_read)
351
10
    recommended_read = read_length_;
352
353
221
  read_wrap->buffer_ = EmitAlloc(recommended_read);
354
355
221
  current_read_ = std::move(read_wrap);
356
357
221
  current_read_->Dispatch(uv_fs_read,
358
                          fd_,
359
221
                          &current_read_->buffer_,
360
                          1,
361
                          read_offset_,
362
663
                          uv_fs_callback_t{[](uv_fs_t* req) {
363
    FileHandle* handle;
364
    {
365
221
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
366
221
      handle = req_wrap->file_handle_;
367
221
      CHECK_EQ(handle->current_read_.get(), req_wrap);
368
    }
369
370
    // ReadStart() checks whether current_read_ is set to determine whether
371
    // a read is in progress. Moving it into a local variable makes sure that
372
    // the ReadStart() call below doesn't think we're still actively reading.
373
    std::unique_ptr<FileHandleReadWrap> read_wrap =
374
221
        std::move(handle->current_read_);
375
376
221
    int result = req->result;
377
221
    uv_buf_t buffer = read_wrap->buffer_;
378
379
221
    uv_fs_req_cleanup(req);
380
381
    // Push the read wrap back to the freelist, or let it be destroyed
382
    // once we’re exiting the current scope.
383
221
    constexpr size_t wanted_freelist_fill = 100;
384
221
    auto& freelist = handle->env()->file_handle_read_wrap_freelist();
385
221
    if (freelist.size() < wanted_freelist_fill) {
386
221
      read_wrap->Reset();
387
221
      freelist.emplace_back(std::move(read_wrap));
388
    }
389
390
221
    if (result >= 0) {
391
      // Read at most as many bytes as we originally planned to.
392

220
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
393
        result = handle->read_length_;
394
395
      // If we read data and we have an expected length, decrease it by
396
      // how much we have read.
397
220
      if (handle->read_length_ >= 0)
398
16
        handle->read_length_ -= result;
399
400
      // If we have an offset, increase it by how much we have read.
401
220
      if (handle->read_offset_ >= 0)
402
218
        handle->read_offset_ += result;
403
    }
404
405
    // Reading 0 bytes from a file always means EOF, or that we reached
406
    // the end of the requested range.
407
221
    if (result == 0)
408
6
      result = UV_EOF;
409
410
221
    handle->EmitRead(result, buffer);
411
412
    // Start over, if EmitRead() didn’t tell us to stop.
413
221
    if (handle->reading_)
414
      handle->ReadStart();
415
1326
  }});
416
417
221
  return 0;
418
}
419
420
242
int FileHandle::ReadStop() {
421
242
  reading_ = false;
422
242
  return 0;
423
}
424
425
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
426
427
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
428
  return new FileHandleCloseWrap(this, object);
429
}
430
431
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
432
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
433
  closing_ = true;
434
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
435
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
436
        FileHandleCloseWrap::from_req(req));
437
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
438
    handle->AfterClose();
439
440
    int result = req->result;
441
    uv_fs_req_cleanup(req);
442
    wrap->Done(result);
443
  }});
444
445
  return 0;
446
}
447
448
449
4594
void FSReqCallback::Reject(Local<Value> reject) {
450
4594
  MakeCallback(env()->oncomplete_string(), 1, &reject);
451
4594
}
452
453
5662
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
454
5662
  Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
455
5662
}
456
457
54248
void FSReqCallback::Resolve(Local<Value> value) {
458
  Local<Value> argv[2] {
459
    Null(env()->isolate()),
460
    value
461
108496
  };
462
  MakeCallback(env()->oncomplete_string(),
463
152298
               value->IsUndefined() ? 1 : arraysize(argv),
464
98050
               argv);
465
54240
}
466
467
58842
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
468
117684
  args.GetReturnValue().SetUndefined();
469
58842
}
470
471
58862
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
472
58862
  CHECK(args.IsConstructCall());
473
58862
  Environment* env = Environment::GetCurrent(args);
474
176586
  new FSReqCallback(env, args.This(), args[0]->IsTrue());
475
58862
}
476
477
59194
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
478
    : wrap_(wrap),
479
      req_(req),
480
      handle_scope_(wrap->env()->isolate()),
481
59194
      context_scope_(wrap->env()->context()) {
482
59194
  CHECK_EQ(wrap_->req(), req);
483
59194
}
484
485
177558
FSReqAfterScope::~FSReqAfterScope() {
486
59186
  uv_fs_req_cleanup(wrap_->req());
487
59186
  delete wrap_;
488
59186
}
489
490
// TODO(joyeecheung): create a normal context object, and
491
// construct the actual errors in the JS land using the context.
492
// The context should include fds for some fs APIs, currently they are
493
// missing in the error messages. The path, dest, syscall, fd, .etc
494
// can be put into the context before the binding is even invoked,
495
// the only information that has to come from the C++ layer is the
496
// error number (and possibly the syscall for abstraction),
497
// which is also why the errors should have been constructed
498
// in JS for more flexibility.
499
4613
void FSReqAfterScope::Reject(uv_fs_t* req) {
500
  wrap_->Reject(UVException(wrap_->env()->isolate(),
501
                            req->result,
502
                            wrap_->syscall(),
503
                            nullptr,
504
                            req->path,
505
4613
                            wrap_->data()));
506
4613
}
507
508
59194
bool FSReqAfterScope::Proceed() {
509
59194
  if (req_->result < 0) {
510
4613
    Reject(req_);
511
4613
    return false;
512
  }
513
54581
  return true;
514
}
515
516
11231
void AfterNoArgs(uv_fs_t* req) {
517
11231
  FSReqBase* req_wrap = FSReqBase::from_req(req);
518
11231
  FSReqAfterScope after(req_wrap, req);
519
520
11231
  if (after.Proceed())
521
21000
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
522
11224
}
523
524
9419
void AfterStat(uv_fs_t* req) {
525
9419
  FSReqBase* req_wrap = FSReqBase::from_req(req);
526
9419
  FSReqAfterScope after(req_wrap, req);
527
528
9419
  if (after.Proceed()) {
529
5790
    req_wrap->ResolveStat(&req->statbuf);
530
9419
  }
531
9419
}
532
533
38268
void AfterInteger(uv_fs_t* req) {
534
38268
  FSReqBase* req_wrap = FSReqBase::from_req(req);
535
38268
  FSReqAfterScope after(req_wrap, req);
536
537
38268
  if (after.Proceed())
538
76070
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
539
38268
}
540
541
63
void AfterOpenFileHandle(uv_fs_t* req) {
542
63
  FSReqBase* req_wrap = FSReqBase::from_req(req);
543
63
  FSReqAfterScope after(req_wrap, req);
544
545
63
  if (after.Proceed()) {
546
63
    FileHandle* fd = FileHandle::New(req_wrap->env(), req->result);
547
126
    if (fd == nullptr) return;
548
126
    req_wrap->Resolve(fd->object());
549
63
  }
550
}
551
552
6
void AfterStringPath(uv_fs_t* req) {
553
6
  FSReqBase* req_wrap = FSReqBase::from_req(req);
554
6
  FSReqAfterScope after(req_wrap, req);
555
556
  MaybeLocal<Value> link;
557
  Local<Value> error;
558
559
6
  if (after.Proceed()) {
560
    link = StringBytes::Encode(req_wrap->env()->isolate(),
561
                               req->path,
562
                               req_wrap->encoding(),
563
5
                               &error);
564
5
    if (link.IsEmpty())
565
      req_wrap->Reject(error);
566
    else
567
10
      req_wrap->Resolve(link.ToLocalChecked());
568
6
  }
569
6
}
570
571
65
void AfterStringPtr(uv_fs_t* req) {
572
65
  FSReqBase* req_wrap = FSReqBase::from_req(req);
573
65
  FSReqAfterScope after(req_wrap, req);
574
575
  MaybeLocal<Value> link;
576
  Local<Value> error;
577
578
65
  if (after.Proceed()) {
579
    link = StringBytes::Encode(req_wrap->env()->isolate(),
580
                               static_cast<const char*>(req->ptr),
581
                               req_wrap->encoding(),
582
50
                               &error);
583
50
    if (link.IsEmpty())
584
      req_wrap->Reject(error);
585
    else
586
100
      req_wrap->Resolve(link.ToLocalChecked());
587
64
  }
588
64
}
589
590
135
void AfterScanDir(uv_fs_t* req) {
591
135
  FSReqBase* req_wrap = FSReqBase::from_req(req);
592
135
  FSReqAfterScope after(req_wrap, req);
593
594
135
  if (!after.Proceed()) {
595
3
    return;
596
  }
597
132
  Environment* env = req_wrap->env();
598
  Local<Value> error;
599
  int r;
600
264
  std::vector<Local<Value>> name_v;
601
602
5912
  for (int i = 0; ; i++) {
603
    uv_dirent_t ent;
604
605
5912
    r = uv_fs_scandir_next(req, &ent);
606
5912
    if (r == UV_EOF)
607
132
      break;
608
5780
    if (r != 0) {
609
      return req_wrap->Reject(UVException(
610
          env->isolate(), r, nullptr, req_wrap->syscall(), req->path));
611
    }
612
613
    MaybeLocal<Value> filename =
614
      StringBytes::Encode(env->isolate(),
615
          ent.name,
616
          req_wrap->encoding(),
617
5780
          &error);
618
5780
    if (filename.IsEmpty())
619
      return req_wrap->Reject(error);
620
621
5780
    name_v.push_back(filename.ToLocalChecked());
622
5780
  }
623
624
396
  req_wrap->Resolve(Array::New(env->isolate(), name_v.data(), name_v.size()));
625
}
626
627
7
void AfterScanDirWithTypes(uv_fs_t* req) {
628
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
629
7
  FSReqAfterScope after(req_wrap, req);
630
631
7
  if (!after.Proceed()) {
632
1
    return;
633
  }
634
635
6
  Environment* env = req_wrap->env();
636
6
  Isolate* isolate = env->isolate();
637
  Local<Value> error;
638
  int r;
639
640
12
  std::vector<Local<Value>> name_v;
641
12
  std::vector<Local<Value>> type_v;
642
643
22
  for (int i = 0; ; i++) {
644
    uv_dirent_t ent;
645
646
22
    r = uv_fs_scandir_next(req, &ent);
647
22
    if (r == UV_EOF)
648
6
      break;
649
16
    if (r != 0) {
650
      return req_wrap->Reject(
651
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
652
    }
653
654
    MaybeLocal<Value> filename =
655
      StringBytes::Encode(isolate,
656
          ent.name,
657
          req_wrap->encoding(),
658
16
          &error);
659
16
    if (filename.IsEmpty())
660
      return req_wrap->Reject(error);
661
662
16
    name_v.push_back(filename.ToLocalChecked());
663
16
    type_v.emplace_back(Integer::New(isolate, ent.type));
664
16
  }
665
666
6
  Local<Array> result = Array::New(isolate, 2);
667
6
  result->Set(env->context(),
668
              0,
669
              Array::New(isolate, name_v.data(),
670
24
              name_v.size())).Check();
671
6
  result->Set(env->context(),
672
              1,
673
              Array::New(isolate, type_v.data(),
674
24
              type_v.size())).Check();
675
18
  req_wrap->Resolve(result);
676
}
677
678
679
// This class is only used on sync fs calls.
680
// For async calls FSReqCallback is used.
681
class FSReqWrapSync {
682
 public:
683
531726
  FSReqWrapSync() = default;
684
531726
  ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
685
  uv_fs_t req;
686
687
  FSReqWrapSync(const FSReqWrapSync&) = delete;
688
  FSReqWrapSync& operator=(const FSReqWrapSync&) = delete;
689
};
690
691
// Returns nullptr if the operation fails from the start.
692
template <typename Func, typename... Args>
693
59061
inline FSReqBase* AsyncDestCall(Environment* env,
694
    FSReqBase* req_wrap,
695
    const FunctionCallbackInfo<Value>& args,
696
    const char* syscall, const char* dest, size_t len,
697
    enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
698







59061
  CHECK_NOT_NULL(req_wrap);
699
59061
  req_wrap->Init(syscall, dest, len, enc);
700
59061
  int err = req_wrap->Dispatch(fn, fn_args..., after);
701







59061
  if (err < 0) {
702
1
    uv_fs_t* uv_req = req_wrap->req();
703
1
    uv_req->result = err;
704
1
    uv_req->path = nullptr;
705
1
    after(uv_req);  // after may delete req_wrap if there is an error
706
1
    req_wrap = nullptr;
707
  } else {
708
59060
    req_wrap->SetReturnValue(args);
709
  }
710
711
59061
  return req_wrap;
712
}
713
714
// Returns nullptr if the operation fails from the start.
715
template <typename Func, typename... Args>
716
58724
inline FSReqBase* AsyncCall(Environment* env,
717
    FSReqBase* req_wrap,
718
    const FunctionCallbackInfo<Value>& args,
719
    const char* syscall, enum encoding enc,
720
    uv_fs_cb after, Func fn, Args... fn_args) {
721
  return AsyncDestCall(env, req_wrap, args,
722
                       syscall, nullptr, 0, enc,
723
58724
                       after, fn, fn_args...);
724
}
725
726
// Template counterpart of SYNC_CALL, except that it only puts
727
// the error number and the syscall in the context instead of
728
// creating an error in the C++ land.
729
// ctx must be checked using value->IsObject() before being passed.
730
template <typename Func, typename... Args>
731
531726
inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap,
732
    const char* syscall, Func fn, Args... args) {
733
531726
  env->PrintSyncTrace();
734
531726
  int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
735







531726
  if (err < 0) {
736
8166
    Local<Context> context = env->context();
737
8166
    Local<Object> ctx_obj = ctx.As<Object>();
738
8166
    Isolate* isolate = env->isolate();
739
    ctx_obj->Set(context,
740
             env->errno_string(),
741
32664
             Integer::New(isolate, err)).Check();
742
    ctx_obj->Set(context,
743
             env->syscall_string(),
744
32664
             OneByteString(isolate, syscall)).Check();
745
  }
746
531726
  return err;
747
}
748
749
// TODO(addaleax): Currently, callers check the return value and assume
750
// that nullptr indicates a synchronous call, rather than a failure.
751
// Failure conditions should be disambiguated and handled appropriately.
752
590921
inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
753
                             bool use_bigint = false) {
754
590921
  if (value->IsObject()) {
755
58843
    return Unwrap<FSReqBase>(value.As<Object>());
756
1064156
  } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
757
352
    if (use_bigint) {
758
3
      return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
759
    } else {
760
349
      return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
761
    }
762
  }
763
531726
  return nullptr;
764
}
765
766
7133
void Access(const FunctionCallbackInfo<Value>& args) {
767
7133
  Environment* env = Environment::GetCurrent(args);
768
7133
  Isolate* isolate = env->isolate();
769
7133
  HandleScope scope(isolate);
770
771
7133
  const int argc = args.Length();
772
7133
  CHECK_GE(argc, 2);
773
774
14266
  CHECK(args[1]->IsInt32());
775
21399
  int mode = args[1].As<Int32>()->Value();
776
777
14266
  BufferValue path(isolate, args[0]);
778
7133
  CHECK_NOT_NULL(*path);
779
780
7133
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
781
7133
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
782
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
783
60
              uv_fs_access, *path, mode);
784
  } else {  // access(path, mode, undefined, ctx)
785
7073
    CHECK_EQ(argc, 4);
786
7073
    FSReqWrapSync req_wrap_sync;
787

7075
    FS_SYNC_TRACE_BEGIN(access);
788
14146
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
789

7075
    FS_SYNC_TRACE_END(access);
790
7133
  }
791
7133
}
792
793
794
61667
void Close(const FunctionCallbackInfo<Value>& args) {
795
61667
  Environment* env = Environment::GetCurrent(args);
796
797
61667
  const int argc = args.Length();
798
61667
  CHECK_GE(argc, 2);
799
800
123334
  CHECK(args[0]->IsInt32());
801
185001
  int fd = args[0].As<Int32>()->Value();
802
803
61667
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
804
61667
  if (req_wrap_async != nullptr) {  // close(fd, req)
805
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
806
7455
              uv_fs_close, fd);
807
  } else {  // close(fd, undefined, ctx)
808
54212
    CHECK_EQ(argc, 3);
809
54212
    FSReqWrapSync req_wrap_sync;
810

54272
    FS_SYNC_TRACE_BEGIN(close);
811
54212
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
812

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

13235
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
869
1
    start = 3;  // Skip UTF-8 BOM.
870
  }
871
872
13235
  const size_t size = offset - start;
873

32829
  if (size == 0 || (
874
19595
    size == SearchString(&chars[start], size, "\"main\"") &&
875
6362
    size == SearchString(&chars[start], size, "\"exports\""))) {
876
6361
    return;
877
  } else {
878
    Local<String> chars_string =
879
        String::NewFromUtf8(isolate,
880
6874
                            &chars[start],
881
                            v8::NewStringType::kNormal,
882
20622
                            size).ToLocalChecked();
883
13748
    args.GetReturnValue().Set(chars_string);
884
6874
  }
885
}
886
887
// Used to speed up module loading.  Returns 0 if the path refers to
888
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
889
// The speedup comes from not creating thousands of Stat and Error objects.
890
175644
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
891
175644
  Environment* env = Environment::GetCurrent(args);
892
893
526932
  CHECK(args[0]->IsString());
894
175644
  node::Utf8Value path(env->isolate(), args[0]);
895
896
  uv_fs_t req;
897
175644
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
898
175644
  if (rc == 0) {
899
73088
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
900
73088
    rc = !!(s->st_mode & S_IFDIR);
901
  }
902
175644
  uv_fs_req_cleanup(&req);
903
904
351288
  args.GetReturnValue().Set(rc);
905
175644
}
906
907
35413
static void Stat(const FunctionCallbackInfo<Value>& args) {
908
35413
  Environment* env = Environment::GetCurrent(args);
909
910
35413
  const int argc = args.Length();
911
35413
  CHECK_GE(argc, 2);
912
913
35413
  BufferValue path(env->isolate(), args[0]);
914
35413
  CHECK_NOT_NULL(*path);
915
916
70826
  bool use_bigint = args[1]->IsTrue();
917
70826
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
918
35413
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
919
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
920
1966
              uv_fs_stat, *path);
921
  } else {  // stat(path, use_bigint, undefined, ctx)
922
33447
    CHECK_EQ(argc, 4);
923
33447
    FSReqWrapSync req_wrap_sync;
924

33449
    FS_SYNC_TRACE_BEGIN(stat);
925
66894
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
926

33449
    FS_SYNC_TRACE_END(stat);
927
33447
    if (err != 0) {
928
35417
      return;  // error info is in ctx
929
    }
930
931
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
932
33443
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
933

66886
    args.GetReturnValue().Set(arr);
934
35409
  }
935
}
936
937
119743
static void LStat(const FunctionCallbackInfo<Value>& args) {
938
119743
  Environment* env = Environment::GetCurrent(args);
939
940
119743
  const int argc = args.Length();
941
119743
  CHECK_GE(argc, 3);
942
943
119743
  BufferValue path(env->isolate(), args[0]);
944
119743
  CHECK_NOT_NULL(*path);
945
946
239486
  bool use_bigint = args[1]->IsTrue();
947
239486
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
948
119743
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
949
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
950
4716
              uv_fs_lstat, *path);
951
  } else {  // lstat(path, use_bigint, undefined, ctx)
952
115027
    CHECK_EQ(argc, 4);
953
115027
    FSReqWrapSync req_wrap_sync;
954

115061
    FS_SYNC_TRACE_BEGIN(lstat);
955
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
956
230054
                       *path);
957

115061
    FS_SYNC_TRACE_END(lstat);
958
115027
    if (err != 0) {
959
120000
      return;  // error info is in ctx
960
    }
961
962
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
963
114770
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
964

229540
    args.GetReturnValue().Set(arr);
965
119486
  }
966
}
967
968
50407
static void FStat(const FunctionCallbackInfo<Value>& args) {
969
50407
  Environment* env = Environment::GetCurrent(args);
970
971
50407
  const int argc = args.Length();
972
50407
  CHECK_GE(argc, 2);
973
974
100814
  CHECK(args[0]->IsInt32());
975
151221
  int fd = args[0].As<Int32>()->Value();
976
977
100814
  bool use_bigint = args[1]->IsTrue();
978
100814
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
979
50407
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
980
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
981
2737
              uv_fs_fstat, fd);
982
  } else {  // fstat(fd, use_bigint, undefined, ctx)
983
47670
    CHECK_EQ(argc, 4);
984
47670
    FSReqWrapSync req_wrap_sync;
985

47680
    FS_SYNC_TRACE_BEGIN(fstat);
986
47670
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
987

47680
    FS_SYNC_TRACE_END(fstat);
988
47670
    if (err != 0) {
989
50424
      return;  // error info is in ctx
990
    }
991
992
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
993
47653
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
994
95306
    args.GetReturnValue().Set(arr);
995
  }
996
}
997
998
102
static void Symlink(const FunctionCallbackInfo<Value>& args) {
999
102
  Environment* env = Environment::GetCurrent(args);
1000
102
  Isolate* isolate = env->isolate();
1001
1002
102
  int argc = args.Length();
1003
102
  CHECK_GE(argc, 4);
1004
1005
102
  BufferValue target(isolate, args[0]);
1006
102
  CHECK_NOT_NULL(*target);
1007
204
  BufferValue path(isolate, args[1]);
1008
102
  CHECK_NOT_NULL(*path);
1009
1010
204
  CHECK(args[2]->IsInt32());
1011
306
  int flags = args[2].As<Int32>()->Value();
1012
1013
102
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1014
102
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1015
20
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1016
40
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1017
  } else {  // symlink(target, path, flags, undefinec, ctx)
1018
82
    CHECK_EQ(argc, 5);
1019
82
    FSReqWrapSync req_wrap_sync;
1020

86
    FS_SYNC_TRACE_BEGIN(symlink);
1021
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1022
164
             uv_fs_symlink, *target, *path, flags);
1023

86
    FS_SYNC_TRACE_END(symlink);
1024
102
  }
1025
102
}
1026
1027
100
static void Link(const FunctionCallbackInfo<Value>& args) {
1028
100
  Environment* env = Environment::GetCurrent(args);
1029
100
  Isolate* isolate = env->isolate();
1030
1031
100
  int argc = args.Length();
1032
100
  CHECK_GE(argc, 3);
1033
1034
100
  BufferValue src(isolate, args[0]);
1035
100
  CHECK_NOT_NULL(*src);
1036
1037
200
  BufferValue dest(isolate, args[1]);
1038
100
  CHECK_NOT_NULL(*dest);
1039
1040
100
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1041
100
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1042
95
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1043
190
                  AfterNoArgs, uv_fs_link, *src, *dest);
1044
  } else {  // link(src, dest)
1045
5
    CHECK_EQ(argc, 4);
1046
5
    FSReqWrapSync req_wrap_sync;
1047

11
    FS_SYNC_TRACE_BEGIN(link);
1048
    SyncCall(env, args[3], &req_wrap_sync, "link",
1049
10
             uv_fs_link, *src, *dest);
1050

11
    FS_SYNC_TRACE_END(link);
1051
100
  }
1052
100
}
1053
1054
89
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1055
89
  Environment* env = Environment::GetCurrent(args);
1056
89
  Isolate* isolate = env->isolate();
1057
1058
89
  int argc = args.Length();
1059
89
  CHECK_GE(argc, 3);
1060
1061
89
  BufferValue path(isolate, args[0]);
1062
89
  CHECK_NOT_NULL(*path);
1063
1064
89
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1065
1066
89
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1067
89
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1068
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1069
43
              uv_fs_readlink, *path);
1070
  } else {
1071
46
    CHECK_EQ(argc, 4);
1072
46
    FSReqWrapSync req_wrap_sync;
1073

48
    FS_SYNC_TRACE_BEGIN(readlink);
1074
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1075
92
                       uv_fs_readlink, *path);
1076

48
    FS_SYNC_TRACE_END(readlink);
1077
46
    if (err < 0) {
1078
1
      return;  // syscall failed, no need to continue, error info is in ctx
1079
    }
1080
45
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1081
1082
    Local<Value> error;
1083
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1084
                                               link_path,
1085
                                               encoding,
1086
45
                                               &error);
1087
45
    if (rc.IsEmpty()) {
1088
      Local<Object> ctx = args[3].As<Object>();
1089
      ctx->Set(env->context(), env->error_string(), error).Check();
1090
      return;
1091
    }
1092
1093

90
    args.GetReturnValue().Set(rc.ToLocalChecked());
1094
88
  }
1095
}
1096
1097
212
static void Rename(const FunctionCallbackInfo<Value>& args) {
1098
212
  Environment* env = Environment::GetCurrent(args);
1099
212
  Isolate* isolate = env->isolate();
1100
1101
212
  int argc = args.Length();
1102
212
  CHECK_GE(argc, 3);
1103
1104
212
  BufferValue old_path(isolate, args[0]);
1105
212
  CHECK_NOT_NULL(*old_path);
1106
424
  BufferValue new_path(isolate, args[1]);
1107
212
  CHECK_NOT_NULL(*new_path);
1108
1109
212
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1110
212
  if (req_wrap_async != nullptr) {
1111
207
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1112
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1113
414
                  *old_path, *new_path);
1114
  } else {
1115
5
    CHECK_EQ(argc, 4);
1116
5
    FSReqWrapSync req_wrap_sync;
1117

7
    FS_SYNC_TRACE_BEGIN(rename);
1118
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1119
10
             *old_path, *new_path);
1120

7
    FS_SYNC_TRACE_END(rename);
1121
212
  }
1122
212
}
1123
1124
48
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1125
48
  Environment* env = Environment::GetCurrent(args);
1126
1127
48
  const int argc = args.Length();
1128
48
  CHECK_GE(argc, 3);
1129
1130
96
  CHECK(args[0]->IsInt32());
1131
144
  const int fd = args[0].As<Int32>()->Value();
1132
1133
48
  CHECK(IsSafeJsInt(args[1]));
1134
144
  const int64_t len = args[1].As<Integer>()->Value();
1135
1136
48
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1137
48
  if (req_wrap_async != nullptr) {
1138
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1139
34
              uv_fs_ftruncate, fd, len);
1140
  } else {
1141
14
    CHECK_EQ(argc, 4);
1142
14
    FSReqWrapSync req_wrap_sync;
1143

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1144
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1145
14
             len);
1146

16
    FS_SYNC_TRACE_END(ftruncate);
1147
  }
1148
48
}
1149
1150
7
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1151
7
  Environment* env = Environment::GetCurrent(args);
1152
1153
7
  const int argc = args.Length();
1154
7
  CHECK_GE(argc, 2);
1155
1156
14
  CHECK(args[0]->IsInt32());
1157
21
  const int fd = args[0].As<Int32>()->Value();
1158
1159
7
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1160
7
  if (req_wrap_async != nullptr) {
1161
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1162
4
              uv_fs_fdatasync, fd);
1163
  } else {
1164
3
    CHECK_EQ(argc, 3);
1165
3
    FSReqWrapSync req_wrap_sync;
1166

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

5
    FS_SYNC_TRACE_END(fdatasync);
1169
  }
1170
7
}
1171
1172
23
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1173
23
  Environment* env = Environment::GetCurrent(args);
1174
1175
23
  const int argc = args.Length();
1176
23
  CHECK_GE(argc, 2);
1177
1178
46
  CHECK(args[0]->IsInt32());
1179
69
  const int fd = args[0].As<Int32>()->Value();
1180
1181
23
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1182
23
  if (req_wrap_async != nullptr) {
1183
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1184
6
              uv_fs_fsync, fd);
1185
  } else {
1186
17
    CHECK_EQ(argc, 3);
1187
17
    FSReqWrapSync req_wrap_sync;
1188

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

19
    FS_SYNC_TRACE_END(fsync);
1191
  }
1192
23
}
1193
1194
3647
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1195
3647
  Environment* env = Environment::GetCurrent(args);
1196
1197
3647
  const int argc = args.Length();
1198
3647
  CHECK_GE(argc, 2);
1199
1200
3647
  BufferValue path(env->isolate(), args[0]);
1201
3647
  CHECK_NOT_NULL(*path);
1202
1203
3647
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1204
3647
  if (req_wrap_async != nullptr) {
1205
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1206
99
              uv_fs_unlink, *path);
1207
  } else {
1208
3548
    CHECK_EQ(argc, 3);
1209
3548
    FSReqWrapSync req_wrap_sync;
1210

3608
    FS_SYNC_TRACE_BEGIN(unlink);
1211
7096
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1212

3608
    FS_SYNC_TRACE_END(unlink);
1213
3647
  }
1214
3647
}
1215
1216
3852
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1217
3852
  Environment* env = Environment::GetCurrent(args);
1218
1219
3852
  const int argc = args.Length();
1220
3852
  CHECK_GE(argc, 2);
1221
1222
3852
  BufferValue path(env->isolate(), args[0]);
1223
3852
  CHECK_NOT_NULL(*path);
1224
1225
3852
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);  // rmdir(path, req)
1226
3852
  if (req_wrap_async != nullptr) {
1227
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1228
23
              uv_fs_rmdir, *path);
1229
  } else {  // rmdir(path, undefined, ctx)
1230
3829
    CHECK_EQ(argc, 3);
1231
3829
    FSReqWrapSync req_wrap_sync;
1232

3835
    FS_SYNC_TRACE_BEGIN(rmdir);
1233
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1234
7658
             uv_fs_rmdir, *path);
1235

3835
    FS_SYNC_TRACE_END(rmdir);
1236
3852
  }
1237
3852
}
1238
1239
4965
int MKDirpSync(uv_loop_t* loop,
1240
               uv_fs_t* req,
1241
               const std::string& path,
1242
               int mode,
1243
               uv_fs_cb cb) {
1244
4965
  FSContinuationData continuation_data(req, mode, cb);
1245
4965
  continuation_data.PushPath(std::move(path));
1246
1247
4966
  while (continuation_data.paths.size() > 0) {
1248
4998
    std::string next_path = continuation_data.PopPath();
1249
4997
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1250
    while (true) {
1251

4999
      switch (err) {
1252
        case 0:
1253
36
          if (continuation_data.paths.size() == 0) {
1254
21
            return 0;
1255
          }
1256
16
          break;
1257
        case UV_ENOENT: {
1258
          std::string dirname = next_path.substr(0,
1259
17
                                        next_path.find_last_of(kPathSeparator));
1260
17
          if (dirname != next_path) {
1261
16
            continuation_data.PushPath(std::move(next_path));
1262
16
            continuation_data.PushPath(std::move(dirname));
1263
1
          } else if (continuation_data.paths.size() == 0) {
1264
1
            err = UV_EEXIST;
1265
1
            continue;
1266
          }
1267
16
          break;
1268
        }
1269
        case UV_EPERM: {
1270
          return err;
1271
        }
1272
        default:
1273
4946
          uv_fs_req_cleanup(req);
1274
4946
          int orig_err = err;
1275
4946
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1276

4945
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1277
1
            uv_fs_req_cleanup(req);
1278

1
            if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
1279
              return UV_ENOTDIR;
1280
            }
1281
1
            return UV_EEXIST;
1282
          }
1283
4944
          if (err < 0) return err;
1284
4942
          break;
1285
      }
1286
4974
      break;
1287
    }
1288
4974
    uv_fs_req_cleanup(req);
1289
4974
  }
1290
1291
4941
  return 0;
1292
}
1293
1294
22
int MKDirpAsync(uv_loop_t* loop,
1295
                uv_fs_t* req,
1296
                const char* path,
1297
                int mode,
1298
                uv_fs_cb cb) {
1299
22
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1300
  // on the first iteration of algorithm, stash state information.
1301
22
  if (req_wrap->continuation_data == nullptr) {
1302
20
    req_wrap->continuation_data =
1303
10
        std::make_unique<FSContinuationData>(req, mode, cb);
1304
10
    req_wrap->continuation_data->PushPath(std::move(path));
1305
  }
1306
1307
  // on each iteration of algorithm, mkdir directory on top of stack.
1308
22
  std::string next_path = req_wrap->continuation_data->PopPath();
1309
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1310
66
                        uv_fs_callback_t{[](uv_fs_t* req) {
1311
22
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1312
22
    Environment* env = req_wrap->env();
1313
22
    uv_loop_t* loop = env->event_loop();
1314
22
    std::string path = req->path;
1315
22
    int err = req->result;
1316
1317
    while (true) {
1318

23
      switch (err) {
1319
        case 0: {
1320
11
          if (req_wrap->continuation_data->paths.size() == 0) {
1321
5
            req_wrap->continuation_data->Done(0);
1322
          } else {
1323
6
            uv_fs_req_cleanup(req);
1324
            MKDirpAsync(loop, req, path.c_str(),
1325
6
                        req_wrap->continuation_data->mode, nullptr);
1326
          }
1327
11
          break;
1328
        }
1329
        case UV_ENOENT: {
1330
          std::string dirname = path.substr(0,
1331
7
                                            path.find_last_of(kPathSeparator));
1332
7
          if (dirname != path) {
1333
6
            req_wrap->continuation_data->PushPath(std::move(path));
1334
6
            req_wrap->continuation_data->PushPath(std::move(dirname));
1335
1
          } else if (req_wrap->continuation_data->paths.size() == 0) {
1336
1
            err = UV_EEXIST;
1337
1
            continue;
1338
          }
1339
6
          uv_fs_req_cleanup(req);
1340
          MKDirpAsync(loop, req, path.c_str(),
1341
6
                      req_wrap->continuation_data->mode, nullptr);
1342
6
          break;
1343
        }
1344
        case UV_EPERM: {
1345
          req_wrap->continuation_data->Done(err);
1346
          break;
1347
        }
1348
        default:
1349
5
          uv_fs_req_cleanup(req);
1350
          // Stash err for use in the callback.
1351
5
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1352
          int err = uv_fs_stat(loop, req, path.c_str(),
1353
15
                               uv_fs_callback_t{[](uv_fs_t* req) {
1354
5
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1355
5
            int err = req->result;
1356

8
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1357
3
                  req_wrap->continuation_data->paths.size() > 0) {
1358
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1359
                Environment* env = req_wrap->env();
1360
                uv_loop_t* loop = env->event_loop();
1361
                std::string path = req->path;
1362
                uv_fs_req_cleanup(req);
1363
                MKDirpAsync(loop, req, path.c_str(),
1364
                            req_wrap->continuation_data->mode, nullptr);
1365
5
                return;
1366
              }
1367
              err = UV_ENOTDIR;
1368
            }
1369
            // verify that the path pointed to is actually a directory.
1370

5
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1371
5
            uv_fs_req_cleanup(req);
1372
5
            req_wrap->continuation_data->Done(err);
1373
15
          }});
1374
5
          if (err < 0) req_wrap->continuation_data->Done(err);
1375
5
          break;
1376
      }
1377
22
      break;
1378
    }
1379
88
  }});
1380
1381
22
  return err;
1382
}
1383
1384
3237
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1385
3237
  Environment* env = Environment::GetCurrent(args);
1386
1387
3237
  const int argc = args.Length();
1388
3237
  CHECK_GE(argc, 4);
1389
1390
3237
  BufferValue path(env->isolate(), args[0]);
1391
3237
  CHECK_NOT_NULL(*path);
1392
1393
6474
  CHECK(args[1]->IsInt32());
1394
9711
  const int mode = args[1].As<Int32>()->Value();
1395
1396
6474
  CHECK(args[2]->IsBoolean());
1397
6474
  bool mkdirp = args[2]->IsTrue();
1398
1399
3237
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1400
3237
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1401
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1402
1109
              AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1403
  } else {  // mkdir(path, mode, undefined, ctx)
1404
2128
    CHECK_EQ(argc, 5);
1405
2128
    FSReqWrapSync req_wrap_sync;
1406

2132
    FS_SYNC_TRACE_BEGIN(mkdir);
1407
2128
    if (mkdirp) {
1408
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1409
16
               MKDirpSync, *path, mode);
1410
    } else {
1411
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1412
4240
               uv_fs_mkdir, *path, mode);
1413
    }
1414

2132
    FS_SYNC_TRACE_END(mkdir);
1415
3237
  }
1416
3237
}
1417
1418
42
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1419
42
  Environment* env = Environment::GetCurrent(args);
1420
42
  Isolate* isolate = env->isolate();
1421
1422
42
  const int argc = args.Length();
1423
42
  CHECK_GE(argc, 3);
1424
1425
42
  BufferValue path(isolate, args[0]);
1426
42
  CHECK_NOT_NULL(*path);
1427
1428
42
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1429
1430
42
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1431
42
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1432
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1433
22
              uv_fs_realpath, *path);
1434
  } else {  // realpath(path, encoding, undefined, ctx)
1435
20
    CHECK_EQ(argc, 4);
1436
20
    FSReqWrapSync req_wrap_sync;
1437

22
    FS_SYNC_TRACE_BEGIN(realpath);
1438
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1439
40
                       uv_fs_realpath, *path);
1440

22
    FS_SYNC_TRACE_END(realpath);
1441
20
    if (err < 0) {
1442
2
      return;  // syscall failed, no need to continue, error info is in ctx
1443
    }
1444
1445
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1446
1447
    Local<Value> error;
1448
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1449
                                               link_path,
1450
                                               encoding,
1451
18
                                               &error);
1452
18
    if (rc.IsEmpty()) {
1453
      Local<Object> ctx = args[3].As<Object>();
1454
      ctx->Set(env->context(), env->error_string(), error).Check();
1455
      return;
1456
    }
1457
1458

36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1459
40
  }
1460
}
1461
1462
16066
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1463
16066
  Environment* env = Environment::GetCurrent(args);
1464
16066
  Isolate* isolate = env->isolate();
1465
1466
16066
  const int argc = args.Length();
1467
16066
  CHECK_GE(argc, 3);
1468
1469
16066
  BufferValue path(isolate, args[0]);
1470
16066
  CHECK_NOT_NULL(*path);
1471
1472
16066
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1473
1474
32132
  bool with_types = args[2]->IsTrue();
1475
1476
16066
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1477
16066
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1478
142
    if (with_types) {
1479
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1480
7
                AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1481
    } else {
1482
      AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1483
135
                AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1484
    }
1485
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1486
15924
    CHECK_EQ(argc, 5);
1487
15924
    FSReqWrapSync req_wrap_sync;
1488

15926
    FS_SYNC_TRACE_BEGIN(readdir);
1489
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1490
31848
                       uv_fs_scandir, *path, 0 /*flags*/);
1491

15926
    FS_SYNC_TRACE_END(readdir);
1492
15924
    if (err < 0) {
1493
43
      return;  // syscall failed, no need to continue, error info is in ctx
1494
    }
1495
1496
15881
    CHECK_GE(req_wrap_sync.req.result, 0);
1497
    int r;
1498
31762
    std::vector<Local<Value>> name_v;
1499
31762
    std::vector<Local<Value>> type_v;
1500
1501
686141
    for (int i = 0; ; i++) {
1502
      uv_dirent_t ent;
1503
1504
686141
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1505
686141
      if (r == UV_EOF)
1506
15881
        break;
1507
670260
      if (r != 0) {
1508
        Local<Object> ctx = args[4].As<Object>();
1509
        ctx->Set(env->context(), env->errno_string(),
1510
                 Integer::New(isolate, r)).Check();
1511
        ctx->Set(env->context(), env->syscall_string(),
1512
                 OneByteString(isolate, "readdir")).Check();
1513
        return;
1514
      }
1515
1516
      Local<Value> error;
1517
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1518
                                                       ent.name,
1519
                                                       encoding,
1520
670260
                                                       &error);
1521
1522
670260
      if (filename.IsEmpty()) {
1523
        Local<Object> ctx = args[4].As<Object>();
1524
        ctx->Set(env->context(), env->error_string(), error).Check();
1525
        return;
1526
      }
1527
1528
670260
      name_v.push_back(filename.ToLocalChecked());
1529
1530
670260
      if (with_types) {
1531
19
        type_v.emplace_back(Integer::New(isolate, ent.type));
1532
      }
1533
670260
    }
1534
1535
1536
15881
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1537
15881
    if (with_types) {
1538
5
      Local<Array> result = Array::New(isolate, 2);
1539
15
      result->Set(env->context(), 0, names).Check();
1540
5
      result->Set(env->context(),
1541
                  1,
1542
                  Array::New(isolate, type_v.data(),
1543
20
                             type_v.size())).Check();
1544
10
      args.GetReturnValue().Set(result);
1545
    } else {
1546
31752
      args.GetReturnValue().Set(names);
1547
15881
    }
1548
16023
  }
1549
}
1550
1551
62708
static void Open(const FunctionCallbackInfo<Value>& args) {
1552
62708
  Environment* env = Environment::GetCurrent(args);
1553
1554
62708
  const int argc = args.Length();
1555
62708
  CHECK_GE(argc, 3);
1556
1557
62708
  BufferValue path(env->isolate(), args[0]);
1558
62708
  CHECK_NOT_NULL(*path);
1559
1560
125416
  CHECK(args[1]->IsInt32());
1561
188124
  const int flags = args[1].As<Int32>()->Value();
1562
1563
125416
  CHECK(args[2]->IsInt32());
1564
188124
  const int mode = args[2].As<Int32>()->Value();
1565
1566
62708
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1567
62708
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1568
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1569
7743
              uv_fs_open, *path, flags, mode);
1570
  } else {  // open(path, flags, mode, undefined, ctx)
1571
54965
    CHECK_EQ(argc, 5);
1572
54965
    FSReqWrapSync req_wrap_sync;
1573

55037
    FS_SYNC_TRACE_BEGIN(open);
1574
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1575
109930
                          uv_fs_open, *path, flags, mode);
1576

55037
    FS_SYNC_TRACE_END(open);
1577
109930
    args.GetReturnValue().Set(result);
1578
62708
  }
1579
62708
}
1580
1581
64
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1582
64
  Environment* env = Environment::GetCurrent(args);
1583
64
  Isolate* isolate = env->isolate();
1584
1585
64
  const int argc = args.Length();
1586
64
  CHECK_GE(argc, 3);
1587
1588
64
  BufferValue path(isolate, args[0]);
1589
64
  CHECK_NOT_NULL(*path);
1590
1591
128
  CHECK(args[1]->IsInt32());
1592
192
  const int flags = args[1].As<Int32>()->Value();
1593
1594
128
  CHECK(args[2]->IsInt32());
1595
192
  const int mode = args[2].As<Int32>()->Value();
1596
1597
64
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1598
64
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1599
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1600
63
              uv_fs_open, *path, flags, mode);
1601
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1602
1
    CHECK_EQ(argc, 5);
1603
1
    FSReqWrapSync req_wrap_sync;
1604

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

1
    FS_SYNC_TRACE_END(open);
1608
1
    if (result < 0) {
1609
      return;  // syscall failed, no need to continue, error info is in ctx
1610
    }
1611
1
    FileHandle* fd = FileHandle::New(env, result);
1612
1
    if (fd == nullptr) return;
1613

3
    args.GetReturnValue().Set(fd->object());
1614
64
  }
1615
}
1616
1617
35
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1618
35
  Environment* env = Environment::GetCurrent(args);
1619
35
  Isolate* isolate = env->isolate();
1620
1621
35
  const int argc = args.Length();
1622
35
  CHECK_GE(argc, 3);
1623
1624
35
  BufferValue src(isolate, args[0]);
1625
35
  CHECK_NOT_NULL(*src);
1626
1627
70
  BufferValue dest(isolate, args[1]);
1628
35
  CHECK_NOT_NULL(*dest);
1629
1630
70
  CHECK(args[2]->IsInt32());
1631
105
  const int flags = args[2].As<Int32>()->Value();
1632
1633
35
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1634
35
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1635
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1636
15
                  *dest, dest.length(), UTF8, AfterNoArgs,
1637
30
                  uv_fs_copyfile, *src, *dest, flags);
1638
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1639
20
    CHECK_EQ(argc, 5);
1640
20
    FSReqWrapSync req_wrap_sync;
1641

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1642
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1643
40
             uv_fs_copyfile, *src, *dest, flags);
1644

22
    FS_SYNC_TRACE_END(copyfile);
1645
35
  }
1646
35
}
1647
1648
1649
// Wrapper for write(2).
1650
//
1651
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1652
// 0 fd        integer. file descriptor
1653
// 1 buffer    the data to write
1654
// 2 offset    where in the buffer to start from
1655
// 3 length    how much to write
1656
// 4 position  if integer, position to write at in the file.
1657
//             if null, write from the current position
1658
143722
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1659
143722
  Environment* env = Environment::GetCurrent(args);
1660
1661
143722
  const int argc = args.Length();
1662
143722
  CHECK_GE(argc, 4);
1663
1664
287444
  CHECK(args[0]->IsInt32());
1665
431166
  const int fd = args[0].As<Int32>()->Value();
1666
1667
143722
  CHECK(Buffer::HasInstance(args[1]));
1668
287444
  Local<Object> buffer_obj = args[1].As<Object>();
1669
143722
  char* buffer_data = Buffer::Data(buffer_obj);
1670
143722
  size_t buffer_length = Buffer::Length(buffer_obj);
1671
1672
143722
  CHECK(IsSafeJsInt(args[2]));
1673
431166
  const int64_t off_64 = args[2].As<Integer>()->Value();
1674
143722
  CHECK_GE(off_64, 0);
1675
143722
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1676
143722
  const size_t off = static_cast<size_t>(off_64);
1677
1678
287444
  CHECK(args[3]->IsInt32());
1679
431166
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1680
143722
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1681
143722
  CHECK_LE(len, buffer_length);
1682
143722
  CHECK_GE(off + len, off);
1683
1684

165469
  const int64_t pos = GET_OFFSET(args[4]);
1685
1686
143722
  char* buf = buffer_data + off;
1687
143722
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1688
1689
143722
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1690
143722
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1691
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1692
16760
              uv_fs_write, fd, &uvbuf, 1, pos);
1693
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1694
126962
    CHECK_EQ(argc, 7);
1695
126962
    FSReqWrapSync req_wrap_sync;
1696

127012
    FS_SYNC_TRACE_BEGIN(write);
1697
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1698
126962
                                uv_fs_write, fd, &uvbuf, 1, pos);
1699

127012
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1700
380886
    args.GetReturnValue().Set(bytesWritten);
1701
  }
1702
143722
}
1703
1704
1705
// Wrapper for writev(2).
1706
//
1707
// bytesWritten = writev(fd, chunks, position, callback)
1708
// 0 fd        integer. file descriptor
1709
// 1 chunks    array of buffers to write
1710
// 2 position  if integer, position to write at in the file.
1711
//             if null, write from the current position
1712
26
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1713
26
  Environment* env = Environment::GetCurrent(args);
1714
1715
26
  const int argc = args.Length();
1716
26
  CHECK_GE(argc, 3);
1717
1718
52
  CHECK(args[0]->IsInt32());
1719
78
  const int fd = args[0].As<Int32>()->Value();
1720
1721
52
  CHECK(args[1]->IsArray());
1722
52
  Local<Array> chunks = args[1].As<Array>();
1723
1724

26
  int64_t pos = GET_OFFSET(args[2]);
1725
1726
26
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1727
1728
181503
  for (uint32_t i = 0; i < iovs.length(); i++) {
1729
544431
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1730
181477
    CHECK(Buffer::HasInstance(chunk));
1731
181477
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1732
  }
1733
1734
26
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1735
26
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1736
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1737
22
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1738
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1739
4
    CHECK_EQ(argc, 5);
1740
4
    FSReqWrapSync req_wrap_sync;
1741

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1745
12
    args.GetReturnValue().Set(bytesWritten);
1746
26
  }
1747
26
}
1748
1749
1750
// Wrapper for write(2).
1751
//
1752
// bytesWritten = write(fd, string, position, enc, callback)
1753
// 0 fd        integer. file descriptor
1754
// 1 string    non-buffer values are converted to strings
1755
// 2 position  if integer, position to write at in the file.
1756
//             if null, write from the current position
1757
// 3 enc       encoding of string
1758
1353
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1759
1353
  Environment* env = Environment::GetCurrent(args);
1760
1353
  Isolate* isolate = env->isolate();
1761
1762
1353
  const int argc = args.Length();
1763
1353
  CHECK_GE(argc, 4);
1764
1765
2706
  CHECK(args[0]->IsInt32());
1766
4059
  const int fd = args[0].As<Int32>()->Value();
1767
1768

1761
  const int64_t pos = GET_OFFSET(args[2]);
1769
1770
1353
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1771
1772
1353
  Local<Value> value = args[1];
1773
1353
  char* buf = nullptr;
1774
  size_t len;
1775
1776
1353
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1777
1353
  const bool is_async = req_wrap_async != nullptr;
1778
1779
  // Avoid copying the string when it is externalized but only when:
1780
  // 1. The target encoding is compatible with the string's encoding, and
1781
  // 2. The write is synchronous, otherwise the string might get neutered
1782
  //    while the request is in flight, and
1783
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1784
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1785
  // The const_casts are conceptually sound: memory is read but not written.
1786

3791
  if (!is_async && value->IsString()) {
1787
1219
    auto string = value.As<String>();
1788


1220
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1789
1
      auto ext = string->GetExternalOneByteStringResource();
1790
1
      buf = const_cast<char*>(ext->data());
1791
1
      len = ext->length();
1792


1219
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1793
2
      auto ext = string->GetExternalStringResource();
1794
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1795
1
      len = ext->length() * sizeof(*ext->data());
1796
    }
1797
  }
1798
1799
1353
  if (is_async) {  // write(fd, string, pos, enc, req)
1800
134
    CHECK_NOT_NULL(req_wrap_async);
1801
268
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1802
    FSReqBase::FSReqBuffer& stack_buffer =
1803
134
        req_wrap_async->Init("write", len, enc);
1804
    // StorageSize may return too large a char, so correct the actual length
1805
    // by the write size
1806
134
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1807
134
    stack_buffer.SetLengthAndZeroTerminate(len);
1808
134
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1809
    int err = req_wrap_async->Dispatch(uv_fs_write,
1810
                                       fd,
1811
                                       &uvbuf,
1812
                                       1,
1813
                                       pos,
1814
134
                                       AfterInteger);
1815
134
    if (err < 0) {
1816
      uv_fs_t* uv_req = req_wrap_async->req();
1817
      uv_req->result = err;
1818
      uv_req->path = nullptr;
1819
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
1820
                             // an error
1821
    } else {
1822
134
      req_wrap_async->SetReturnValue(args);
1823
    }
1824
  } else {  // write(fd, string, pos, enc, undefined, ctx)
1825
1219
    CHECK_EQ(argc, 6);
1826
1219
    FSReqWrapSync req_wrap_sync;
1827
2438
    FSReqBase::FSReqBuffer stack_buffer;
1828
1219
    if (buf == nullptr) {
1829
2434
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1830
        return;
1831
1217
      stack_buffer.AllocateSufficientStorage(len + 1);
1832
      // StorageSize may return too large a char, so correct the actual length
1833
      // by the write size
1834
      len = StringBytes::Write(isolate, *stack_buffer,
1835
1217
                               len, args[1], enc);
1836
1217
      stack_buffer.SetLengthAndZeroTerminate(len);
1837
1217
      buf = *stack_buffer;
1838
    }
1839
1219
    uv_buf_t uvbuf = uv_buf_init(buf, len);
1840

1219
    FS_SYNC_TRACE_BEGIN(write);
1841
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1842
1219
                                uv_fs_write, fd, &uvbuf, 1, pos);
1843

1219
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1844
4876
    args.GetReturnValue().Set(bytesWritten);
1845
  }
1846
}
1847
1848
1849
/*
1850
 * Wrapper for read(2).
1851
 *
1852
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1853
 *
1854
 * 0 fd        int32. file descriptor
1855
 * 1 buffer    instance of Buffer
1856
 * 2 offset    int64. offset to start reading into inside buffer
1857
 * 3 length    int32. length to read
1858
 * 4 position  int64. file position - -1 for current position
1859
 */
1860
79059
static void Read(const FunctionCallbackInfo<Value>& args) {
1861
79059
  Environment* env = Environment::GetCurrent(args);
1862
1863
79059
  const int argc = args.Length();
1864
79059
  CHECK_GE(argc, 5);
1865
1866
158118
  CHECK(args[0]->IsInt32());
1867
237177
  const int fd = args[0].As<Int32>()->Value();
1868
1869
79059
  CHECK(Buffer::HasInstance(args[1]));
1870
158118
  Local<Object> buffer_obj = args[1].As<Object>();
1871
79059
  char* buffer_data = Buffer::Data(buffer_obj);
1872
79059
  size_t buffer_length = Buffer::Length(buffer_obj);
1873
1874
79059
  CHECK(IsSafeJsInt(args[2]));
1875
237177
  const int64_t off_64 = args[2].As<Integer>()->Value();
1876
79059
  CHECK_GE(off_64, 0);
1877
79059
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
1878
79059
  const size_t off = static_cast<size_t>(off_64);
1879
1880
158118
  CHECK(args[3]->IsInt32());
1881
237177
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1882
79059
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1883
1884
79059
  CHECK(IsSafeJsInt(args[4]));
1885
237177
  const int64_t pos = args[4].As<Integer>()->Value();
1886
1887
79059
  char* buf = buffer_data + off;
1888
79059
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1889
1890
79059
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1891
79059
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
1892
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1893
13610
              uv_fs_read, fd, &uvbuf, 1, pos);
1894
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
1895
65449
    CHECK_EQ(argc, 7);
1896
65449
    FSReqWrapSync req_wrap_sync;
1897

65459
    FS_SYNC_TRACE_BEGIN(read);
1898
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1899
65449
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1900

65459
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1901
196347
    args.GetReturnValue().Set(bytesRead);
1902
  }
1903
79059
}
1904
1905
1906
/* fs.chmod(path, mode);
1907
 * Wrapper for chmod(1) / EIO_CHMOD
1908
 */
1909
218
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1910
218
  Environment* env = Environment::GetCurrent(args);
1911
1912
218
  const int argc = args.Length();
1913
218
  CHECK_GE(argc, 2);
1914
1915
218
  BufferValue path(env->isolate(), args[0]);
1916
218
  CHECK_NOT_NULL(*path);
1917
1918
436
  CHECK(args[1]->IsInt32());
1919
654
  int mode = args[1].As<Int32>()->Value();
1920
1921
218
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1922
218
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
1923
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1924
204
              uv_fs_chmod, *path, mode);
1925
  } else {  // chmod(path, mode, undefined, ctx)
1926
14
    CHECK_EQ(argc, 4);
1927
14
    FSReqWrapSync req_wrap_sync;
1928

16
    FS_SYNC_TRACE_BEGIN(chmod);
1929
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1930
28
             uv_fs_chmod, *path, mode);
1931

16
    FS_SYNC_TRACE_END(chmod);
1932
218
  }
1933
218
}
1934
1935
1936
/* fs.fchmod(fd, mode);
1937
 * Wrapper for fchmod(1) / EIO_FCHMOD
1938
 */
1939
12
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1940
12
  Environment* env = Environment::GetCurrent(args);
1941
1942
12
  const int argc = args.Length();
1943
12
  CHECK_GE(argc, 2);
1944
1945
24
  CHECK(args[0]->IsInt32());
1946
36
  const int fd = args[0].As<Int32>()->Value();
1947
1948
24
  CHECK(args[1]->IsInt32());
1949
36
  const int mode = args[1].As<Int32>()->Value();
1950
1951
12
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1952
12
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
1953
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
1954
7
              uv_fs_fchmod, fd, mode);
1955
  } else {  // fchmod(fd, mode, undefined, ctx)
1956
5
    CHECK_EQ(argc, 4);
1957
5
    FSReqWrapSync req_wrap_sync;
1958

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1959
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1960
5
             uv_fs_fchmod, fd, mode);
1961

7
    FS_SYNC_TRACE_END(fchmod);
1962
  }
1963
12
}
1964
1965
1966
/* fs.chown(path, uid, gid);
1967
 * Wrapper for chown(1) / EIO_CHOWN
1968
 */
1969
102
static void Chown(const FunctionCallbackInfo<Value>& args) {
1970
102
  Environment* env = Environment::GetCurrent(args);
1971
1972
102
  const int argc = args.Length();
1973
102
  CHECK_GE(argc, 3);
1974
1975
102
  BufferValue path(env->isolate(), args[0]);
1976
102
  CHECK_NOT_NULL(*path);
1977
1978
204
  CHECK(args[1]->IsUint32());
1979
306
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
1980
1981
204
  CHECK(args[2]->IsUint32());
1982
306
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
1983
1984
102
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1985
102
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
1986
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
1987
99
              uv_fs_chown, *path, uid, gid);
1988
  } else {  // chown(path, uid, gid, undefined, ctx)
1989
3
    CHECK_EQ(argc, 5);
1990
3
    FSReqWrapSync req_wrap_sync;
1991

5
    FS_SYNC_TRACE_BEGIN(chown);
1992
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1993
6
             uv_fs_chown, *path, uid, gid);
1994

5
    FS_SYNC_TRACE_END(chown);
1995
102
  }
1996
102
}
1997
1998
1999
/* fs.fchown(fd, uid, gid);
2000
 * Wrapper for fchown(1) / EIO_FCHOWN
2001
 */
2002
4
static void FChown(const FunctionCallbackInfo<Value>& args) {
2003
4
  Environment* env = Environment::GetCurrent(args);
2004
2005
4
  const int argc = args.Length();
2006
4
  CHECK_GE(argc, 3);
2007
2008
8
  CHECK(args[0]->IsInt32());
2009
12
  const int fd = args[0].As<Int32>()->Value();
2010
2011
8
  CHECK(args[1]->IsUint32());
2012
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2013
2014
8
  CHECK(args[2]->IsUint32());
2015
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2016
2017
4
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2018
4
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2019
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2020
2
              uv_fs_fchown, fd, uid, gid);
2021
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2022
2
    CHECK_EQ(argc, 5);
2023
2
    FSReqWrapSync req_wrap_sync;
2024

4
    FS_SYNC_TRACE_BEGIN(fchown);
2025
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2026
2
             uv_fs_fchown, fd, uid, gid);
2027

4
    FS_SYNC_TRACE_END(fchown);
2028
  }
2029
4
}
2030
2031
2032
9
static void LChown(const FunctionCallbackInfo<Value>& args) {
2033
9
  Environment* env = Environment::GetCurrent(args);
2034
2035
9
  const int argc = args.Length();
2036
9
  CHECK_GE(argc, 3);
2037
2038
9
  BufferValue path(env->isolate(), args[0]);
2039
9
  CHECK_NOT_NULL(*path);
2040
2041
18
  CHECK(args[1]->IsUint32());
2042
27
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2043
2044
18
  CHECK(args[2]->IsUint32());
2045
27
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2046
2047
9
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2048
9
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2049
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2050
7
              uv_fs_lchown, *path, uid, gid);
2051
  } else {  // lchown(path, uid, gid, undefined, ctx)
2052
2
    CHECK_EQ(argc, 5);
2053
2
    FSReqWrapSync req_wrap_sync;
2054

4
    FS_SYNC_TRACE_BEGIN(lchown);
2055
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2056
4
             uv_fs_lchown, *path, uid, gid);
2057

4
    FS_SYNC_TRACE_END(lchown);
2058
9
  }
2059
9
}
2060
2061
2062
29
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2063
29
  Environment* env = Environment::GetCurrent(args);
2064
2065
29
  const int argc = args.Length();
2066
29
  CHECK_GE(argc, 3);
2067
2068
29
  BufferValue path(env->isolate(), args[0]);
2069
29
  CHECK_NOT_NULL(*path);
2070
2071
58
  CHECK(args[1]->IsNumber());
2072
87
  const double atime = args[1].As<Number>()->Value();
2073
2074
58
  CHECK(args[2]->IsNumber());
2075
87
  const double mtime = args[2].As<Number>()->Value();
2076
2077
29
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2078
29
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2079
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2080
14
              uv_fs_utime, *path, atime, mtime);
2081
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2082
15
    CHECK_EQ(argc, 5);
2083
15
    FSReqWrapSync req_wrap_sync;
2084

17
    FS_SYNC_TRACE_BEGIN(utimes);
2085
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2086
30
             uv_fs_utime, *path, atime, mtime);
2087

17
    FS_SYNC_TRACE_END(utimes);
2088
29
  }
2089
29
}
2090
2091
1779
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2092
1779
  Environment* env = Environment::GetCurrent(args);
2093
2094
1779
  const int argc = args.Length();
2095
1779
  CHECK_GE(argc, 3);
2096
2097
3558
  CHECK(args[0]->IsInt32());
2098
5337
  const int fd = args[0].As<Int32>()->Value();
2099
2100
3558
  CHECK(args[1]->IsNumber());
2101
5337
  const double atime = args[1].As<Number>()->Value();
2102
2103
3558
  CHECK(args[2]->IsNumber());
2104
5337
  const double mtime = args[2].As<Number>()->Value();
2105
2106
1779
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2107
1779
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2108
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2109
1771
              uv_fs_futime, fd, atime, mtime);
2110
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2111
8
    CHECK_EQ(argc, 5);
2112
8
    FSReqWrapSync req_wrap_sync;
2113

10
    FS_SYNC_TRACE_BEGIN(futimes);
2114
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2115
8
             uv_fs_futime, fd, atime, mtime);
2116

10
    FS_SYNC_TRACE_END(futimes);
2117
  }
2118
1779
}
2119
2120
13
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2121
13
  Environment* env = Environment::GetCurrent(args);
2122
13
  Isolate* isolate = env->isolate();
2123
2124
13
  const int argc = args.Length();
2125
13
  CHECK_GE(argc, 2);
2126
2127
13
  BufferValue tmpl(isolate, args[0]);
2128
13
  CHECK_NOT_NULL(*tmpl);
2129
2130
13
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2131
2132
13
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2133
13
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2134
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2135
6
              uv_fs_mkdtemp, *tmpl);
2136
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2137
7
    CHECK_EQ(argc, 4);
2138
7
    FSReqWrapSync req_wrap_sync;
2139

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2140
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2141
14
             uv_fs_mkdtemp, *tmpl);
2142

9
    FS_SYNC_TRACE_END(mkdtemp);
2143
7
    const char* path = req_wrap_sync.req.path;
2144
2145
    Local<Value> error;
2146
    MaybeLocal<Value> rc =
2147
7
        StringBytes::Encode(isolate, path, encoding, &error);
2148
7
    if (rc.IsEmpty()) {
2149
      Local<Object> ctx = args[3].As<Object>();
2150
      ctx->Set(env->context(), env->error_string(), error).Check();
2151
13
      return;
2152
    }
2153

14
    args.GetReturnValue().Set(rc.ToLocalChecked());
2154
13
  }
2155
}
2156
2157
5150
void Initialize(Local<Object> target,
2158
                Local<Value> unused,
2159
                Local<Context> context,
2160
                void* priv) {
2161
5150
  Environment* env = Environment::GetCurrent(context);
2162
5150
  Isolate* isolate = env->isolate();
2163
2164
5150
  env->SetMethod(target, "access", Access);
2165
5150
  env->SetMethod(target, "close", Close);
2166
5150
  env->SetMethod(target, "open", Open);
2167
5150
  env->SetMethod(target, "openFileHandle", OpenFileHandle);
2168
5150
  env->SetMethod(target, "read", Read);
2169
5150
  env->SetMethod(target, "fdatasync", Fdatasync);
2170
5150
  env->SetMethod(target, "fsync", Fsync);
2171
5150
  env->SetMethod(target, "rename", Rename);
2172
5150
  env->SetMethod(target, "ftruncate", FTruncate);
2173
5150
  env->SetMethod(target, "rmdir", RMDir);
2174
5150
  env->SetMethod(target, "mkdir", MKDir);
2175
5150
  env->SetMethod(target, "readdir", ReadDir);
2176
5150
  env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2177
5150
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2178
5150
  env->SetMethod(target, "stat", Stat);
2179
5150
  env->SetMethod(target, "lstat", LStat);
2180
5150
  env->SetMethod(target, "fstat", FStat);
2181
5150
  env->SetMethod(target, "link", Link);
2182
5150
  env->SetMethod(target, "symlink", Symlink);
2183
5150
  env->SetMethod(target, "readlink", ReadLink);
2184
5150
  env->SetMethod(target, "unlink", Unlink);
2185
5150
  env->SetMethod(target, "writeBuffer", WriteBuffer);
2186
5150
  env->SetMethod(target, "writeBuffers", WriteBuffers);
2187
5150
  env->SetMethod(target, "writeString", WriteString);
2188
5150
  env->SetMethod(target, "realpath", RealPath);
2189
5150
  env->SetMethod(target, "copyFile", CopyFile);
2190
2191
5150
  env->SetMethod(target, "chmod", Chmod);
2192
5150
  env->SetMethod(target, "fchmod", FChmod);
2193
  // env->SetMethod(target, "lchmod", LChmod);
2194
2195
5150
  env->SetMethod(target, "chown", Chown);
2196
5150
  env->SetMethod(target, "fchown", FChown);
2197
5150
  env->SetMethod(target, "lchown", LChown);
2198
2199
5150
  env->SetMethod(target, "utimes", UTimes);
2200
5150
  env->SetMethod(target, "futimes", FUTimes);
2201
2202
5150
  env->SetMethod(target, "mkdtemp", Mkdtemp);
2203
2204
  target
2205
      ->Set(context,
2206
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2207
            Integer::New(
2208
                isolate,
2209
20600
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2210
10300
      .Check();
2211
2212
  target->Set(context,
2213
              FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2214
20600
              env->fs_stats_field_array()->GetJSArray()).Check();
2215
2216
  target->Set(context,
2217
              FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2218
20600
              env->fs_stats_field_bigint_array()->GetJSArray()).Check();
2219
2220
5150
  StatWatcher::Initialize(env, target);
2221
2222
  // Create FunctionTemplate for FSReqCallback
2223
5150
  Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
2224
10300
  fst->InstanceTemplate()->SetInternalFieldCount(1);
2225
10300
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2226
  Local<String> wrapString =
2227
5150
      FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
2228
5150
  fst->SetClassName(wrapString);
2229
  target
2230
      ->Set(context, wrapString,
2231
20600
            fst->GetFunction(env->context()).ToLocalChecked())
2232
10300
      .Check();
2233
2234
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2235
  // to do anything in the constructor, so we only store the instance template.
2236
5150
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2237
10300
  fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2238
10300
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2239
  Local<String> fhWrapString =
2240
5150
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2241
5150
  fh_rw->SetClassName(fhWrapString);
2242
  env->set_filehandlereadwrap_template(
2243
5150
      fst->InstanceTemplate());
2244
2245
  // Create Function Template for FSReqPromise
2246
5150
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2247
10300
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2248
  Local<String> promiseString =
2249
5150
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2250
5150
  fpt->SetClassName(promiseString);
2251
5150
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2252
5150
  fpo->SetInternalFieldCount(1);
2253
5150
  env->set_fsreqpromise_constructor_template(fpo);
2254
2255
  // Create FunctionTemplate for FileHandle
2256
5150
  Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2257
10300
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2258
5150
  env->SetProtoMethod(fd, "close", FileHandle::Close);
2259
5150
  env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2260
5150
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2261
5150
  fdt->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
2262
  Local<String> handleString =
2263
5150
       FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2264
5150
  fd->SetClassName(handleString);
2265
5150
  StreamBase::AddMethods(env, fd);
2266
  target
2267
      ->Set(context, handleString,
2268
20600
            fd->GetFunction(env->context()).ToLocalChecked())
2269
10300
      .Check();
2270
5150
  env->set_fd_constructor_template(fdt);
2271
2272
  // Create FunctionTemplate for FileHandle::CloseReq
2273
5150
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2274
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2275
10300
                        "FileHandleCloseReq"));
2276
10300
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2277
5150
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2278
5150
  fdcloset->SetInternalFieldCount(1);
2279
5150
  env->set_fdclose_constructor_template(fdcloset);
2280
2281
  Local<Symbol> use_promises_symbol =
2282
    Symbol::New(isolate,
2283
5150
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2284
5150
  env->set_fs_use_promises_symbol(use_promises_symbol);
2285
  target->Set(context,
2286
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2287
15450
              use_promises_symbol).Check();
2288
5150
}
2289
2290
}  // namespace fs
2291
2292
}  // end namespace node
2293
2294

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