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: 1236 1315 94.0 %
Date: 2019-09-26 22:31:05 Branches: 790 1196 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
144182
inline int64_t GetOffset(Local<Value> value) {
92

158630
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
93
}
94
95
#define TRACE_NAME(name) "fs.sync." #name
96
#define GET_TRACE_ENABLED                                                  \
97
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED                             \
98
  (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
99
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                  \
100
  if (GET_TRACE_ENABLED)                                                   \
101
  TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
102
  ##__VA_ARGS__);
103
#define FS_SYNC_TRACE_END(syscall, ...)                                    \
104
  if (GET_TRACE_ENABLED)                                                   \
105
  TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall),   \
106
  ##__VA_ARGS__);
107
108
// We sometimes need to convert a C++ lambda function to a raw C-style function.
109
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
110
// functions, and thus does not wrap them properly.
111
typedef void(*uv_fs_callback_t)(uv_fs_t*);
112
113
// The FileHandle object wraps a file descriptor and will close it on garbage
114
// collection if necessary. If that happens, a process warning will be
115
// emitted (or a fatal exception will occur if the fd cannot be closed.)
116
83
FileHandle::FileHandle(Environment* env, Local<Object> obj, int fd)
117
    : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE),
118
      StreamBase(env),
119
83
      fd_(fd) {
120
83
  MakeWeak();
121
83
  StreamBase::AttachToObject(GetObject());
122
83
}
123
124
83
FileHandle* FileHandle::New(Environment* env, int fd, Local<Object> obj) {
125

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

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

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

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

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

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







59983
  CHECK_NOT_NULL(req_wrap);
702
59983
  req_wrap->Init(syscall, dest, len, enc);
703
59983
  int err = req_wrap->Dispatch(fn, fn_args..., after);
704







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







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

6981
    FS_SYNC_TRACE_BEGIN(access);
791
13958
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
792

6981
    FS_SYNC_TRACE_END(access);
793
7039
  }
794
7039
}
795
796
797
63314
void Close(const FunctionCallbackInfo<Value>& args) {
798
63314
  Environment* env = Environment::GetCurrent(args);
799
800
63314
  const int argc = args.Length();
801
63314
  CHECK_GE(argc, 2);
802
803
126628
  CHECK(args[0]->IsInt32());
804
189942
  int fd = args[0].As<Int32>()->Value();
805
806
63314
  FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
807
63314
  if (req_wrap_async != nullptr) {  // close(fd, req)
808
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
809
7566
              uv_fs_close, fd);
810
  } else {  // close(fd, undefined, ctx)
811
55748
    CHECK_EQ(argc, 3);
812
55748
    FSReqWrapSync req_wrap_sync;
813

55808
    FS_SYNC_TRACE_BEGIN(close);
814
55748
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
815

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

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

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

32646
    FS_SYNC_TRACE_BEGIN(stat);
929
65288
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
930

32646
    FS_SYNC_TRACE_END(stat);
931
32644
    if (err != 0) {
932
34647
      return;  // error info is in ctx
933
    }
934
935
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
936
32638
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
937

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

117063
    FS_SYNC_TRACE_BEGIN(lstat);
959
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
960
234058
                       *path);
961

117063
    FS_SYNC_TRACE_END(lstat);
962
117029
    if (err != 0) {
963
122536
      return;  // error info is in ctx
964
    }
965
966
    Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
967
116765
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
968

233530
    args.GetReturnValue().Set(arr);
969
122008
  }
970
}
971
972
51958
static void FStat(const FunctionCallbackInfo<Value>& args) {
973
51958
  Environment* env = Environment::GetCurrent(args);
974
975
51958
  const int argc = args.Length();
976
51958
  CHECK_GE(argc, 2);
977
978
103916
  CHECK(args[0]->IsInt32());
979
155874
  int fd = args[0].As<Int32>()->Value();
980
981
103916
  bool use_bigint = args[1]->IsTrue();
982
103916
  FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
983
51958
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
984
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
985
2808
              uv_fs_fstat, fd);
986
  } else {  // fstat(fd, use_bigint, undefined, ctx)
987
49150
    CHECK_EQ(argc, 4);
988
49150
    FSReqWrapSync req_wrap_sync;
989

49160
    FS_SYNC_TRACE_BEGIN(fstat);
990
49150
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
991

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

86
    FS_SYNC_TRACE_BEGIN(symlink);
1025
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1026
164
             uv_fs_symlink, *target, *path, flags);
1027

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

11
    FS_SYNC_TRACE_BEGIN(link);
1052
    SyncCall(env, args[3], &req_wrap_sync, "link",
1053
10
             uv_fs_link, *src, *dest);
1054

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

48
    FS_SYNC_TRACE_BEGIN(readlink);
1078
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1079
92
                       uv_fs_readlink, *path);
1080

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

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

7
    FS_SYNC_TRACE_BEGIN(rename);
1122
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1123
10
             *old_path, *new_path);
1124

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

16
    FS_SYNC_TRACE_BEGIN(ftruncate);
1148
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1149
14
             len);
1150

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

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

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

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

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

3618
    FS_SYNC_TRACE_BEGIN(unlink);
1215
7116
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1216

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

3857
    FS_SYNC_TRACE_BEGIN(rmdir);
1237
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1238
7702
             uv_fs_rmdir, *path);
1239

3857
    FS_SYNC_TRACE_END(rmdir);
1240
3895
  }
1241
3895
}
1242
1243
5086
int MKDirpSync(uv_loop_t* loop,
1244
               uv_fs_t* req,
1245
               const std::string& path,
1246
               int mode,
1247
               uv_fs_cb cb) {
1248
5086
  FSContinuationData continuation_data(req, mode, cb);
1249
5086
  continuation_data.PushPath(std::move(path));
1250
1251
5086
  while (continuation_data.paths.size() > 0) {
1252
5136
    std::string next_path = continuation_data.PopPath();
1253
5136
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1254
    while (true) {
1255

5137
      switch (err) {
1256
        case 0:
1257
49
          if (continuation_data.paths.size() == 0) {
1258
25
            return 0;
1259
          }
1260
24
          break;
1261
        case UV_ENOENT: {
1262
          std::string dirname = next_path.substr(0,
1263
26
                                        next_path.find_last_of(kPathSeparator));
1264
26
          if (dirname != next_path) {
1265
25
            continuation_data.PushPath(std::move(next_path));
1266
25
            continuation_data.PushPath(std::move(dirname));
1267
1
          } else if (continuation_data.paths.size() == 0) {
1268
1
            err = UV_EEXIST;
1269
1
            continue;
1270
          }
1271
25
          break;
1272
        }
1273
        case UV_EPERM: {
1274
          return err;
1275
        }
1276
        default:
1277
5062
          uv_fs_req_cleanup(req);
1278
5062
          int orig_err = err;
1279
5062
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1280

5062
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1281
1
            uv_fs_req_cleanup(req);
1282

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

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

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

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

2142
    FS_SYNC_TRACE_BEGIN(mkdir);
1411
2138
    if (mkdirp) {
1412
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1413
22
               MKDirpSync, *path, mode);
1414
    } else {
1415
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1416
4254
               uv_fs_mkdir, *path, mode);
1417
    }
1418

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

22
    FS_SYNC_TRACE_BEGIN(realpath);
1442
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1443
40
                       uv_fs_realpath, *path);
1444

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

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

15950
    FS_SYNC_TRACE_BEGIN(readdir);
1493
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1494
31896
                       uv_fs_scandir, *path, 0 /*flags*/);
1495

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

56490
    FS_SYNC_TRACE_BEGIN(open);
1578
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1579
112836
                          uv_fs_open, *path, flags, mode);
1580

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

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

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

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

22
    FS_SYNC_TRACE_BEGIN(copyfile);
1646
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1647
40
             uv_fs_copyfile, *src, *dest, flags);
1648

22
    FS_SYNC_TRACE_END(copyfile);
1649
35
  }
1650
35
}
1651
1652
1653
// Wrapper for write(2).
1654
//
1655
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1656
// 0 fd        integer. file descriptor
1657
// 1 buffer    the data to write
1658
// 2 offset    where in the buffer to start from
1659
// 3 length    how much to write
1660
// 4 position  if integer, position to write at in the file.
1661
//             if null, write from the current position
1662
142788
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1663
142788
  Environment* env = Environment::GetCurrent(args);
1664
1665
142788
  const int argc = args.Length();
1666
142788
  CHECK_GE(argc, 4);
1667
1668
285576
  CHECK(args[0]->IsInt32());
1669
428364
  const int fd = args[0].As<Int32>()->Value();
1670
1671
142788
  CHECK(Buffer::HasInstance(args[1]));
1672
285576
  Local<Object> buffer_obj = args[1].As<Object>();
1673
142788
  char* buffer_data = Buffer::Data(buffer_obj);
1674
142788
  size_t buffer_length = Buffer::Length(buffer_obj);
1675
1676
142788
  CHECK(IsSafeJsInt(args[2]));
1677
428364
  const int64_t off_64 = args[2].As<Integer>()->Value();
1678
142788
  CHECK_GE(off_64, 0);
1679
142788
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1680
142788
  const size_t off = static_cast<size_t>(off_64);
1681
1682
285576
  CHECK(args[3]->IsInt32());
1683
428364
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1684
142788
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1685
142788
  CHECK_LE(len, buffer_length);
1686
142788
  CHECK_GE(off + len, off);
1687
1688
142788
  const int64_t pos = GetOffset(args[4]);
1689
1690
142788
  char* buf = buffer_data + off;
1691
142788
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1692
1693
142788
  FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1694
142788
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1695
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1696
16602
              uv_fs_write, fd, &uvbuf, 1, pos);
1697
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1698
126186
    CHECK_EQ(argc, 7);
1699
126186
    FSReqWrapSync req_wrap_sync;
1700

126236
    FS_SYNC_TRACE_BEGIN(write);
1701
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1702
126186
                                uv_fs_write, fd, &uvbuf, 1, pos);
1703

126236
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1704
378558
    args.GetReturnValue().Set(bytesWritten);
1705
  }
1706
142788
}
1707
1708
1709
// Wrapper for writev(2).
1710
//
1711
// bytesWritten = writev(fd, chunks, position, callback)
1712
// 0 fd        integer. file descriptor
1713
// 1 chunks    array of buffers to write
1714
// 2 position  if integer, position to write at in the file.
1715
//             if null, write from the current position
1716
28
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1717
28
  Environment* env = Environment::GetCurrent(args);
1718
1719
28
  const int argc = args.Length();
1720
28
  CHECK_GE(argc, 3);
1721
1722
56
  CHECK(args[0]->IsInt32());
1723
84
  const int fd = args[0].As<Int32>()->Value();
1724
1725
56
  CHECK(args[1]->IsArray());
1726
56
  Local<Array> chunks = args[1].As<Array>();
1727
1728
28
  int64_t pos = GetOffset(args[2]);
1729
1730
28
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1731
1732
148746
  for (uint32_t i = 0; i < iovs.length(); i++) {
1733
446154
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
1734
148718
    CHECK(Buffer::HasInstance(chunk));
1735
148718
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1736
  }
1737
1738
28
  FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1739
28
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
1740
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1741
24
              uv_fs_write, fd, *iovs, iovs.length(), pos);
1742
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
1743
4
    CHECK_EQ(argc, 5);
1744
4
    FSReqWrapSync req_wrap_sync;
1745

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1749
12
    args.GetReturnValue().Set(bytesWritten);
1750
28
  }
1751
28
}
1752
1753
1754
// Wrapper for write(2).
1755
//
1756
// bytesWritten = write(fd, string, position, enc, callback)
1757
// 0 fd        integer. file descriptor
1758
// 1 string    non-buffer values are converted to strings
1759
// 2 position  if integer, position to write at in the file.
1760
//             if null, write from the current position
1761
// 3 enc       encoding of string
1762
1366
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1763
1366
  Environment* env = Environment::GetCurrent(args);
1764
1366
  Isolate* isolate = env->isolate();
1765
1766
1366
  const int argc = args.Length();
1767
1366
  CHECK_GE(argc, 4);
1768
1769
2732
  CHECK(args[0]->IsInt32());
1770
4098
  const int fd = args[0].As<Int32>()->Value();
1771
1772
1366
  const int64_t pos = GetOffset(args[2]);
1773
1774
1366
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
1775
1776
1366
  Local<Value> value = args[1];
1777
1366
  char* buf = nullptr;
1778
  size_t len;
1779
1780
1366
  FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1781
1366
  const bool is_async = req_wrap_async != nullptr;
1782
1783
  // Avoid copying the string when it is externalized but only when:
1784
  // 1. The target encoding is compatible with the string's encoding, and
1785
  // 2. The write is synchronous, otherwise the string might get neutered
1786
  //    while the request is in flight, and
1787
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
1788
  //    need to call StringBytes::Write() to ensure proper byte swapping.
1789
  // The const_casts are conceptually sound: memory is read but not written.
1790

3816
  if (!is_async && value->IsString()) {
1791
1225
    auto string = value.As<String>();
1792


1226
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1793
1
      auto ext = string->GetExternalOneByteStringResource();
1794
1
      buf = const_cast<char*>(ext->data());
1795
1
      len = ext->length();
1796


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

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

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

108036
    FS_SYNC_TRACE_BEGIN(read);
1902
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1903
108026
                                   uv_fs_read, fd, &uvbuf, 1, pos);
1904

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

16
    FS_SYNC_TRACE_BEGIN(chmod);
1933
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
1934
28
             uv_fs_chmod, *path, mode);
1935

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

7
    FS_SYNC_TRACE_BEGIN(fchmod);
1963
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
1964
5
             uv_fs_fchmod, fd, mode);
1965

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

5
    FS_SYNC_TRACE_BEGIN(chown);
1996
    SyncCall(env, args[4], &req_wrap_sync, "chown",
1997
6
             uv_fs_chown, *path, uid, gid);
1998

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

4
    FS_SYNC_TRACE_BEGIN(fchown);
2029
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2030
2
             uv_fs_fchown, fd, uid, gid);
2031

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

4
    FS_SYNC_TRACE_BEGIN(lchown);
2059
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2060
4
             uv_fs_lchown, *path, uid, gid);
2061

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

17
    FS_SYNC_TRACE_BEGIN(utimes);
2089
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2090
30
             uv_fs_utime, *path, atime, mtime);
2091

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

10
    FS_SYNC_TRACE_BEGIN(futimes);
2118
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2119
8
             uv_fs_futime, fd, atime, mtime);
2120

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

9
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2144
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2145
14
             uv_fs_mkdtemp, *tmpl);
2146

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

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

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