GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.cc Lines: 1512 1596 94.7 %
Date: 2022-09-22 04:22:24 Branches: 985 1450 67.9 %

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

28
  if (str_size >= extension.size() &&
102
14
      str.compare(str.size() - extension.size(),
103
        extension.size(), extension) == 0) {
104
    str_size -= extension.size();
105
  }
106
107
14
  return str.substr(start_pos, str_size);
108
}
109
110
222857
inline int64_t GetOffset(Local<Value> value) {
111
223957
  return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
112
}
113
114
90
static const char* get_fs_func_name_by_type(uv_fs_type req_type) {
115








90
  switch (req_type) {
116
#define FS_TYPE_TO_NAME(type, name)                                            \
117
  case UV_FS_##type:                                                           \
118
    return name;
119
10
    FS_TYPE_TO_NAME(OPEN, "open")
120
10
    FS_TYPE_TO_NAME(CLOSE, "close")
121
4
    FS_TYPE_TO_NAME(READ, "read")
122
6
    FS_TYPE_TO_NAME(WRITE, "write")
123
    FS_TYPE_TO_NAME(SENDFILE, "sendfile")
124
2
    FS_TYPE_TO_NAME(STAT, "stat")
125
2
    FS_TYPE_TO_NAME(LSTAT, "lstat")
126
4
    FS_TYPE_TO_NAME(FSTAT, "fstat")
127
2
    FS_TYPE_TO_NAME(FTRUNCATE, "ftruncate")
128
2
    FS_TYPE_TO_NAME(UTIME, "utime")
129
2
    FS_TYPE_TO_NAME(FUTIME, "futime")
130
2
    FS_TYPE_TO_NAME(ACCESS, "access")
131
2
    FS_TYPE_TO_NAME(CHMOD, "chmod")
132
2
    FS_TYPE_TO_NAME(FCHMOD, "fchmod")
133
2
    FS_TYPE_TO_NAME(FSYNC, "fsync")
134
2
    FS_TYPE_TO_NAME(FDATASYNC, "fdatasync")
135
5
    FS_TYPE_TO_NAME(UNLINK, "unlink")
136
6
    FS_TYPE_TO_NAME(RMDIR, "rmdir")
137
1
    FS_TYPE_TO_NAME(MKDIR, "mkdir")
138
2
    FS_TYPE_TO_NAME(MKDTEMP, "mkdtemp")
139
2
    FS_TYPE_TO_NAME(RENAME, "rename")
140
2
    FS_TYPE_TO_NAME(SCANDIR, "scandir")
141
2
    FS_TYPE_TO_NAME(LINK, "link")
142
2
    FS_TYPE_TO_NAME(SYMLINK, "symlink")
143
2
    FS_TYPE_TO_NAME(READLINK, "readlink")
144
2
    FS_TYPE_TO_NAME(CHOWN, "chown")
145
2
    FS_TYPE_TO_NAME(FCHOWN, "fchown")
146
2
    FS_TYPE_TO_NAME(REALPATH, "realpath")
147
2
    FS_TYPE_TO_NAME(COPYFILE, "copyfile")
148
2
    FS_TYPE_TO_NAME(LCHOWN, "lchown")
149
    FS_TYPE_TO_NAME(STATFS, "statfs")
150
    FS_TYPE_TO_NAME(MKSTEMP, "mkstemp")
151
2
    FS_TYPE_TO_NAME(LUTIME, "lutime")
152
#undef FS_TYPE_TO_NAME
153
    default:
154
      return "unknow";
155
  }
156
}
157
158
#define TRACE_NAME(name) "fs.sync." #name
159
#define GET_TRACE_ENABLED                                                      \
160
  (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                                \
161
       TRACING_CATEGORY_NODE2(fs, sync)) != 0)
162
#define FS_SYNC_TRACE_BEGIN(syscall, ...)                                      \
163
  if (GET_TRACE_ENABLED)                                                       \
164
    TRACE_EVENT_BEGIN(                                                         \
165
        TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
166
#define FS_SYNC_TRACE_END(syscall, ...)                                        \
167
  if (GET_TRACE_ENABLED)                                                       \
168
    TRACE_EVENT_END(                                                           \
169
        TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
170
171
#define FS_ASYNC_TRACE_BEGIN0(fs_type, id)                                     \
172
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(TRACING_CATEGORY_NODE2(fs, async),         \
173
                                    get_fs_func_name_by_type(fs_type),         \
174
                                    id);
175
176
#define FS_ASYNC_TRACE_END0(fs_type, id)                                       \
177
  TRACE_EVENT_NESTABLE_ASYNC_END0(TRACING_CATEGORY_NODE2(fs, async),           \
178
                                  get_fs_func_name_by_type(fs_type),           \
179
                                  id);
180
181
#define FS_ASYNC_TRACE_BEGIN1(fs_type, id, name, value)                        \
182
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE2(fs, async),         \
183
                                    get_fs_func_name_by_type(fs_type),         \
184
                                    id,                                        \
185
                                    name,                                      \
186
                                    value);
187
188
#define FS_ASYNC_TRACE_END1(fs_type, id, name, value)                          \
189
  TRACE_EVENT_NESTABLE_ASYNC_END1(TRACING_CATEGORY_NODE2(fs, async),           \
190
                                  get_fs_func_name_by_type(fs_type),           \
191
                                  id,                                          \
192
                                  name,                                        \
193
                                  value);
194
195
#define FS_ASYNC_TRACE_BEGIN2(fs_type, id, name1, value1, name2, value2)       \
196
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(fs, async),         \
197
                                    get_fs_func_name_by_type(fs_type),         \
198
                                    id,                                        \
199
                                    name1,                                     \
200
                                    value1,                                    \
201
                                    name2,                                     \
202
                                    value2);
203
204
#define FS_ASYNC_TRACE_END2(fs_type, id, name1, value1, name2, value2)         \
205
  TRACE_EVENT_NESTABLE_ASYNC_END2(TRACING_CATEGORY_NODE2(fs, async),           \
206
                                  get_fs_func_name_by_type(fs_type),           \
207
                                  id,                                          \
208
                                  name1,                                       \
209
                                  value1,                                      \
210
                                  name2,                                       \
211
                                  value2);
212
213
// We sometimes need to convert a C++ lambda function to a raw C-style function.
214
// This is helpful, because ReqWrap::Dispatch() does not recognize lambda
215
// functions, and thus does not wrap them properly.
216
typedef void(*uv_fs_callback_t)(uv_fs_t*);
217
218
219
void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
220
  tracker->TrackField("paths", paths_);
221
}
222
223
FileHandleReadWrap::~FileHandleReadWrap() = default;
224
225
FSReqBase::~FSReqBase() = default;
226
227
2
void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
228
2
  tracker->TrackField("continuation_data", continuation_data_);
229
2
}
230
231
// The FileHandle object wraps a file descriptor and will close it on garbage
232
// collection if necessary. If that happens, a process warning will be
233
// emitted (or a fatal exception will occur if the fd cannot be closed.)
234
1379
FileHandle::FileHandle(BindingData* binding_data,
235
1379
                       Local<Object> obj, int fd)
236
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
237
      StreamBase(env()),
238
      fd_(fd),
239
1379
      binding_data_(binding_data) {
240
1379
  MakeWeak();
241
1379
  StreamBase::AttachToObject(GetObject());
242
1379
}
243
244
1379
FileHandle* FileHandle::New(BindingData* binding_data,
245
                            int fd, Local<Object> obj) {
246
1379
  Environment* env = binding_data->env();
247
2743
  if (obj.IsEmpty() && !env->fd_constructor_template()
248
2743
                            ->NewInstance(env->context())
249
1364
                            .ToLocal(&obj)) {
250
    return nullptr;
251
  }
252
1379
  return new FileHandle(binding_data, obj, fd);
253
}
254
255
15
void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
256
15
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
257
15
  Environment* env = binding_data->env();
258
15
  CHECK(args.IsConstructCall());
259
15
  CHECK(args[0]->IsInt32());
260
261
  FileHandle* handle =
262
30
      FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
263
15
  if (handle == nullptr) return;
264
15
  if (args[1]->IsNumber())
265
30
    handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
266
15
  if (args[2]->IsNumber())
267
30
    handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
268
}
269
270
5336
FileHandle::~FileHandle() {
271
2668
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
272
2668
  Close();           // Close synchronously and emit warning
273
2668
  CHECK(closed_);    // We have to be closed at the point
274
5336
}
275
276
int FileHandle::DoWrite(WriteWrap* w,
277
                        uv_buf_t* bufs,
278
                        size_t count,
279
                        uv_stream_t* send_handle) {
280
  return UV_ENOSYS;  // Not implemented (yet).
281
}
282
283
void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
284
  tracker->TrackField("current_read", current_read_);
285
}
286
287
10
FileHandle::TransferMode FileHandle::GetTransferMode() const {
288

10
  return reading_ || closing_ || closed_ ?
289
10
      TransferMode::kUntransferable : TransferMode::kTransferable;
290
}
291
292
6
std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
293
6
  CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
294
12
  auto ret = std::make_unique<TransferData>(fd_);
295
6
  closed_ = true;
296
6
  return ret;
297
}
298
299
6
FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
300
301
24
FileHandle::TransferData::~TransferData() {
302
12
  if (fd_ > 0) {
303
    uv_fs_t close_req;
304
8
    CHECK_NE(fd_, -1);
305
8
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
306
8
    uv_fs_req_cleanup(&close_req);
307
  }
308
24
}
309
310
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
311
    Environment* env,
312
    v8::Local<v8::Context> context,
313
    std::unique_ptr<worker::TransferData> self) {
314
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
315
2
  if (bd == nullptr) return {};
316
317
2
  int fd = fd_;
318
2
  fd_ = -1;
319
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
320
}
321
322
// Close the file descriptor if it hasn't already been closed. A process
323
// warning will be emitted using a SetImmediate to avoid calling back to
324
// JS during GC. If closing the fd fails at this point, a fatal exception
325
// will crash the process immediately.
326
1334
inline void FileHandle::Close() {
327

1334
  if (closed_ || closing_) return;
328
  uv_fs_t req;
329
20
  CHECK_NE(fd_, -1);
330
20
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
331
20
  uv_fs_req_cleanup(&req);
332
333
  struct err_detail { int ret; int fd; };
334
335
20
  err_detail detail { ret, fd_ };
336
337
20
  AfterClose();
338
339
20
  if (ret < 0) {
340
    // Do not unref this
341
    env()->SetImmediate([detail](Environment* env) {
342
      char msg[70];
343
      snprintf(msg, arraysize(msg),
344
              "Closing file descriptor %d on garbage collection failed",
345
              detail.fd);
346
      // This exception will end up being fatal for the process because
347
      // it is being thrown from within the SetImmediate handler and
348
      // there is no JS stack to bubble it to. In other words, tearing
349
      // down the process is the only reasonable thing we can do here.
350
      HandleScope handle_scope(env->isolate());
351
      env->ThrowUVException(detail.ret, "close", msg);
352
    });
353
    return;
354
  }
355
356
  // If the close was successful, we still want to emit a process warning
357
  // to notify that the file descriptor was gc'd. We want to be noisy about
358
  // this because not explicitly closing the FileHandle is a bug.
359
360
20
  env()->SetImmediate([detail](Environment* env) {
361
    ProcessEmitWarning(env,
362
                       "Closing file descriptor %d on garbage collection",
363
4
                       detail.fd);
364
4
    if (env->filehandle_close_warning()) {
365
3
      env->set_filehandle_close_warning(false);
366
3
      USE(ProcessEmitDeprecationWarning(
367
          env,
368
          "Closing a FileHandle object on garbage collection is deprecated. "
369
          "Please close FileHandle objects explicitly using "
370
          "FileHandle.prototype.close(). In the future, an error will be "
371
          "thrown if a file descriptor is closed during garbage collection.",
372
3
          "DEP0137"));
373
    }
374
4
  }, CallbackFlags::kUnrefed);
375
}
376
377
1342
void FileHandle::CloseReq::Resolve() {
378
1342
  Isolate* isolate = env()->isolate();
379
2650
  HandleScope scope(isolate);
380
1342
  Context::Scope context_scope(env()->context());
381
1342
  InternalCallbackScope callback_scope(this);
382
2684
  Local<Promise> promise = promise_.Get(isolate);
383
1342
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
384
4026
  resolver->Resolve(env()->context(), Undefined(isolate)).Check();
385
1308
}
386
387
1
void FileHandle::CloseReq::Reject(Local<Value> reason) {
388
1
  Isolate* isolate = env()->isolate();
389
2
  HandleScope scope(isolate);
390
1
  Context::Scope context_scope(env()->context());
391
1
  InternalCallbackScope callback_scope(this);
392
2
  Local<Promise> promise = promise_.Get(isolate);
393
1
  Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
394
2
  resolver->Reject(env()->context(), reason).Check();
395
1
}
396
397
1343
FileHandle* FileHandle::CloseReq::file_handle() {
398
1343
  Isolate* isolate = env()->isolate();
399
1343
  HandleScope scope(isolate);
400
2686
  Local<Value> val = ref_.Get(isolate);
401
1343
  Local<Object> obj = val.As<Object>();
402
1343
  return Unwrap<FileHandle>(obj);
403
}
404
405
1343
FileHandle::CloseReq::CloseReq(Environment* env,
406
                               Local<Object> obj,
407
                               Local<Promise> promise,
408
1343
                               Local<Value> ref)
409
1343
  : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
410
1343
  promise_.Reset(env->isolate(), promise);
411
1343
  ref_.Reset(env->isolate(), ref);
412
1343
}
413
414
10472
FileHandle::CloseReq::~CloseReq() {
415
2618
  uv_fs_req_cleanup(req());
416
2618
  promise_.Reset();
417
2618
  ref_.Reset();
418
5236
}
419
420
void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
421
  tracker->TrackField("promise", promise_);
422
  tracker->TrackField("ref", ref_);
423
}
424
425
426
427
// Closes this FileHandle asynchronously and returns a Promise that will be
428
// resolved when the callback is invoked, or rejects with a UVException if
429
// there was a problem closing the fd. This is the preferred mechanism for
430
// closing the FD object even tho the object will attempt to close
431
// automatically on gc.
432
1343
MaybeLocal<Promise> FileHandle::ClosePromise() {
433
1343
  Isolate* isolate = env()->isolate();
434
1343
  EscapableHandleScope scope(isolate);
435
1343
  Local<Context> context = env()->context();
436
437
  Local<Value> close_resolver =
438
4029
      object()->GetInternalField(FileHandle::kClosingPromiseSlot);
439

4029
  if (!close_resolver.IsEmpty() && !close_resolver->IsUndefined()) {
440
    CHECK(close_resolver->IsPromise());
441
    return close_resolver.As<Promise>();
442
  }
443
444
1343
  CHECK(!closed_);
445
1343
  CHECK(!closing_);
446
1343
  CHECK(!reading_);
447
448
1343
  auto maybe_resolver = Promise::Resolver::New(context);
449
1343
  CHECK(!maybe_resolver.IsEmpty());
450
1343
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
451
1343
  Local<Promise> promise = resolver.As<Promise>();
452
453
  Local<Object> close_req_obj;
454
1343
  if (!env()->fdclose_constructor_template()
455
2686
          ->NewInstance(env()->context()).ToLocal(&close_req_obj)) {
456
    return MaybeLocal<Promise>();
457
  }
458
1343
  closing_ = true;
459
2686
  object()->SetInternalField(FileHandle::kClosingPromiseSlot, promise);
460
461
2686
  CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
462
2686
  auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
463
1343
    BaseObjectPtr<CloseReq> close(CloseReq::from_req(req));
464
1343
    CHECK(close);
465
1343
    close->file_handle()->AfterClose();
466
1343
    if (!close->env()->can_call_into_js()) return;
467
1343
    Isolate* isolate = close->env()->isolate();
468
1343
    if (req->result < 0) {
469
2
      HandleScope handle_scope(isolate);
470
2
      close->Reject(
471
1
          UVException(isolate, static_cast<int>(req->result), "close"));
472
    } else {
473
1342
      close->Resolve();
474
    }
475
  }};
476
1343
  CHECK_NE(fd_, -1);
477
1343
  int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
478
1343
  if (ret < 0) {
479
    req->Reject(UVException(isolate, ret, "close"));
480
    delete req;
481
  }
482
483
1343
  return scope.Escape(promise);
484
}
485
486
1343
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
487
  FileHandle* fd;
488
1343
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
489
  Local<Promise> ret;
490
2686
  if (!fd->ClosePromise().ToLocal(&ret)) return;
491
2686
  args.GetReturnValue().Set(ret);
492
}
493
494
495
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
496
  FileHandle* fd;
497
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
498
  // Just act as if this FileHandle has been closed.
499
8
  fd->AfterClose();
500
}
501
502
503
1371
void FileHandle::AfterClose() {
504
1371
  closing_ = false;
505
1371
  closed_ = true;
506
1371
  fd_ = -1;
507

1371
  if (reading_ && !persistent().IsEmpty())
508
    EmitRead(UV_EOF);
509
1371
}
510
511
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
512
  tracker->TrackField("buffer", buffer_);
513
  tracker->TrackField("file_handle", this->file_handle_);
514
}
515
516
18
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
517
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
518
18
    file_handle_(handle) {}
519
520
227
int FileHandle::ReadStart() {
521

227
  if (!IsAlive() || IsClosing())
522
    return UV_EOF;
523
524
227
  reading_ = true;
525
526
227
  if (current_read_)
527
9
    return 0;
528
529
436
  BaseObjectPtr<FileHandleReadWrap> read_wrap;
530
531
218
  if (read_length_ == 0) {
532
5
    EmitRead(UV_EOF);
533
5
    return 0;
534
  }
535
536
  {
537
    // Create a new FileHandleReadWrap or re-use one.
538
    // Either way, we need these two scopes for AsyncReset() or otherwise
539
    // for creating the new instance.
540
213
    HandleScope handle_scope(env()->isolate());
541
213
    AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
542
543
213
    auto& freelist = binding_data_->file_handle_read_wrap_freelist;
544
213
    if (freelist.size() > 0) {
545
195
      read_wrap = std::move(freelist.back());
546
195
      freelist.pop_back();
547
      // Use a fresh async resource.
548
      // Lifetime is ensured via AsyncWrap::resource_.
549
195
      Local<Object> resource = Object::New(env()->isolate());
550
195
      USE(resource->Set(
551
585
          env()->context(), env()->handle_string(), read_wrap->object()));
552
195
      read_wrap->AsyncReset(resource);
553
195
      read_wrap->file_handle_ = this;
554
    } else {
555
      Local<Object> wrap_obj;
556
36
      if (!env()
557
18
               ->filehandlereadwrap_template()
558
18
               ->NewInstance(env()->context())
559
18
               .ToLocal(&wrap_obj)) {
560
        return UV_EBUSY;
561
      }
562
18
      read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
563
    }
564
  }
565
213
  int64_t recommended_read = 65536;
566

213
  if (read_length_ >= 0 && read_length_ <= recommended_read)
567
7
    recommended_read = read_length_;
568
569
213
  read_wrap->buffer_ = EmitAlloc(recommended_read);
570
571
213
  current_read_ = std::move(read_wrap);
572
573
426
  current_read_->Dispatch(uv_fs_read,
574
                          fd_,
575
213
                          &current_read_->buffer_,
576
                          1,
577
                          read_offset_,
578
213
                          uv_fs_callback_t{[](uv_fs_t* req) {
579
    FileHandle* handle;
580
    {
581
213
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
582
213
      handle = req_wrap->file_handle_;
583
213
      CHECK_EQ(handle->current_read_.get(), req_wrap);
584
    }
585
586
    // ReadStart() checks whether current_read_ is set to determine whether
587
    // a read is in progress. Moving it into a local variable makes sure that
588
    // the ReadStart() call below doesn't think we're still actively reading.
589
    BaseObjectPtr<FileHandleReadWrap> read_wrap =
590
426
        std::move(handle->current_read_);
591
592
213
    ssize_t result = req->result;
593
213
    uv_buf_t buffer = read_wrap->buffer_;
594
595
213
    uv_fs_req_cleanup(req);
596
597
    // Push the read wrap back to the freelist, or let it be destroyed
598
    // once we’re exiting the current scope.
599
213
    constexpr size_t kWantedFreelistFill = 100;
600
213
    auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
601
213
    if (freelist.size() < kWantedFreelistFill) {
602
213
      read_wrap->Reset();
603
213
      freelist.emplace_back(std::move(read_wrap));
604
    }
605
606
213
    if (result >= 0) {
607
      // Read at most as many bytes as we originally planned to.
608

212
      if (handle->read_length_ >= 0 && handle->read_length_ < result)
609
        result = handle->read_length_;
610
611
      // If we read data and we have an expected length, decrease it by
612
      // how much we have read.
613
212
      if (handle->read_length_ >= 0)
614
9
        handle->read_length_ -= result;
615
616
      // If we have an offset, increase it by how much we have read.
617
212
      if (handle->read_offset_ >= 0)
618
204
        handle->read_offset_ += result;
619
    }
620
621
    // Reading 0 bytes from a file always means EOF, or that we reached
622
    // the end of the requested range.
623
213
    if (result == 0)
624
10
      result = UV_EOF;
625
626
213
    handle->EmitRead(result, buffer);
627
628
    // Start over, if EmitRead() didn’t tell us to stop.
629
213
    if (handle->reading_)
630
3
      handle->ReadStart();
631
213
  }});
632
633
213
  return 0;
634
}
635
636
230
int FileHandle::ReadStop() {
637
230
  reading_ = false;
638
230
  return 0;
639
}
640
641
typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
642
643
3
ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
644
3
  return new FileHandleCloseWrap(this, object);
645
}
646
647
3
int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
648

3
  if (closing_ || closed_) {
649
3
    req_wrap->Done(0);
650
3
    return 1;
651
  }
652
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
653
  closing_ = true;
654
  CHECK_NE(fd_, -1);
655
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
656
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
657
        FileHandleCloseWrap::from_req(req));
658
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
659
    handle->AfterClose();
660
661
    int result = static_cast<int>(req->result);
662
    uv_fs_req_cleanup(req);
663
    wrap->Done(result);
664
  }});
665
666
  return 0;
667
}
668
669
670
4866
void FSReqCallback::Reject(Local<Value> reject) {
671
4866
  MakeCallback(env()->oncomplete_string(), 1, &reject);
672
4864
}
673
674
2531
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
675
2531
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
676
2531
}
677
678
47355
void FSReqCallback::Resolve(Local<Value> value) {
679
  Local<Value> argv[2] {
680
    Null(env()->isolate()),
681
    value
682
47355
  };
683
  MakeCallback(env()->oncomplete_string(),
684
87587
               value->IsUndefined() ? 1 : arraysize(argv),
685
134942
               argv);
686
47349
}
687
688
52221
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
689
52221
  args.GetReturnValue().SetUndefined();
690
52221
}
691
692
52221
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
693
52221
  CHECK(args.IsConstructCall());
694
52221
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
695
104442
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
696
52221
}
697
698
57571
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
699
    : wrap_(wrap),
700
      req_(req),
701
      handle_scope_(wrap->env()->isolate()),
702
57571
      context_scope_(wrap->env()->context()) {
703
57571
  CHECK_EQ(wrap_->req(), req);
704
57571
}
705
706
115126
FSReqAfterScope::~FSReqAfterScope() {
707
57563
  Clear();
708
57563
}
709
710
62985
void FSReqAfterScope::Clear() {
711
62985
  if (!wrap_) return;
712
713
57565
  uv_fs_req_cleanup(wrap_->req());
714
57565
  wrap_->Detach();
715
57565
  wrap_.reset();
716
}
717
718
// TODO(joyeecheung): create a normal context object, and
719
// construct the actual errors in the JS land using the context.
720
// The context should include fds for some fs APIs, currently they are
721
// missing in the error messages. The path, dest, syscall, fd, .etc
722
// can be put into the context before the binding is even invoked,
723
// the only information that has to come from the C++ layer is the
724
// error number (and possibly the syscall for abstraction),
725
// which is also why the errors should have been constructed
726
// in JS for more flexibility.
727
5278
void FSReqAfterScope::Reject(uv_fs_t* req) {
728
10554
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
729
5278
  Local<Value> exception = UVException(wrap_->env()->isolate(),
730
5278
                                       static_cast<int>(req->result),
731
                                       wrap_->syscall(),
732
                                       nullptr,
733
                                       req->path,
734
5278
                                       wrap_->data());
735
5278
  Clear();
736
5278
  wrap->Reject(exception);
737
5276
}
738
739
57571
bool FSReqAfterScope::Proceed() {
740
57571
  if (!wrap_->env()->can_call_into_js()) {
741
143
    return false;
742
  }
743
744
57428
  if (req_->result < 0) {
745
5278
    Reject(req_);
746
5276
    return false;
747
  }
748
52150
  return true;
749
}
750
751
7568
void AfterNoArgs(uv_fs_t* req) {
752
7568
  FSReqBase* req_wrap = FSReqBase::from_req(req);
753
15131
  FSReqAfterScope after(req_wrap, req);
754

7868
  FS_ASYNC_TRACE_END1(
755
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
756
7568
  if (after.Proceed())
757
14590
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
758
7563
}
759
760
8843
void AfterStat(uv_fs_t* req) {
761
8843
  FSReqBase* req_wrap = FSReqBase::from_req(req);
762
17686
  FSReqAfterScope after(req_wrap, req);
763

9288
  FS_ASYNC_TRACE_END1(
764
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
765
8843
  if (after.Proceed()) {
766
4178
    req_wrap->ResolveStat(&req->statbuf);
767
  }
768
8843
}
769
770
38544
void AfterInteger(uv_fs_t* req) {
771
38544
  FSReqBase* req_wrap = FSReqBase::from_req(req);
772
77086
  FSReqAfterScope after(req_wrap, req);
773

39091
  FS_ASYNC_TRACE_END1(
774
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
775
38544
  int result = static_cast<int>(req->result);
776

38544
  if (result >= 0 && req_wrap->is_plain_open())
777
5469
    req_wrap->env()->AddUnmanagedFd(result);
778
779
38544
  if (after.Proceed())
780
76730
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
781
38542
}
782
783
1644
void AfterOpenFileHandle(uv_fs_t* req) {
784
1644
  FSReqBase* req_wrap = FSReqBase::from_req(req);
785
1644
  FSReqAfterScope after(req_wrap, req);
786

2037
  FS_ASYNC_TRACE_END1(
787
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
788
1644
  if (after.Proceed()) {
789
1361
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
790
1361
                                     static_cast<int>(req->result));
791
1361
    if (fd == nullptr) return;
792
2722
    req_wrap->Resolve(fd->object());
793
  }
794
}
795
796
// Reverse the logic applied by path.toNamespacedPath() to create a
797
// namespace-prefixed path.
798
509
void FromNamespacedPath(std::string* path) {
799
#ifdef _WIN32
800
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
801
    *path = path->substr(8);
802
    path->insert(0, "\\\\");
803
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
804
    *path = path->substr(4);
805
  }
806
#endif
807
509
}
808
809
364
void AfterMkdirp(uv_fs_t* req) {
810
364
  FSReqBase* req_wrap = FSReqBase::from_req(req);
811
364
  FSReqAfterScope after(req_wrap, req);
812

470
  FS_ASYNC_TRACE_END1(
813
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
814
364
  if (after.Proceed()) {
815
716
    std::string first_path(req_wrap->continuation_data()->first_path());
816
358
    if (first_path.empty())
817
252
      return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
818
232
    FromNamespacedPath(&first_path);
819
    Local<Value> path;
820
    Local<Value> error;
821
232
    if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
822
                             req_wrap->encoding(),
823
464
                             &error).ToLocal(&path)) {
824
      return req_wrap->Reject(error);
825
    }
826
232
    return req_wrap->Resolve(path);
827
  }
828
}
829
830
7
void AfterStringPath(uv_fs_t* req) {
831
7
  FSReqBase* req_wrap = FSReqBase::from_req(req);
832
14
  FSReqAfterScope after(req_wrap, req);
833

12
  FS_ASYNC_TRACE_END1(
834
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
835
  MaybeLocal<Value> link;
836
  Local<Value> error;
837
838
7
  if (after.Proceed()) {
839
    link = StringBytes::Encode(req_wrap->env()->isolate(),
840
                               req->path,
841
                               req_wrap->encoding(),
842
6
                               &error);
843
6
    if (link.IsEmpty())
844
      req_wrap->Reject(error);
845
    else
846
12
      req_wrap->Resolve(link.ToLocalChecked());
847
  }
848
7
}
849
850
66
void AfterStringPtr(uv_fs_t* req) {
851
66
  FSReqBase* req_wrap = FSReqBase::from_req(req);
852
131
  FSReqAfterScope after(req_wrap, req);
853

78
  FS_ASYNC_TRACE_END1(
854
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
855
  MaybeLocal<Value> link;
856
  Local<Value> error;
857
858
66
  if (after.Proceed()) {
859
    link = StringBytes::Encode(req_wrap->env()->isolate(),
860
60
                               static_cast<const char*>(req->ptr),
861
                               req_wrap->encoding(),
862
60
                               &error);
863
60
    if (link.IsEmpty())
864
      req_wrap->Reject(error);
865
    else
866
120
      req_wrap->Resolve(link.ToLocalChecked());
867
  }
868
65
}
869
870
223
void AfterScanDir(uv_fs_t* req) {
871
223
  FSReqBase* req_wrap = FSReqBase::from_req(req);
872
223
  FSReqAfterScope after(req_wrap, req);
873

236
  FS_ASYNC_TRACE_END1(
874
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
875
223
  if (!after.Proceed()) {
876
7
    return;
877
  }
878
879
216
  Environment* env = req_wrap->env();
880
216
  Isolate* isolate = env->isolate();
881
  Local<Value> error;
882
  int r;
883
884
216
  std::vector<Local<Value>> name_v;
885
216
  std::vector<Local<Value>> type_v;
886
887
216
  const bool with_file_types = req_wrap->with_file_types();
888
889
  for (;;) {
890
    uv_dirent_t ent;
891
892
7942
    r = uv_fs_scandir_next(req, &ent);
893
7942
    if (r == UV_EOF)
894
216
      break;
895
7726
    if (r != 0) {
896
      return req_wrap->Reject(
897
          UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
898
    }
899
900
    Local<Value> filename;
901
7726
    if (!StringBytes::Encode(isolate, ent.name, req_wrap->encoding(), &error)
902
7726
             .ToLocal(&filename)) {
903
      return req_wrap->Reject(error);
904
    }
905
7726
    name_v.push_back(filename);
906
907
7726
    if (with_file_types) type_v.emplace_back(Integer::New(isolate, ent.type));
908
7726
  }
909
910
216
  if (with_file_types) {
911
    Local<Value> result[] = {Array::New(isolate, name_v.data(), name_v.size()),
912
246
                             Array::New(isolate, type_v.data(), type_v.size())};
913
246
    req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
914
  } else {
915
186
    req_wrap->Resolve(Array::New(isolate, name_v.data(), name_v.size()));
916
  }
917
}
918
919
4182
void Access(const FunctionCallbackInfo<Value>& args) {
920
4182
  Environment* env = Environment::GetCurrent(args);
921
4182
  Isolate* isolate = env->isolate();
922
8364
  HandleScope scope(isolate);
923
924
4182
  const int argc = args.Length();
925
4182
  CHECK_GE(argc, 2);
926
927
4182
  CHECK(args[1]->IsInt32());
928
8364
  int mode = args[1].As<Int32>()->Value();
929
930
8364
  BufferValue path(isolate, args[0]);
931
4182
  CHECK_NOT_NULL(*path);
932
933
4182
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
934
4182
  if (req_wrap_async != nullptr) {  // access(path, mode, req)
935

67
    FS_ASYNC_TRACE_BEGIN1(
936
        UV_FS_ACCESS, req_wrap_async, "path", TRACE_STR_COPY(*path))
937
46
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
938
              uv_fs_access, *path, mode);
939
  } else {  // access(path, mode, undefined, ctx)
940
4136
    CHECK_EQ(argc, 4);
941
8272
    FSReqWrapSync req_wrap_sync;
942

4138
    FS_SYNC_TRACE_BEGIN(access);
943
8272
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
944

4138
    FS_SYNC_TRACE_END(access);
945
  }
946
4182
}
947
948
949
67201
void Close(const FunctionCallbackInfo<Value>& args) {
950
67201
  Environment* env = Environment::GetCurrent(args);
951
952
67201
  const int argc = args.Length();
953
67201
  CHECK_GE(argc, 2);
954
955
67201
  CHECK(args[0]->IsInt32());
956
134402
  int fd = args[0].As<Int32>()->Value();
957
67201
  env->RemoveUnmanagedFd(fd);
958
959
67201
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
960
67201
  if (req_wrap_async != nullptr) {  // close(fd, req)
961

5616
    FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, req_wrap_async)
962
5384
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
963
              uv_fs_close, fd);
964
  } else {  // close(fd, undefined, ctx)
965
61817
    CHECK_EQ(argc, 3);
966
123634
    FSReqWrapSync req_wrap_sync;
967

61874
    FS_SYNC_TRACE_BEGIN(close);
968
61817
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
969

61874
    FS_SYNC_TRACE_END(close);
970
  }
971
67201
}
972
973
974
// Used to speed up module loading. Returns an array [string, boolean]
975
58330
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
976
58330
  Environment* env = Environment::GetCurrent(args);
977
58330
  Isolate* isolate = env->isolate();
978
58330
  uv_loop_t* loop = env->event_loop();
979
980
116660
  CHECK(args[0]->IsString());
981
58330
  node::Utf8Value path(isolate, args[0]);
982
983
58330
  if (strlen(*path) != path.length()) {
984
3
    args.GetReturnValue().Set(Array::New(isolate));
985
3
    return;  // Contains a nul byte.
986
  }
987
  uv_fs_t open_req;
988
58327
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
989
58327
  uv_fs_req_cleanup(&open_req);
990
991
58327
  if (fd < 0) {
992
51949
    args.GetReturnValue().Set(Array::New(isolate));
993
51949
    return;
994
  }
995
996
6378
  auto defer_close = OnScopeLeave([fd, loop]() {
997
    uv_fs_t close_req;
998
6378
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
999
6378
    uv_fs_req_cleanup(&close_req);
1000
6378
  });
1001
1002
6378
  const size_t kBlockSize = 32 << 10;
1003
6378
  std::vector<char> chars;
1004
6378
  int64_t offset = 0;
1005
  ssize_t numchars;
1006
  do {
1007
6378
    const size_t start = chars.size();
1008
6378
    chars.resize(start + kBlockSize);
1009
1010
    uv_buf_t buf;
1011
6378
    buf.base = &chars[start];
1012
6378
    buf.len = kBlockSize;
1013
1014
    uv_fs_t read_req;
1015
6378
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
1016
6378
    uv_fs_req_cleanup(&read_req);
1017
1018
6378
    if (numchars < 0) {
1019
1
      args.GetReturnValue().Set(Array::New(isolate));
1020
1
      return;
1021
    }
1022
6377
    offset += numchars;
1023
6377
  } while (static_cast<size_t>(numchars) == kBlockSize);
1024
1025
6377
  size_t start = 0;
1026

6377
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
1027
1
    start = 3;  // Skip UTF-8 BOM.
1028
  }
1029
1030
6377
  const size_t size = offset - start;
1031
6377
  char* p = &chars[start];
1032
6377
  char* pe = &chars[size];
1033
  char* pos[2];
1034
6377
  char** ppos = &pos[0];
1035
1036
101383
  while (p < pe) {
1037
101367
    char c = *p++;
1038

101367
    if (c == '\\' && p < pe && *p == '"') p++;
1039
101367
    if (c != '"') continue;
1040
15296
    *ppos++ = p;
1041
15296
    if (ppos < &pos[2]) continue;
1042
7648
    ppos = &pos[0];
1043
1044
7648
    char* s = &pos[0][0];
1045
7648
    char* se = &pos[1][-1];  // Exclude quote.
1046
7648
    size_t n = se - s;
1047
1048
7648
    if (n == 4) {
1049
6353
      if (0 == memcmp(s, "main", 4)) break;
1050
6314
      if (0 == memcmp(s, "name", 4)) break;
1051
49
      if (0 == memcmp(s, "type", 4)) break;
1052
1295
    } else if (n == 7) {
1053
13
      if (0 == memcmp(s, "exports", 7)) break;
1054
7
      if (0 == memcmp(s, "imports", 7)) break;
1055
    }
1056
  }
1057
1058
1059
  Local<Value> return_value[] = {
1060
6377
    String::NewFromUtf8(isolate,
1061
6377
                        &chars[start],
1062
                        v8::NewStringType::kNormal,
1063
6377
                        size).ToLocalChecked(),
1064
    Boolean::New(isolate, p < pe ? true : false)
1065
19131
  };
1066
12754
  args.GetReturnValue().Set(
1067
    Array::New(isolate, return_value, arraysize(return_value)));
1068
}
1069
1070
// Used to speed up module loading.  Returns 0 if the path refers to
1071
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
1072
// The speedup comes from not creating thousands of Stat and Error objects.
1073
165744
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
1074
165744
  Environment* env = Environment::GetCurrent(args);
1075
1076
331488
  CHECK(args[0]->IsString());
1077
165744
  node::Utf8Value path(env->isolate(), args[0]);
1078
1079
  uv_fs_t req;
1080
165744
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1081
165744
  if (rc == 0) {
1082
79925
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1083
79925
    rc = !!(s->st_mode & S_IFDIR);
1084
  }
1085
165744
  uv_fs_req_cleanup(&req);
1086
1087
331488
  args.GetReturnValue().Set(rc);
1088
165744
}
1089
1090
18354
static void Stat(const FunctionCallbackInfo<Value>& args) {
1091
18354
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1092
18354
  Environment* env = binding_data->env();
1093
1094
18354
  const int argc = args.Length();
1095
18354
  CHECK_GE(argc, 2);
1096
1097
18354
  BufferValue path(env->isolate(), args[0]);
1098
18354
  CHECK_NOT_NULL(*path);
1099
1100
18354
  bool use_bigint = args[1]->IsTrue();
1101
18354
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1102
18354
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1103

2882
    FS_ASYNC_TRACE_BEGIN1(
1104
        UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1105
2755
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1106
              uv_fs_stat, *path);
1107
  } else {  // stat(path, use_bigint, undefined, ctx)
1108
15599
    CHECK_EQ(argc, 4);
1109
15599
    FSReqWrapSync req_wrap_sync;
1110

15601
    FS_SYNC_TRACE_BEGIN(stat);
1111
31198
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1112

15601
    FS_SYNC_TRACE_END(stat);
1113
15599
    if (err != 0) {
1114
710
      return;  // error info is in ctx
1115
    }
1116
1117
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1118
14889
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1119
29778
    args.GetReturnValue().Set(arr);
1120
  }
1121
}
1122
1123
120006
static void LStat(const FunctionCallbackInfo<Value>& args) {
1124
120006
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1125
120006
  Environment* env = binding_data->env();
1126
1127
120006
  const int argc = args.Length();
1128
120006
  CHECK_GE(argc, 3);
1129
1130
120006
  BufferValue path(env->isolate(), args[0]);
1131
120006
  CHECK_NOT_NULL(*path);
1132
1133
120006
  bool use_bigint = args[1]->IsTrue();
1134
120006
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1135
120006
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1136

4922
    FS_ASYNC_TRACE_BEGIN1(
1137
        UV_FS_LSTAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1138
4804
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1139
              uv_fs_lstat, *path);
1140
  } else {  // lstat(path, use_bigint, undefined, ctx)
1141
115202
    CHECK_EQ(argc, 4);
1142
115202
    FSReqWrapSync req_wrap_sync;
1143

115219
    FS_SYNC_TRACE_BEGIN(lstat);
1144
230404
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1145
                       *path);
1146

115219
    FS_SYNC_TRACE_END(lstat);
1147
115202
    if (err != 0) {
1148
483
      return;  // error info is in ctx
1149
    }
1150
1151
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1152
114719
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1153
229438
    args.GetReturnValue().Set(arr);
1154
  }
1155
}
1156
1157
56926
static void FStat(const FunctionCallbackInfo<Value>& args) {
1158
56926
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1159
56926
  Environment* env = binding_data->env();
1160
1161
56926
  const int argc = args.Length();
1162
56926
  CHECK_GE(argc, 2);
1163
1164
56926
  CHECK(args[0]->IsInt32());
1165
113852
  int fd = args[0].As<Int32>()->Value();
1166
1167
56926
  bool use_bigint = args[1]->IsTrue();
1168
56926
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1169
56926
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1170

1712
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FSTAT, req_wrap_async)
1171
1286
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1172
              uv_fs_fstat, fd);
1173
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1174
55640
    CHECK_EQ(argc, 4);
1175
55640
    FSReqWrapSync req_wrap_sync;
1176

55649
    FS_SYNC_TRACE_BEGIN(fstat);
1177
55640
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1178

55649
    FS_SYNC_TRACE_END(fstat);
1179
55640
    if (err != 0) {
1180
21
      return;  // error info is in ctx
1181
    }
1182
1183
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1184
55619
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1185
111238
    args.GetReturnValue().Set(arr);
1186
  }
1187
}
1188
1189
457
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1190
457
  Environment* env = Environment::GetCurrent(args);
1191
457
  Isolate* isolate = env->isolate();
1192
1193
457
  const int argc = args.Length();
1194
457
  CHECK_GE(argc, 4);
1195
1196
914
  BufferValue target(isolate, args[0]);
1197
457
  CHECK_NOT_NULL(*target);
1198
914
  BufferValue path(isolate, args[1]);
1199
457
  CHECK_NOT_NULL(*path);
1200
1201
457
  CHECK(args[2]->IsInt32());
1202
914
  int flags = args[2].As<Int32>()->Value();
1203
1204
457
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1205
457
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1206

235
    FS_ASYNC_TRACE_BEGIN2(UV_FS_SYMLINK,
1207
                          req_wrap_async,
1208
                          "target",
1209
                          TRACE_STR_COPY(*target),
1210
                          "path",
1211
                          TRACE_STR_COPY(*path))
1212
124
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1213
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1214
  } else {  // symlink(target, path, flags, undefinec, ctx)
1215
333
    CHECK_EQ(argc, 5);
1216
666
    FSReqWrapSync req_wrap_sync;
1217

337
    FS_SYNC_TRACE_BEGIN(symlink);
1218
666
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1219
             uv_fs_symlink, *target, *path, flags);
1220

337
    FS_SYNC_TRACE_END(symlink);
1221
  }
1222
457
}
1223
1224
12
static void Link(const FunctionCallbackInfo<Value>& args) {
1225
12
  Environment* env = Environment::GetCurrent(args);
1226
12
  Isolate* isolate = env->isolate();
1227
1228
12
  const int argc = args.Length();
1229
12
  CHECK_GE(argc, 3);
1230
1231
24
  BufferValue src(isolate, args[0]);
1232
12
  CHECK_NOT_NULL(*src);
1233
1234
24
  BufferValue dest(isolate, args[1]);
1235
12
  CHECK_NOT_NULL(*dest);
1236
1237
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1238
12
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1239

9
    FS_ASYNC_TRACE_BEGIN2(UV_FS_LINK,
1240
                          req_wrap_async,
1241
                          "src",
1242
                          TRACE_STR_COPY(*src),
1243
                          "dest",
1244
                          TRACE_STR_COPY(*dest))
1245
5
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1246
                  AfterNoArgs, uv_fs_link, *src, *dest);
1247
  } else {  // link(src, dest)
1248
7
    CHECK_EQ(argc, 4);
1249
14
    FSReqWrapSync req_wrap_sync;
1250

13
    FS_SYNC_TRACE_BEGIN(link);
1251
14
    SyncCall(env, args[3], &req_wrap_sync, "link",
1252
             uv_fs_link, *src, *dest);
1253

13
    FS_SYNC_TRACE_END(link);
1254
  }
1255
12
}
1256
1257
110
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1258
110
  Environment* env = Environment::GetCurrent(args);
1259
110
  Isolate* isolate = env->isolate();
1260
1261
110
  const int argc = args.Length();
1262
110
  CHECK_GE(argc, 3);
1263
1264
110
  BufferValue path(isolate, args[0]);
1265
110
  CHECK_NOT_NULL(*path);
1266
1267
110
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1268
1269
110
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1270
110
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1271

53
    FS_ASYNC_TRACE_BEGIN1(
1272
        UV_FS_READLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1273
43
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1274
              uv_fs_readlink, *path);
1275
  } else {
1276
67
    CHECK_EQ(argc, 4);
1277
67
    FSReqWrapSync req_wrap_sync;
1278

69
    FS_SYNC_TRACE_BEGIN(readlink);
1279
134
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1280
                       uv_fs_readlink, *path);
1281

69
    FS_SYNC_TRACE_END(readlink);
1282
67
    if (err < 0) {
1283
2
      return;  // syscall failed, no need to continue, error info is in ctx
1284
    }
1285
65
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1286
1287
    Local<Value> error;
1288
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1289
                                               link_path,
1290
                                               encoding,
1291
65
                                               &error);
1292
65
    if (rc.IsEmpty()) {
1293
      Local<Object> ctx = args[3].As<Object>();
1294
      ctx->Set(env->context(), env->error_string(), error).Check();
1295
      return;
1296
    }
1297
1298
130
    args.GetReturnValue().Set(rc.ToLocalChecked());
1299
  }
1300
}
1301
1302
7
static void Rename(const FunctionCallbackInfo<Value>& args) {
1303
7
  Environment* env = Environment::GetCurrent(args);
1304
7
  Isolate* isolate = env->isolate();
1305
1306
7
  const int argc = args.Length();
1307
7
  CHECK_GE(argc, 3);
1308
1309
14
  BufferValue old_path(isolate, args[0]);
1310
7
  CHECK_NOT_NULL(*old_path);
1311
14
  BufferValue new_path(isolate, args[1]);
1312
7
  CHECK_NOT_NULL(*new_path);
1313
1314
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1315
7
  if (req_wrap_async != nullptr) {
1316

7
    FS_ASYNC_TRACE_BEGIN2(UV_FS_RENAME,
1317
                          req_wrap_async,
1318
                          "old_path",
1319
                          TRACE_STR_COPY(*old_path),
1320
                          "new_path",
1321
                          TRACE_STR_COPY(*new_path))
1322
4
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1323
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1324
                  *old_path, *new_path);
1325
  } else {
1326
3
    CHECK_EQ(argc, 4);
1327
6
    FSReqWrapSync req_wrap_sync;
1328

5
    FS_SYNC_TRACE_BEGIN(rename);
1329
6
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1330
             *old_path, *new_path);
1331

5
    FS_SYNC_TRACE_END(rename);
1332
  }
1333
7
}
1334
1335
70
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1336
70
  Environment* env = Environment::GetCurrent(args);
1337
1338
70
  const int argc = args.Length();
1339
70
  CHECK_GE(argc, 3);
1340
1341
70
  CHECK(args[0]->IsInt32());
1342
140
  const int fd = args[0].As<Int32>()->Value();
1343
1344
70
  CHECK(IsSafeJsInt(args[1]));
1345
140
  const int64_t len = args[1].As<Integer>()->Value();
1346
1347
70
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1348
70
  if (req_wrap_async != nullptr) {
1349

71
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FTRUNCATE, req_wrap_async)
1350
55
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1351
              uv_fs_ftruncate, fd, len);
1352
  } else {
1353
15
    CHECK_EQ(argc, 4);
1354
30
    FSReqWrapSync req_wrap_sync;
1355

17
    FS_SYNC_TRACE_BEGIN(ftruncate);
1356
15
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1357
             len);
1358

17
    FS_SYNC_TRACE_END(ftruncate);
1359
  }
1360
70
}
1361
1362
8
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1363
8
  Environment* env = Environment::GetCurrent(args);
1364
1365
8
  const int argc = args.Length();
1366
8
  CHECK_GE(argc, 2);
1367
1368
8
  CHECK(args[0]->IsInt32());
1369
16
  const int fd = args[0].As<Int32>()->Value();
1370
1371
8
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1372
8
  if (req_wrap_async != nullptr) {
1373

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FDATASYNC, req_wrap_async)
1374
5
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1375
              uv_fs_fdatasync, fd);
1376
  } else {
1377
3
    CHECK_EQ(argc, 3);
1378
6
    FSReqWrapSync req_wrap_sync;
1379

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

5
    FS_SYNC_TRACE_END(fdatasync);
1382
  }
1383
8
}
1384
1385
22
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1386
22
  Environment* env = Environment::GetCurrent(args);
1387
1388
22
  const int argc = args.Length();
1389
22
  CHECK_GE(argc, 2);
1390
1391
22
  CHECK(args[0]->IsInt32());
1392
44
  const int fd = args[0].As<Int32>()->Value();
1393
1394
22
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1395
22
  if (req_wrap_async != nullptr) {
1396

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FSYNC, req_wrap_async)
1397
5
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1398
              uv_fs_fsync, fd);
1399
  } else {
1400
17
    CHECK_EQ(argc, 3);
1401
34
    FSReqWrapSync req_wrap_sync;
1402

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

19
    FS_SYNC_TRACE_END(fsync);
1405
  }
1406
22
}
1407
1408
2750
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1409
2750
  Environment* env = Environment::GetCurrent(args);
1410
1411
2750
  const int argc = args.Length();
1412
2750
  CHECK_GE(argc, 2);
1413
1414
5500
  BufferValue path(env->isolate(), args[0]);
1415
2750
  CHECK_NOT_NULL(*path);
1416
1417
2750
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1418
2750
  if (req_wrap_async != nullptr) {
1419

1242
    FS_ASYNC_TRACE_BEGIN1(
1420
        UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1421
1133
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1422
              uv_fs_unlink, *path);
1423
  } else {
1424
1617
    CHECK_EQ(argc, 3);
1425
3234
    FSReqWrapSync req_wrap_sync;
1426

1672
    FS_SYNC_TRACE_BEGIN(unlink);
1427
3234
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1428

1672
    FS_SYNC_TRACE_END(unlink);
1429
  }
1430
2750
}
1431
1432
1940
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1433
1940
  Environment* env = Environment::GetCurrent(args);
1434
1435
1940
  const int argc = args.Length();
1436
1940
  CHECK_GE(argc, 2);
1437
1438
3880
  BufferValue path(env->isolate(), args[0]);
1439
1940
  CHECK_NOT_NULL(*path);
1440
1441
1940
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1442
1940
  if (req_wrap_async != nullptr) {
1443

273
    FS_ASYNC_TRACE_BEGIN1(
1444
        UV_FS_RMDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1445
262
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1446
              uv_fs_rmdir, *path);
1447
  } else {  // rmdir(path, undefined, ctx)
1448
1678
    CHECK_EQ(argc, 3);
1449
3356
    FSReqWrapSync req_wrap_sync;
1450

1684
    FS_SYNC_TRACE_BEGIN(rmdir);
1451
3356
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1452
             uv_fs_rmdir, *path);
1453

1684
    FS_SYNC_TRACE_END(rmdir);
1454
  }
1455
1940
}
1456
1457
6554
int MKDirpSync(uv_loop_t* loop,
1458
               uv_fs_t* req,
1459
               const std::string& path,
1460
               int mode,
1461
               uv_fs_cb cb) {
1462
6554
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1463
1464
  // on the first iteration of algorithm, stash state information.
1465
6554
  if (req_wrap->continuation_data() == nullptr) {
1466
6554
    req_wrap->set_continuation_data(
1467
13108
        std::make_unique<FSContinuationData>(req, mode, cb));
1468
6554
    req_wrap->continuation_data()->PushPath(std::move(path));
1469
  }
1470
1471
12955
  while (req_wrap->continuation_data()->paths().size() > 0) {
1472
6704
    std::string next_path = req_wrap->continuation_data()->PopPath();
1473
6704
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1474
    while (true) {
1475

6705
      switch (err) {
1476
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1477
        // ~FSReqWrapSync():
1478
373
        case 0:
1479
373
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1480
373
          if (req_wrap->continuation_data()->paths().size() == 0) {
1481
299
            return 0;
1482
          }
1483
74
          break;
1484
2
        case UV_EACCES:
1485
        case UV_ENOSPC:
1486
        case UV_ENOTDIR:
1487
        case UV_EPERM: {
1488
2
          return err;
1489
        }
1490
76
        case UV_ENOENT: {
1491
          std::string dirname = next_path.substr(0,
1492
76
                                        next_path.find_last_of(kPathSeparator));
1493
76
          if (dirname != next_path) {
1494
75
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1495
75
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1496
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1497
1
            err = UV_EEXIST;
1498
1
            continue;
1499
          }
1500
75
          break;
1501
        }
1502
6254
        default:
1503
6254
          uv_fs_req_cleanup(req);
1504
6254
          int orig_err = err;
1505
6254
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1506

6254
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1507
1
            uv_fs_req_cleanup(req);
1508

2
            if (orig_err == UV_EEXIST &&
1509
1
              req_wrap->continuation_data()->paths().size() > 0) {
1510
              return UV_ENOTDIR;
1511
            }
1512
1
            return UV_EEXIST;
1513
          }
1514
6253
          if (err < 0) return err;
1515
6252
          break;
1516
      }
1517
6401
      break;
1518
1
    }
1519
6401
    uv_fs_req_cleanup(req);
1520
  }
1521
1522
6251
  return 0;
1523
}
1524
1525
816
int MKDirpAsync(uv_loop_t* loop,
1526
                uv_fs_t* req,
1527
                const char* path,
1528
                int mode,
1529
                uv_fs_cb cb) {
1530
816
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1531
  // on the first iteration of algorithm, stash state information.
1532
816
  if (req_wrap->continuation_data() == nullptr) {
1533
364
    req_wrap->set_continuation_data(
1534
728
        std::make_unique<FSContinuationData>(req, mode, cb));
1535
364
    req_wrap->continuation_data()->PushPath(std::move(path));
1536
  }
1537
1538
  // on each iteration of algorithm, mkdir directory on top of stack.
1539
816
  std::string next_path = req_wrap->continuation_data()->PopPath();
1540
816
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1541
816
                        uv_fs_callback_t{[](uv_fs_t* req) {
1542
816
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1543
816
    Environment* env = req_wrap->env();
1544
816
    uv_loop_t* loop = env->event_loop();
1545
1632
    std::string path = req->path;
1546
816
    int err = static_cast<int>(req->result);
1547
1548
    while (true) {
1549

817
      switch (err) {
1550
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1551
        // FSReqAfterScope::~FSReqAfterScope()
1552
340
        case 0: {
1553
340
          if (req_wrap->continuation_data()->paths().size() == 0) {
1554
232
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1555
232
            req_wrap->continuation_data()->Done(0);
1556
          } else {
1557
108
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1558
108
            uv_fs_req_cleanup(req);
1559
108
            MKDirpAsync(loop, req, path.c_str(),
1560
                        req_wrap->continuation_data()->mode(), nullptr);
1561
          }
1562
340
          break;
1563
        }
1564
3
        case UV_EACCES:
1565
        case UV_ENOTDIR:
1566
        case UV_EPERM: {
1567
3
          req_wrap->continuation_data()->Done(err);
1568
3
          break;
1569
        }
1570
227
        case UV_ENOENT: {
1571
          std::string dirname = path.substr(0,
1572
227
                                            path.find_last_of(kPathSeparator));
1573
227
          if (dirname != path) {
1574
226
            req_wrap->continuation_data()->PushPath(std::move(path));
1575
226
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1576
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1577
1
            err = UV_EEXIST;
1578
1
            continue;
1579
          }
1580
226
          uv_fs_req_cleanup(req);
1581
226
          MKDirpAsync(loop, req, path.c_str(),
1582
                      req_wrap->continuation_data()->mode(), nullptr);
1583
226
          break;
1584
        }
1585
247
        default:
1586
247
          uv_fs_req_cleanup(req);
1587
          // Stash err for use in the callback.
1588
247
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1589
247
          int err = uv_fs_stat(loop, req, path.c_str(),
1590
247
                               uv_fs_callback_t{[](uv_fs_t* req) {
1591
247
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1592
247
            int err = static_cast<int>(req->result);
1593

494
            if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1594
247
                  req_wrap->continuation_data()->paths().size() > 0) {
1595

118
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1596
118
                Environment* env = req_wrap->env();
1597
118
                uv_loop_t* loop = env->event_loop();
1598
118
                std::string path = req->path;
1599
118
                uv_fs_req_cleanup(req);
1600
118
                MKDirpAsync(loop, req, path.c_str(),
1601
                            req_wrap->continuation_data()->mode(), nullptr);
1602
118
                return;
1603
              }
1604
              err = UV_ENOTDIR;
1605
            }
1606
            // verify that the path pointed to is actually a directory.
1607

129
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1608
129
            req_wrap->continuation_data()->Done(err);
1609
247
          }});
1610
247
          if (err < 0) req_wrap->continuation_data()->Done(err);
1611
247
          break;
1612
      }
1613
816
      break;
1614
1
    }
1615
816
  }});
1616
1617
816
  return err;
1618
}
1619
1620
283
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1621
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1622
283
  env->PrintSyncTrace();
1623
283
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1624
                       nullptr);
1625
283
  if (err < 0) {
1626
4
    v8::Local<v8::Context> context = env->context();
1627
4
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1628
4
    v8::Isolate* isolate = env->isolate();
1629
4
    ctx_obj->Set(context,
1630
                 env->errno_string(),
1631
16
                 v8::Integer::New(isolate, err)).Check();
1632
4
    ctx_obj->Set(context,
1633
                 env->syscall_string(),
1634
16
                 OneByteString(isolate, "mkdir")).Check();
1635
  }
1636
283
  return err;
1637
}
1638
1639
1843
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1640
1843
  Environment* env = Environment::GetCurrent(args);
1641
1642
1843
  const int argc = args.Length();
1643
1843
  CHECK_GE(argc, 4);
1644
1645
1843
  BufferValue path(env->isolate(), args[0]);
1646
1843
  CHECK_NOT_NULL(*path);
1647
1648
1843
  CHECK(args[1]->IsInt32());
1649
3686
  const int mode = args[1].As<Int32>()->Value();
1650
1651
1843
  CHECK(args[2]->IsBoolean());
1652
1843
  bool mkdirp = args[2]->IsTrue();
1653
1654
1843
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1655
1843
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1656

703
    FS_ASYNC_TRACE_BEGIN1(
1657
        UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1658

590
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1659
              mkdirp ? AfterMkdirp : AfterNoArgs,
1660
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1661
  } else {  // mkdir(path, mode, undefined, ctx)
1662
1253
    CHECK_EQ(argc, 5);
1663
1253
    FSReqWrapSync req_wrap_sync;
1664

1257
    FS_SYNC_TRACE_BEGIN(mkdir);
1665
1253
    if (mkdirp) {
1666
283
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1667

562
      if (err == 0 &&
1668
279
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1669
        Local<Value> error;
1670
277
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1671
277
        FromNamespacedPath(&first_path);
1672
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1673
                                                     first_path.c_str(),
1674
277
                                                     UTF8, &error);
1675
277
        if (path.IsEmpty()) {
1676
          Local<Object> ctx = args[4].As<Object>();
1677
          ctx->Set(env->context(), env->error_string(), error).Check();
1678
          return;
1679
        }
1680
554
        args.GetReturnValue().Set(path.ToLocalChecked());
1681
      }
1682
    } else {
1683
1940
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1684
               uv_fs_mkdir, *path, mode);
1685
    }
1686

1257
    FS_SYNC_TRACE_END(mkdir);
1687
  }
1688
}
1689
1690
43
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1691
43
  Environment* env = Environment::GetCurrent(args);
1692
43
  Isolate* isolate = env->isolate();
1693
1694
43
  const int argc = args.Length();
1695
43
  CHECK_GE(argc, 3);
1696
1697
43
  BufferValue path(isolate, args[0]);
1698
43
  CHECK_NOT_NULL(*path);
1699
1700
43
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1701
1702
43
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1703
43
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1704

28
    FS_ASYNC_TRACE_BEGIN1(
1705
        UV_FS_REALPATH, req_wrap_async, "path", TRACE_STR_COPY(*path))
1706
23
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1707
              uv_fs_realpath, *path);
1708
  } else {  // realpath(path, encoding, undefined, ctx)
1709
20
    CHECK_EQ(argc, 4);
1710
20
    FSReqWrapSync req_wrap_sync;
1711

22
    FS_SYNC_TRACE_BEGIN(realpath);
1712
40
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1713
                       uv_fs_realpath, *path);
1714

22
    FS_SYNC_TRACE_END(realpath);
1715
20
    if (err < 0) {
1716
2
      return;  // syscall failed, no need to continue, error info is in ctx
1717
    }
1718
1719
18
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1720
1721
    Local<Value> error;
1722
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1723
                                               link_path,
1724
                                               encoding,
1725
18
                                               &error);
1726
18
    if (rc.IsEmpty()) {
1727
      Local<Object> ctx = args[3].As<Object>();
1728
      ctx->Set(env->context(), env->error_string(), error).Check();
1729
      return;
1730
    }
1731
1732
36
    args.GetReturnValue().Set(rc.ToLocalChecked());
1733
  }
1734
}
1735
1736
14032
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1737
14032
  Environment* env = Environment::GetCurrent(args);
1738
14032
  Isolate* isolate = env->isolate();
1739
1740
14032
  const int argc = args.Length();
1741
14032
  CHECK_GE(argc, 3);
1742
1743
14032
  BufferValue path(isolate, args[0]);
1744
14032
  CHECK_NOT_NULL(*path);
1745
1746
14032
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1747
1748
14032
  bool with_types = args[2]->IsTrue();
1749
1750
14032
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1751
14032
  if (req_wrap_async != nullptr) {  // readdir(path, encoding, withTypes, req)
1752
223
    req_wrap_async->set_with_file_types(with_types);
1753

236
    FS_ASYNC_TRACE_BEGIN1(
1754
        UV_FS_SCANDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1755
223
    AsyncCall(env,
1756
              req_wrap_async,
1757
              args,
1758
              "scandir",
1759
              encoding,
1760
              AfterScanDir,
1761
              uv_fs_scandir,
1762
              *path,
1763
              0 /*flags*/);
1764
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1765
13809
    CHECK_EQ(argc, 5);
1766
13809
    FSReqWrapSync req_wrap_sync;
1767

13811
    FS_SYNC_TRACE_BEGIN(readdir);
1768
27618
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1769
                       uv_fs_scandir, *path, 0 /*flags*/);
1770

13811
    FS_SYNC_TRACE_END(readdir);
1771
13809
    if (err < 0) {
1772
134
      return;  // syscall failed, no need to continue, error info is in ctx
1773
    }
1774
1775
13675
    CHECK_GE(req_wrap_sync.req.result, 0);
1776
    int r;
1777
13675
    std::vector<Local<Value>> name_v;
1778
13675
    std::vector<Local<Value>> type_v;
1779
1780
    for (;;) {
1781
      uv_dirent_t ent;
1782
1783
810198
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1784
810198
      if (r == UV_EOF)
1785
13675
        break;
1786
796523
      if (r != 0) {
1787
        Local<Object> ctx = args[4].As<Object>();
1788
        ctx->Set(env->context(), env->errno_string(),
1789
                 Integer::New(isolate, r)).Check();
1790
        ctx->Set(env->context(), env->syscall_string(),
1791
                 OneByteString(isolate, "readdir")).Check();
1792
        return;
1793
      }
1794
1795
      Local<Value> error;
1796
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1797
                                                       ent.name,
1798
                                                       encoding,
1799
796523
                                                       &error);
1800
1801
796523
      if (filename.IsEmpty()) {
1802
        Local<Object> ctx = args[4].As<Object>();
1803
        ctx->Set(env->context(), env->error_string(), error).Check();
1804
        return;
1805
      }
1806
1807
796523
      name_v.push_back(filename.ToLocalChecked());
1808
1809
796523
      if (with_types) {
1810
51211
        type_v.emplace_back(Integer::New(isolate, ent.type));
1811
      }
1812
796523
    }
1813
1814
1815
13675
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1816
13675
    if (with_types) {
1817
      Local<Value> result[] = {
1818
        names,
1819
        Array::New(isolate, type_v.data(), type_v.size())
1820
386
      };
1821
386
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1822
    } else {
1823
26964
      args.GetReturnValue().Set(names);
1824
    }
1825
  }
1826
}
1827
1828
67936
static void Open(const FunctionCallbackInfo<Value>& args) {
1829
67936
  Environment* env = Environment::GetCurrent(args);
1830
1831
67936
  const int argc = args.Length();
1832
67936
  CHECK_GE(argc, 3);
1833
1834
135872
  BufferValue path(env->isolate(), args[0]);
1835
67936
  CHECK_NOT_NULL(*path);
1836
1837
67936
  CHECK(args[1]->IsInt32());
1838
135872
  const int flags = args[1].As<Int32>()->Value();
1839
1840
67936
  CHECK(args[2]->IsInt32());
1841
135872
  const int mode = args[2].As<Int32>()->Value();
1842
1843
67936
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1844
67936
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1845
5641
    req_wrap_async->set_is_plain_open(true);
1846

5913
    FS_ASYNC_TRACE_BEGIN1(
1847
        UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1848
5641
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1849
              uv_fs_open, *path, flags, mode);
1850
  } else {  // open(path, flags, mode, undefined, ctx)
1851
62295
    CHECK_EQ(argc, 5);
1852
62295
    FSReqWrapSync req_wrap_sync;
1853

62358
    FS_SYNC_TRACE_BEGIN(open);
1854
124590
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1855
                          uv_fs_open, *path, flags, mode);
1856

62358
    FS_SYNC_TRACE_END(open);
1857
62295
    if (result >= 0) env->AddUnmanagedFd(result);
1858
124590
    args.GetReturnValue().Set(result);
1859
  }
1860
67936
}
1861
1862
1647
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1863
1647
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1864
1647
  Environment* env = binding_data->env();
1865
1647
  Isolate* isolate = env->isolate();
1866
1867
1647
  const int argc = args.Length();
1868
1647
  CHECK_GE(argc, 3);
1869
1870
1647
  BufferValue path(isolate, args[0]);
1871
1647
  CHECK_NOT_NULL(*path);
1872
1873
1647
  CHECK(args[1]->IsInt32());
1874
3294
  const int flags = args[1].As<Int32>()->Value();
1875
1876
1647
  CHECK(args[2]->IsInt32());
1877
3294
  const int mode = args[2].As<Int32>()->Value();
1878
1879
1647
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1880
1647
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1881

2041
    FS_ASYNC_TRACE_BEGIN1(
1882
        UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1883
1646
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1884
              uv_fs_open, *path, flags, mode);
1885
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1886
1
    CHECK_EQ(argc, 5);
1887
1
    FSReqWrapSync req_wrap_sync;
1888

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

1
    FS_SYNC_TRACE_END(open);
1892
1
    if (result < 0) {
1893
      return;  // syscall failed, no need to continue, error info is in ctx
1894
    }
1895
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1896
1
    if (fd == nullptr) return;
1897
2
    args.GetReturnValue().Set(fd->object());
1898
  }
1899
}
1900
1901
222
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1902
222
  Environment* env = Environment::GetCurrent(args);
1903
222
  Isolate* isolate = env->isolate();
1904
1905
222
  const int argc = args.Length();
1906
222
  CHECK_GE(argc, 3);
1907
1908
444
  BufferValue src(isolate, args[0]);
1909
222
  CHECK_NOT_NULL(*src);
1910
1911
444
  BufferValue dest(isolate, args[1]);
1912
222
  CHECK_NOT_NULL(*dest);
1913
1914
222
  CHECK(args[2]->IsInt32());
1915
444
  const int flags = args[2].As<Int32>()->Value();
1916
1917
222
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1918
222
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1919

111
    FS_ASYNC_TRACE_BEGIN2(UV_FS_COPYFILE,
1920
                          req_wrap_async,
1921
                          "src",
1922
                          TRACE_STR_COPY(*src),
1923
                          "dest",
1924
                          TRACE_STR_COPY(*dest))
1925
208
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1926
104
                  *dest, dest.length(), UTF8, AfterNoArgs,
1927
                  uv_fs_copyfile, *src, *dest, flags);
1928
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1929
118
    CHECK_EQ(argc, 5);
1930
236
    FSReqWrapSync req_wrap_sync;
1931

120
    FS_SYNC_TRACE_BEGIN(copyfile);
1932
236
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1933
             uv_fs_copyfile, *src, *dest, flags);
1934

120
    FS_SYNC_TRACE_END(copyfile);
1935
  }
1936
222
}
1937
1938
1939
// Wrapper for write(2).
1940
//
1941
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1942
// 0 fd        integer. file descriptor
1943
// 1 buffer    the data to write
1944
// 2 offset    where in the buffer to start from
1945
// 3 length    how much to write
1946
// 4 position  if integer, position to write at in the file.
1947
//             if null, write from the current position
1948
90894
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1949
90894
  Environment* env = Environment::GetCurrent(args);
1950
1951
90894
  const int argc = args.Length();
1952
90894
  CHECK_GE(argc, 4);
1953
1954
90894
  CHECK(args[0]->IsInt32());
1955
181788
  const int fd = args[0].As<Int32>()->Value();
1956
1957
90894
  CHECK(Buffer::HasInstance(args[1]));
1958
90894
  Local<Object> buffer_obj = args[1].As<Object>();
1959
90894
  char* buffer_data = Buffer::Data(buffer_obj);
1960
90894
  size_t buffer_length = Buffer::Length(buffer_obj);
1961
1962
90894
  CHECK(IsSafeJsInt(args[2]));
1963
181788
  const int64_t off_64 = args[2].As<Integer>()->Value();
1964
90894
  CHECK_GE(off_64, 0);
1965
90894
  CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1966
90894
  const size_t off = static_cast<size_t>(off_64);
1967
1968
90894
  CHECK(args[3]->IsInt32());
1969
181788
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1970
90894
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1971
90894
  CHECK_LE(len, buffer_length);
1972
90894
  CHECK_GE(off + len, off);
1973
1974
90894
  const int64_t pos = GetOffset(args[4]);
1975
1976
90894
  char* buf = buffer_data + off;
1977
90894
  uv_buf_t uvbuf = uv_buf_init(buf, len);
1978
1979
90894
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
1980
90894
  if (req_wrap_async != nullptr) {  // write(fd, buffer, off, len, pos, req)
1981

17823
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
1982
17653
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1983
              uv_fs_write, fd, &uvbuf, 1, pos);
1984
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1985
73241
    CHECK_EQ(argc, 7);
1986
73241
    FSReqWrapSync req_wrap_sync;
1987

73291
    FS_SYNC_TRACE_BEGIN(write);
1988
73241
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1989
73241
                                uv_fs_write, fd, &uvbuf, 1, pos);
1990

73291
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1991
146482
    args.GetReturnValue().Set(bytesWritten);
1992
  }
1993
90894
}
1994
1995
1996
// Wrapper for writev(2).
1997
//
1998
// bytesWritten = writev(fd, chunks, position, callback)
1999
// 0 fd        integer. file descriptor
2000
// 1 chunks    array of buffers to write
2001
// 2 position  if integer, position to write at in the file.
2002
//             if null, write from the current position
2003
19
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
2004
19
  Environment* env = Environment::GetCurrent(args);
2005
2006
19
  const int argc = args.Length();
2007
19
  CHECK_GE(argc, 3);
2008
2009
19
  CHECK(args[0]->IsInt32());
2010
38
  const int fd = args[0].As<Int32>()->Value();
2011
2012
19
  CHECK(args[1]->IsArray());
2013
38
  Local<Array> chunks = args[1].As<Array>();
2014
2015
19
  int64_t pos = GetOffset(args[2]);
2016
2017
38
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
2018
2019
75
  for (uint32_t i = 0; i < iovs.length(); i++) {
2020
56
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
2021
56
    CHECK(Buffer::HasInstance(chunk));
2022
56
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
2023
  }
2024
2025
19
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2026
19
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
2027

24
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2028
15
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
2029
              uv_fs_write, fd, *iovs, iovs.length(), pos);
2030
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
2031
4
    CHECK_EQ(argc, 5);
2032
4
    FSReqWrapSync req_wrap_sync;
2033

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

4
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2037
8
    args.GetReturnValue().Set(bytesWritten);
2038
  }
2039
19
}
2040
2041
2042
// Wrapper for write(2).
2043
//
2044
// bytesWritten = write(fd, string, position, enc, callback)
2045
// 0 fd        integer. file descriptor
2046
// 1 string    non-buffer values are converted to strings
2047
// 2 position  if integer, position to write at in the file.
2048
//             if null, write from the current position
2049
// 3 enc       encoding of string
2050
131933
static void WriteString(const FunctionCallbackInfo<Value>& args) {
2051
131933
  Environment* env = Environment::GetCurrent(args);
2052
131933
  Isolate* isolate = env->isolate();
2053
2054
131933
  const int argc = args.Length();
2055
131933
  CHECK_GE(argc, 4);
2056
2057
131933
  CHECK(args[0]->IsInt32());
2058
263866
  const int fd = args[0].As<Int32>()->Value();
2059
2060
131933
  const int64_t pos = GetOffset(args[2]);
2061
2062
131933
  const auto enc = ParseEncoding(isolate, args[3], UTF8);
2063
2064
131933
  Local<Value> value = args[1];
2065
131933
  char* buf = nullptr;
2066
  size_t len;
2067
2068
131933
  FSReqBase* req_wrap_async = GetReqWrap(args, 4);
2069
131933
  const bool is_async = req_wrap_async != nullptr;
2070
2071
  // Avoid copying the string when it is externalized but only when:
2072
  // 1. The target encoding is compatible with the string's encoding, and
2073
  // 2. The write is synchronous, otherwise the string might get neutered
2074
  //    while the request is in flight, and
2075
  // 3. For UCS2, when the host system is little-endian.  Big-endian systems
2076
  //    need to call StringBytes::Write() to ensure proper byte swapping.
2077
  // The const_casts are conceptually sound: memory is read but not written.
2078

395643
  if (!is_async && value->IsString()) {
2079
131855
    auto string = value.As<String>();
2080


131856
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
2081
1
      auto ext = string->GetExternalOneByteStringResource();
2082
1
      buf = const_cast<char*>(ext->data());
2083
1
      len = ext->length();
2084


131855
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
2085
1
      auto ext = string->GetExternalStringResource();
2086
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
2087
1
      len = ext->length() * sizeof(*ext->data());
2088
    }
2089
  }
2090
2091
131933
  if (is_async) {  // write(fd, string, pos, enc, req)
2092
78
    CHECK_NOT_NULL(req_wrap_async);
2093
156
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
2094
    FSReqBase::FSReqBuffer& stack_buffer =
2095
78
        req_wrap_async->Init("write", len, enc);
2096
    // StorageSize may return too large a char, so correct the actual length
2097
    // by the write size
2098
78
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
2099
78
    stack_buffer.SetLengthAndZeroTerminate(len);
2100
78
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
2101

90
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2102
78
    int err = req_wrap_async->Dispatch(uv_fs_write,
2103
                                       fd,
2104
                                       &uvbuf,
2105
                                       1,
2106
                                       pos,
2107
                                       AfterInteger);
2108
78
    if (err < 0) {
2109
      uv_fs_t* uv_req = req_wrap_async->req();
2110
      uv_req->result = err;
2111
      uv_req->path = nullptr;
2112
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
2113
                             // an error
2114
    } else {
2115
78
      req_wrap_async->SetReturnValue(args);
2116
    }
2117
  } else {  // write(fd, string, pos, enc, undefined, ctx)
2118
131855
    CHECK_EQ(argc, 6);
2119
131855
    FSReqWrapSync req_wrap_sync;
2120
131855
    FSReqBase::FSReqBuffer stack_buffer;
2121
131855
    if (buf == nullptr) {
2122
263706
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
2123
        return;
2124
131853
      stack_buffer.AllocateSufficientStorage(len + 1);
2125
      // StorageSize may return too large a char, so correct the actual length
2126
      // by the write size
2127
131853
      len = StringBytes::Write(isolate, *stack_buffer,
2128
                               len, args[1], enc);
2129
131853
      stack_buffer.SetLengthAndZeroTerminate(len);
2130
131853
      buf = *stack_buffer;
2131
    }
2132
131855
    uv_buf_t uvbuf = uv_buf_init(buf, len);
2133

131855
    FS_SYNC_TRACE_BEGIN(write);
2134
131855
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2135
131855
                                uv_fs_write, fd, &uvbuf, 1, pos);
2136

131855
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2137
263710
    args.GetReturnValue().Set(bytesWritten);
2138
  }
2139
}
2140
2141
2142
/*
2143
 * Wrapper for read(2).
2144
 *
2145
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2146
 *
2147
 * 0 fd        int32. file descriptor
2148
 * 1 buffer    instance of Buffer
2149
 * 2 offset    int64. offset to start reading into inside buffer
2150
 * 3 length    int32. length to read
2151
 * 4 position  int64. file position - -1 for current position
2152
 */
2153
214096
static void Read(const FunctionCallbackInfo<Value>& args) {
2154
214096
  Environment* env = Environment::GetCurrent(args);
2155
2156
214096
  const int argc = args.Length();
2157
214096
  CHECK_GE(argc, 5);
2158
2159
214096
  CHECK(args[0]->IsInt32());
2160
428192
  const int fd = args[0].As<Int32>()->Value();
2161
2162
214096
  CHECK(Buffer::HasInstance(args[1]));
2163
214096
  Local<Object> buffer_obj = args[1].As<Object>();
2164
214096
  char* buffer_data = Buffer::Data(buffer_obj);
2165
214096
  size_t buffer_length = Buffer::Length(buffer_obj);
2166
2167
214096
  CHECK(IsSafeJsInt(args[2]));
2168
428192
  const int64_t off_64 = args[2].As<Integer>()->Value();
2169
214096
  CHECK_GE(off_64, 0);
2170
214096
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2171
214096
  const size_t off = static_cast<size_t>(off_64);
2172
2173
214096
  CHECK(args[3]->IsInt32());
2174
428192
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2175
214096
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2176
2177

214126
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2178
214096
  const int64_t pos = args[4]->IsNumber() ?
2179
428132
                      args[4].As<Integer>()->Value() :
2180
60
                      args[4].As<BigInt>()->Int64Value();
2181
2182
214096
  char* buf = buffer_data + off;
2183
214096
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2184
2185
214096
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2186
214096
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2187

15613
    FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2188
15150
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2189
              uv_fs_read, fd, &uvbuf, 1, pos);
2190
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2191
198946
    CHECK_EQ(argc, 7);
2192
198946
    FSReqWrapSync req_wrap_sync;
2193

198985
    FS_SYNC_TRACE_BEGIN(read);
2194
198946
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2195
198946
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2196

198985
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2197
397892
    args.GetReturnValue().Set(bytesRead);
2198
  }
2199
214096
}
2200
2201
2202
// Wrapper for readv(2).
2203
//
2204
// bytesRead = fs.readv(fd, buffers[, position], callback)
2205
// 0 fd        integer. file descriptor
2206
// 1 buffers   array of buffers to read
2207
// 2 position  if integer, position to read at in the file.
2208
//             if null, read from the current position
2209
11
static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2210
11
  Environment* env = Environment::GetCurrent(args);
2211
2212
11
  const int argc = args.Length();
2213
11
  CHECK_GE(argc, 3);
2214
2215
11
  CHECK(args[0]->IsInt32());
2216
22
  const int fd = args[0].As<Int32>()->Value();
2217
2218
11
  CHECK(args[1]->IsArray());
2219
22
  Local<Array> buffers = args[1].As<Array>();
2220
2221
11
  int64_t pos = GetOffset(args[2]);  // -1 if not a valid JS int
2222
2223
22
  MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2224
2225
  // Init uv buffers from ArrayBufferViews
2226
28
  for (uint32_t i = 0; i < iovs.length(); i++) {
2227
17
    Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2228
17
    CHECK(Buffer::HasInstance(buffer));
2229
17
    iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2230
  }
2231
2232
11
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2233
11
  if (req_wrap_async != nullptr) {  // readBuffers(fd, buffers, pos, req)
2234

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2235
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2236
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2237
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2238
4
    CHECK_EQ(argc, 5);
2239
4
    FSReqWrapSync req_wrap_sync;
2240

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

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2244
8
    args.GetReturnValue().Set(bytesRead);
2245
  }
2246
11
}
2247
2248
2249
/* fs.chmod(path, mode);
2250
 * Wrapper for chmod(1) / EIO_CHMOD
2251
 */
2252
311
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2253
311
  Environment* env = Environment::GetCurrent(args);
2254
2255
311
  const int argc = args.Length();
2256
311
  CHECK_GE(argc, 2);
2257
2258
622
  BufferValue path(env->isolate(), args[0]);
2259
311
  CHECK_NOT_NULL(*path);
2260
2261
311
  CHECK(args[1]->IsInt32());
2262
622
  int mode = args[1].As<Int32>()->Value();
2263
2264
311
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2265
311
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2266

149
    FS_ASYNC_TRACE_BEGIN1(
2267
        UV_FS_CHMOD, req_wrap_async, "path", TRACE_STR_COPY(*path))
2268
142
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2269
              uv_fs_chmod, *path, mode);
2270
  } else {  // chmod(path, mode, undefined, ctx)
2271
169
    CHECK_EQ(argc, 4);
2272
338
    FSReqWrapSync req_wrap_sync;
2273

171
    FS_SYNC_TRACE_BEGIN(chmod);
2274
338
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2275
             uv_fs_chmod, *path, mode);
2276

171
    FS_SYNC_TRACE_END(chmod);
2277
  }
2278
311
}
2279
2280
2281
/* fs.fchmod(fd, mode);
2282
 * Wrapper for fchmod(1) / EIO_FCHMOD
2283
 */
2284
13
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2285
13
  Environment* env = Environment::GetCurrent(args);
2286
2287
13
  const int argc = args.Length();
2288
13
  CHECK_GE(argc, 2);
2289
2290
13
  CHECK(args[0]->IsInt32());
2291
26
  const int fd = args[0].As<Int32>()->Value();
2292
2293
13
  CHECK(args[1]->IsInt32());
2294
26
  const int mode = args[1].As<Int32>()->Value();
2295
2296
13
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2297
13
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2298

14
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
2299
8
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2300
              uv_fs_fchmod, fd, mode);
2301
  } else {  // fchmod(fd, mode, undefined, ctx)
2302
5
    CHECK_EQ(argc, 4);
2303
10
    FSReqWrapSync req_wrap_sync;
2304

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2305
5
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2306
             uv_fs_fchmod, fd, mode);
2307

7
    FS_SYNC_TRACE_END(fchmod);
2308
  }
2309
13
}
2310
2311
2312
/* fs.chown(path, uid, gid);
2313
 * Wrapper for chown(1) / EIO_CHOWN
2314
 */
2315
5
static void Chown(const FunctionCallbackInfo<Value>& args) {
2316
5
  Environment* env = Environment::GetCurrent(args);
2317
2318
5
  const int argc = args.Length();
2319
5
  CHECK_GE(argc, 3);
2320
2321
10
  BufferValue path(env->isolate(), args[0]);
2322
5
  CHECK_NOT_NULL(*path);
2323
2324
5
  CHECK(IsSafeJsInt(args[1]));
2325
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2326
2327
5
  CHECK(IsSafeJsInt(args[2]));
2328
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2329
2330
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2331
5
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2332

6
    FS_ASYNC_TRACE_BEGIN1(
2333
        UV_FS_CHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2334
3
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2335
              uv_fs_chown, *path, uid, gid);
2336
  } else {  // chown(path, uid, gid, undefined, ctx)
2337
2
    CHECK_EQ(argc, 5);
2338
4
    FSReqWrapSync req_wrap_sync;
2339

4
    FS_SYNC_TRACE_BEGIN(chown);
2340
4
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2341
             uv_fs_chown, *path, uid, gid);
2342

4
    FS_SYNC_TRACE_END(chown);
2343
  }
2344
5
}
2345
2346
2347
/* fs.fchown(fd, uid, gid);
2348
 * Wrapper for fchown(1) / EIO_FCHOWN
2349
 */
2350
5
static void FChown(const FunctionCallbackInfo<Value>& args) {
2351
5
  Environment* env = Environment::GetCurrent(args);
2352
2353
5
  const int argc = args.Length();
2354
5
  CHECK_GE(argc, 3);
2355
2356
5
  CHECK(args[0]->IsInt32());
2357
10
  const int fd = args[0].As<Int32>()->Value();
2358
2359
5
  CHECK(IsSafeJsInt(args[1]));
2360
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2361
2362
5
  CHECK(IsSafeJsInt(args[2]));
2363
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2364
2365
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2366
5
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2367

6
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHOWN, req_wrap_async)
2368
3
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2369
              uv_fs_fchown, fd, uid, gid);
2370
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2371
2
    CHECK_EQ(argc, 5);
2372
4
    FSReqWrapSync req_wrap_sync;
2373

4
    FS_SYNC_TRACE_BEGIN(fchown);
2374
2
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2375
             uv_fs_fchown, fd, uid, gid);
2376

4
    FS_SYNC_TRACE_END(fchown);
2377
  }
2378
5
}
2379
2380
2381
6
static void LChown(const FunctionCallbackInfo<Value>& args) {
2382
6
  Environment* env = Environment::GetCurrent(args);
2383
2384
6
  const int argc = args.Length();
2385
6
  CHECK_GE(argc, 3);
2386
2387
12
  BufferValue path(env->isolate(), args[0]);
2388
6
  CHECK_NOT_NULL(*path);
2389
2390
6
  CHECK(IsSafeJsInt(args[1]));
2391
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2392
2393
6
  CHECK(IsSafeJsInt(args[2]));
2394
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2395
2396
6
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2397
6
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2398

7
    FS_ASYNC_TRACE_BEGIN1(
2399
        UV_FS_LCHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2400
4
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2401
              uv_fs_lchown, *path, uid, gid);
2402
  } else {  // lchown(path, uid, gid, undefined, ctx)
2403
2
    CHECK_EQ(argc, 5);
2404
4
    FSReqWrapSync req_wrap_sync;
2405

4
    FS_SYNC_TRACE_BEGIN(lchown);
2406
4
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2407
             uv_fs_lchown, *path, uid, gid);
2408

4
    FS_SYNC_TRACE_END(lchown);
2409
  }
2410
6
}
2411
2412
2413
63
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2414
63
  Environment* env = Environment::GetCurrent(args);
2415
2416
63
  const int argc = args.Length();
2417
63
  CHECK_GE(argc, 3);
2418
2419
126
  BufferValue path(env->isolate(), args[0]);
2420
63
  CHECK_NOT_NULL(*path);
2421
2422
63
  CHECK(args[1]->IsNumber());
2423
126
  const double atime = args[1].As<Number>()->Value();
2424
2425
63
  CHECK(args[2]->IsNumber());
2426
126
  const double mtime = args[2].As<Number>()->Value();
2427
2428
63
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2429
63
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2430

42
    FS_ASYNC_TRACE_BEGIN1(
2431
        UV_FS_UTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2432
36
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2433
              uv_fs_utime, *path, atime, mtime);
2434
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2435
27
    CHECK_EQ(argc, 5);
2436
54
    FSReqWrapSync req_wrap_sync;
2437

29
    FS_SYNC_TRACE_BEGIN(utimes);
2438
54
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2439
             uv_fs_utime, *path, atime, mtime);
2440

29
    FS_SYNC_TRACE_END(utimes);
2441
  }
2442
63
}
2443
2444
19
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2445
19
  Environment* env = Environment::GetCurrent(args);
2446
2447
19
  const int argc = args.Length();
2448
19
  CHECK_GE(argc, 3);
2449
2450
19
  CHECK(args[0]->IsInt32());
2451
38
  const int fd = args[0].As<Int32>()->Value();
2452
2453
19
  CHECK(args[1]->IsNumber());
2454
38
  const double atime = args[1].As<Number>()->Value();
2455
2456
19
  CHECK(args[2]->IsNumber());
2457
38
  const double mtime = args[2].As<Number>()->Value();
2458
2459
19
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2460
19
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2461

14
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FUTIME, req_wrap_async)
2462
10
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2463
              uv_fs_futime, fd, atime, mtime);
2464
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2465
9
    CHECK_EQ(argc, 5);
2466
18
    FSReqWrapSync req_wrap_sync;
2467

11
    FS_SYNC_TRACE_BEGIN(futimes);
2468
9
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2469
             uv_fs_futime, fd, atime, mtime);
2470

11
    FS_SYNC_TRACE_END(futimes);
2471
  }
2472
19
}
2473
2474
16
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2475
16
  Environment* env = Environment::GetCurrent(args);
2476
2477
16
  const int argc = args.Length();
2478
16
  CHECK_GE(argc, 3);
2479
2480
32
  BufferValue path(env->isolate(), args[0]);
2481
16
  CHECK_NOT_NULL(*path);
2482
2483
16
  CHECK(args[1]->IsNumber());
2484
32
  const double atime = args[1].As<Number>()->Value();
2485
2486
16
  CHECK(args[2]->IsNumber());
2487
32
  const double mtime = args[2].As<Number>()->Value();
2488
2489
16
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2490
16
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2491

12
    FS_ASYNC_TRACE_BEGIN1(
2492
        UV_FS_LUTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2493
9
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2494
              uv_fs_lutime, *path, atime, mtime);
2495
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2496
7
    CHECK_EQ(argc, 5);
2497
14
    FSReqWrapSync req_wrap_sync;
2498

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2499
14
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2500
             uv_fs_lutime, *path, atime, mtime);
2501

7
    FS_SYNC_TRACE_END(lutimes);
2502
  }
2503
16
}
2504
2505
16
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2506
16
  Environment* env = Environment::GetCurrent(args);
2507
16
  Isolate* isolate = env->isolate();
2508
2509
16
  const int argc = args.Length();
2510
16
  CHECK_GE(argc, 2);
2511
2512
16
  BufferValue tmpl(isolate, args[0]);
2513
16
  CHECK_NOT_NULL(*tmpl);
2514
2515
16
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2516
2517
16
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2518
16
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2519

12
    FS_ASYNC_TRACE_BEGIN1(
2520
        UV_FS_MKDTEMP, req_wrap_async, "path", TRACE_STR_COPY(*tmpl))
2521
7
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2522
              uv_fs_mkdtemp, *tmpl);
2523
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2524
9
    CHECK_EQ(argc, 4);
2525
9
    FSReqWrapSync req_wrap_sync;
2526

11
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2527
18
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2528
             uv_fs_mkdtemp, *tmpl);
2529

11
    FS_SYNC_TRACE_END(mkdtemp);
2530
9
    const char* path = req_wrap_sync.req.path;
2531
2532
    Local<Value> error;
2533
    MaybeLocal<Value> rc =
2534
9
        StringBytes::Encode(isolate, path, encoding, &error);
2535
9
    if (rc.IsEmpty()) {
2536
      Local<Object> ctx = args[3].As<Object>();
2537
      ctx->Set(env->context(), env->error_string(), error).Check();
2538
      return;
2539
    }
2540
18
    args.GetReturnValue().Set(rc.ToLocalChecked());
2541
  }
2542
}
2543
2544
25
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2545
25
  tracker->TrackField("stats_field_array", stats_field_array);
2546
25
  tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2547
25
  tracker->TrackField("file_handle_read_wrap_freelist",
2548
25
                      file_handle_read_wrap_freelist);
2549
25
}
2550
2551
6309
BindingData::BindingData(Environment* env, v8::Local<v8::Object> wrap)
2552
    : SnapshotableObject(env, wrap, type_int),
2553
      stats_field_array(env->isolate(), kFsStatsBufferLength),
2554
6309
      stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {
2555
6309
  wrap->Set(env->context(),
2556
            FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"),
2557
25236
            stats_field_array.GetJSArray())
2558
      .Check();
2559
2560
6309
  wrap->Set(env->context(),
2561
            FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"),
2562
18927
            stats_field_bigint_array.GetJSArray())
2563
      .Check();
2564
6309
}
2565
2566
5520
void BindingData::Deserialize(Local<Context> context,
2567
                              Local<Object> holder,
2568
                              int index,
2569
                              InternalFieldInfoBase* info) {
2570
  DCHECK_EQ(index, BaseObject::kEmbedderType);
2571
11040
  HandleScope scope(context->GetIsolate());
2572
5520
  Environment* env = Environment::GetCurrent(context);
2573
5520
  BindingData* binding = env->AddBindingData<BindingData>(context, holder);
2574
5520
  CHECK_NOT_NULL(binding);
2575
5520
}
2576
2577
6
bool BindingData::PrepareForSerialization(Local<Context> context,
2578
                                          v8::SnapshotCreator* creator) {
2579
6
  CHECK(file_handle_read_wrap_freelist.empty());
2580
  // We'll just re-initialize the buffers in the constructor since their
2581
  // contents can be thrown away once consumed in the previous call.
2582
6
  stats_field_array.Release();
2583
6
  stats_field_bigint_array.Release();
2584
  // Return true because we need to maintain the reference to the binding from
2585
  // JS land.
2586
6
  return true;
2587
}
2588
2589
6
InternalFieldInfoBase* BindingData::Serialize(int index) {
2590
  DCHECK_EQ(index, BaseObject::kEmbedderType);
2591
  InternalFieldInfo* info =
2592
6
      InternalFieldInfoBase::New<InternalFieldInfo>(type());
2593
6
  return info;
2594
}
2595
2596
789
void Initialize(Local<Object> target,
2597
                Local<Value> unused,
2598
                Local<Context> context,
2599
                void* priv) {
2600
789
  Environment* env = Environment::GetCurrent(context);
2601
789
  Isolate* isolate = env->isolate();
2602
  BindingData* const binding_data =
2603
789
      env->AddBindingData<BindingData>(context, target);
2604
789
  if (binding_data == nullptr) return;
2605
2606
789
  SetMethod(context, target, "access", Access);
2607
789
  SetMethod(context, target, "close", Close);
2608
789
  SetMethod(context, target, "open", Open);
2609
789
  SetMethod(context, target, "openFileHandle", OpenFileHandle);
2610
789
  SetMethod(context, target, "read", Read);
2611
789
  SetMethod(context, target, "readBuffers", ReadBuffers);
2612
789
  SetMethod(context, target, "fdatasync", Fdatasync);
2613
789
  SetMethod(context, target, "fsync", Fsync);
2614
789
  SetMethod(context, target, "rename", Rename);
2615
789
  SetMethod(context, target, "ftruncate", FTruncate);
2616
789
  SetMethod(context, target, "rmdir", RMDir);
2617
789
  SetMethod(context, target, "mkdir", MKDir);
2618
789
  SetMethod(context, target, "readdir", ReadDir);
2619
789
  SetMethod(context, target, "internalModuleReadJSON", InternalModuleReadJSON);
2620
789
  SetMethod(context, target, "internalModuleStat", InternalModuleStat);
2621
789
  SetMethod(context, target, "stat", Stat);
2622
789
  SetMethod(context, target, "lstat", LStat);
2623
789
  SetMethod(context, target, "fstat", FStat);
2624
789
  SetMethod(context, target, "link", Link);
2625
789
  SetMethod(context, target, "symlink", Symlink);
2626
789
  SetMethod(context, target, "readlink", ReadLink);
2627
789
  SetMethod(context, target, "unlink", Unlink);
2628
789
  SetMethod(context, target, "writeBuffer", WriteBuffer);
2629
789
  SetMethod(context, target, "writeBuffers", WriteBuffers);
2630
789
  SetMethod(context, target, "writeString", WriteString);
2631
789
  SetMethod(context, target, "realpath", RealPath);
2632
789
  SetMethod(context, target, "copyFile", CopyFile);
2633
2634
789
  SetMethod(context, target, "chmod", Chmod);
2635
789
  SetMethod(context, target, "fchmod", FChmod);
2636
2637
789
  SetMethod(context, target, "chown", Chown);
2638
789
  SetMethod(context, target, "fchown", FChown);
2639
789
  SetMethod(context, target, "lchown", LChown);
2640
2641
789
  SetMethod(context, target, "utimes", UTimes);
2642
789
  SetMethod(context, target, "futimes", FUTimes);
2643
789
  SetMethod(context, target, "lutimes", LUTimes);
2644
2645
789
  SetMethod(context, target, "mkdtemp", Mkdtemp);
2646
2647
  target
2648
789
      ->Set(context,
2649
            FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2650
            Integer::New(
2651
                isolate,
2652
2367
                static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2653
      .Check();
2654
2655
789
  StatWatcher::Initialize(env, target);
2656
2657
  // Create FunctionTemplate for FSReqCallback
2658
789
  Local<FunctionTemplate> fst = NewFunctionTemplate(isolate, NewFSReqCallback);
2659
1578
  fst->InstanceTemplate()->SetInternalFieldCount(
2660
      FSReqBase::kInternalFieldCount);
2661
789
  fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2662
789
  SetConstructorFunction(context, target, "FSReqCallback", fst);
2663
2664
  // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2665
  // to do anything in the constructor, so we only store the instance template.
2666
789
  Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2667
1578
  fh_rw->InstanceTemplate()->SetInternalFieldCount(
2668
      FSReqBase::kInternalFieldCount);
2669
789
  fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2670
  Local<String> fhWrapString =
2671
789
      FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2672
789
  fh_rw->SetClassName(fhWrapString);
2673
789
  env->set_filehandlereadwrap_template(
2674
      fst->InstanceTemplate());
2675
2676
  // Create Function Template for FSReqPromise
2677
789
  Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2678
789
  fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2679
  Local<String> promiseString =
2680
789
      FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2681
789
  fpt->SetClassName(promiseString);
2682
789
  Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2683
789
  fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2684
789
  env->set_fsreqpromise_constructor_template(fpo);
2685
2686
  // Create FunctionTemplate for FileHandle
2687
789
  Local<FunctionTemplate> fd = NewFunctionTemplate(isolate, FileHandle::New);
2688
789
  fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2689
789
  SetProtoMethod(isolate, fd, "close", FileHandle::Close);
2690
789
  SetProtoMethod(isolate, fd, "releaseFD", FileHandle::ReleaseFD);
2691
789
  Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2692
789
  fdt->SetInternalFieldCount(FileHandle::kInternalFieldCount);
2693
789
  StreamBase::AddMethods(env, fd);
2694
789
  SetConstructorFunction(context, target, "FileHandle", fd);
2695
789
  env->set_fd_constructor_template(fdt);
2696
2697
  // Create FunctionTemplate for FileHandle::CloseReq
2698
789
  Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2699
789
  fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2700
                        "FileHandleCloseReq"));
2701
789
  fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2702
789
  Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2703
789
  fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2704
789
  env->set_fdclose_constructor_template(fdcloset);
2705
2706
  Local<Symbol> use_promises_symbol =
2707
    Symbol::New(isolate,
2708
789
                FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2709
789
  env->set_fs_use_promises_symbol(use_promises_symbol);
2710
789
  target->Set(context,
2711
              FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2712
2367
              use_promises_symbol).Check();
2713
}
2714
2715
3892
BindingData* FSReqBase::binding_data() {
2716
3892
  return binding_data_.get();
2717
}
2718
2719
5527
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2720
5527
  registry->Register(Access);
2721
5527
  StatWatcher::RegisterExternalReferences(registry);
2722
2723
5527
  registry->Register(Close);
2724
5527
  registry->Register(Open);
2725
5527
  registry->Register(OpenFileHandle);
2726
5527
  registry->Register(Read);
2727
5527
  registry->Register(ReadBuffers);
2728
5527
  registry->Register(Fdatasync);
2729
5527
  registry->Register(Fsync);
2730
5527
  registry->Register(Rename);
2731
5527
  registry->Register(FTruncate);
2732
5527
  registry->Register(RMDir);
2733
5527
  registry->Register(MKDir);
2734
5527
  registry->Register(ReadDir);
2735
5527
  registry->Register(InternalModuleReadJSON);
2736
5527
  registry->Register(InternalModuleStat);
2737
5527
  registry->Register(Stat);
2738
5527
  registry->Register(LStat);
2739
5527
  registry->Register(FStat);
2740
5527
  registry->Register(Link);
2741
5527
  registry->Register(Symlink);
2742
5527
  registry->Register(ReadLink);
2743
5527
  registry->Register(Unlink);
2744
5527
  registry->Register(WriteBuffer);
2745
5527
  registry->Register(WriteBuffers);
2746
5527
  registry->Register(WriteString);
2747
5527
  registry->Register(RealPath);
2748
5527
  registry->Register(CopyFile);
2749
2750
5527
  registry->Register(Chmod);
2751
5527
  registry->Register(FChmod);
2752
2753
5527
  registry->Register(Chown);
2754
5527
  registry->Register(FChown);
2755
5527
  registry->Register(LChown);
2756
2757
5527
  registry->Register(UTimes);
2758
5527
  registry->Register(FUTimes);
2759
5527
  registry->Register(LUTimes);
2760
2761
5527
  registry->Register(Mkdtemp);
2762
5527
  registry->Register(NewFSReqCallback);
2763
2764
5527
  registry->Register(FileHandle::New);
2765
5527
  registry->Register(FileHandle::Close);
2766
5527
  registry->Register(FileHandle::ReleaseFD);
2767
5527
  StreamBase::RegisterExternalReferences(registry);
2768
5527
}
2769
2770
}  // namespace fs
2771
2772
}  // end namespace node
2773
2774
5597
NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2775
5527
NODE_MODULE_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)