GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_file.cc Lines: 1521 1607 94.6 %
Date: 2022-11-05 03:21:31 Branches: 1002 1498 66.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
227921
inline int64_t GetOffset(Local<Value> value) {
111
229024
  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
1382
FileHandle::FileHandle(BindingData* binding_data,
235
1382
                       Local<Object> obj, int fd)
236
    : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
237
      StreamBase(env()),
238
      fd_(fd),
239
1382
      binding_data_(binding_data) {
240
1382
  MakeWeak();
241
1382
  StreamBase::AttachToObject(GetObject());
242
1382
}
243
244
1382
FileHandle* FileHandle::New(BindingData* binding_data,
245
                            int fd, Local<Object> obj) {
246
1382
  Environment* env = binding_data->env();
247
2749
  if (obj.IsEmpty() && !env->fd_constructor_template()
248
2749
                            ->NewInstance(env->context())
249
1367
                            .ToLocal(&obj)) {
250
    return nullptr;
251
  }
252
1382
  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
5348
FileHandle::~FileHandle() {
271
2674
  CHECK(!closing_);  // We should not be deleting while explicitly closing!
272
2674
  Close();           // Close synchronously and emit warning
273
2674
  CHECK(closed_);    // We have to be closed at the point
274
5348
}
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
    FS_SYNC_TRACE_BEGIN(close);
306
8
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
307

8
    FS_SYNC_TRACE_END(close);
308
8
    uv_fs_req_cleanup(&close_req);
309
  }
310
24
}
311
312
2
BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
313
    Environment* env,
314
    v8::Local<v8::Context> context,
315
    std::unique_ptr<worker::TransferData> self) {
316
2
  BindingData* bd = Environment::GetBindingData<BindingData>(context);
317
2
  if (bd == nullptr) return {};
318
319
2
  int fd = fd_;
320
2
  fd_ = -1;
321
2
  return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
322
}
323
324
// Close the file descriptor if it hasn't already been closed. A process
325
// warning will be emitted using a SetImmediate to avoid calling back to
326
// JS during GC. If closing the fd fails at this point, a fatal exception
327
// will crash the process immediately.
328
1337
inline void FileHandle::Close() {
329

1337
  if (closed_ || closing_) return;
330
  uv_fs_t req;
331
20
  CHECK_NE(fd_, -1);
332

20
  FS_SYNC_TRACE_BEGIN(close);
333
20
  int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
334

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

4038
  if (!close_resolver.IsEmpty() && !close_resolver->IsUndefined()) {
444
    CHECK(close_resolver->IsPromise());
445
    return close_resolver.As<Promise>();
446
  }
447
448
1346
  CHECK(!closed_);
449
1346
  CHECK(!closing_);
450
1346
  CHECK(!reading_);
451
452
1346
  auto maybe_resolver = Promise::Resolver::New(context);
453
1346
  CHECK(!maybe_resolver.IsEmpty());
454
1346
  Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
455
1346
  Local<Promise> promise = resolver.As<Promise>();
456
457
  Local<Object> close_req_obj;
458
1346
  if (!env()->fdclose_constructor_template()
459
2692
          ->NewInstance(env()->context()).ToLocal(&close_req_obj)) {
460
    return MaybeLocal<Promise>();
461
  }
462
1346
  closing_ = true;
463
2692
  object()->SetInternalField(FileHandle::kClosingPromiseSlot, promise);
464
465
2692
  CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
466
2692
  auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
467
1346
    CloseReq* req_wrap = CloseReq::from_req(req);
468

1740
    FS_ASYNC_TRACE_END1(
469
        req->fs_type, req_wrap, "result", static_cast<int>(req->result))
470
1346
    BaseObjectPtr<CloseReq> close(req_wrap);
471
1346
    CHECK(close);
472
1346
    close->file_handle()->AfterClose();
473
1346
    if (!close->env()->can_call_into_js()) return;
474
1345
    Isolate* isolate = close->env()->isolate();
475
1345
    if (req->result < 0) {
476
2
      HandleScope handle_scope(isolate);
477
2
      close->Reject(
478
1
          UVException(isolate, static_cast<int>(req->result), "close"));
479
    } else {
480
1344
      close->Resolve();
481
    }
482
  }};
483
1346
  CHECK_NE(fd_, -1);
484

1740
  FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, req)
485
1346
  int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
486
1346
  if (ret < 0) {
487
    req->Reject(UVException(isolate, ret, "close"));
488
    delete req;
489
  }
490
491
1346
  return scope.Escape(promise);
492
}
493
494
1346
void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
495
  FileHandle* fd;
496
1346
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
497
  Local<Promise> ret;
498
2692
  if (!fd->ClosePromise().ToLocal(&ret)) return;
499
2692
  args.GetReturnValue().Set(ret);
500
}
501
502
503
8
void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
504
  FileHandle* fd;
505
8
  ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
506
  // Just act as if this FileHandle has been closed.
507
8
  fd->AfterClose();
508
}
509
510
511
1374
void FileHandle::AfterClose() {
512
1374
  closing_ = false;
513
1374
  closed_ = true;
514
1374
  fd_ = -1;
515

1374
  if (reading_ && !persistent().IsEmpty())
516
    EmitRead(UV_EOF);
517
1374
}
518
519
void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
520
  tracker->TrackField("buffer", buffer_);
521
  tracker->TrackField("file_handle", this->file_handle_);
522
}
523
524
18
FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
525
  : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
526
18
    file_handle_(handle) {}
527
528
227
int FileHandle::ReadStart() {
529

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

213
  if (read_length_ >= 0 && read_length_ <= recommended_read)
575
7
    recommended_read = read_length_;
576
577
213
  read_wrap->buffer_ = EmitAlloc(recommended_read);
578
579
213
  current_read_ = std::move(read_wrap);
580

229
  FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, current_read_.get())
581
426
  current_read_->Dispatch(uv_fs_read,
582
                          fd_,
583
213
                          &current_read_->buffer_,
584
                          1,
585
                          read_offset_,
586
213
                          uv_fs_callback_t{[](uv_fs_t* req) {
587
    FileHandle* handle;
588
    {
589
213
      FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
590

229
      FS_ASYNC_TRACE_END1(
591
          req->fs_type, req_wrap, "result", static_cast<int>(req->result))
592
213
      handle = req_wrap->file_handle_;
593
213
      CHECK_EQ(handle->current_read_.get(), req_wrap);
594
    }
595
596
    // ReadStart() checks whether current_read_ is set to determine whether
597
    // a read is in progress. Moving it into a local variable makes sure that
598
    // the ReadStart() call below doesn't think we're still actively reading.
599
    BaseObjectPtr<FileHandleReadWrap> read_wrap =
600
426
        std::move(handle->current_read_);
601
602
213
    ssize_t result = req->result;
603
213
    uv_buf_t buffer = read_wrap->buffer_;
604
605
213
    uv_fs_req_cleanup(req);
606
607
    // Push the read wrap back to the freelist, or let it be destroyed
608
    // once we’re exiting the current scope.
609
213
    constexpr size_t kWantedFreelistFill = 100;
610
213
    auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
611
213
    if (freelist.size() < kWantedFreelistFill) {
612
213
      read_wrap->Reset();
613
213
      freelist.emplace_back(std::move(read_wrap));
614
    }
615
616
213
    if (result >= 0) {
617
      // Read at most as many bytes as we originally planned to.
618

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

3
  if (closing_ || closed_) {
659
3
    req_wrap->Done(0);
660
3
    return 1;
661
  }
662
  FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
663
  closing_ = true;
664
  CHECK_NE(fd_, -1);
665
  FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, wrap)
666
  wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
667
    FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
668
        FileHandleCloseWrap::from_req(req));
669
    FS_ASYNC_TRACE_END1(
670
        req->fs_type, wrap, "result", static_cast<int>(req->result))
671
    FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
672
    handle->AfterClose();
673
674
    int result = static_cast<int>(req->result);
675
    uv_fs_req_cleanup(req);
676
    wrap->Done(result);
677
  }});
678
679
  return 0;
680
}
681
682
683
4866
void FSReqCallback::Reject(Local<Value> reject) {
684
4866
  MakeCallback(env()->oncomplete_string(), 1, &reject);
685
4864
}
686
687
2535
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
688
2535
  Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
689
2535
}
690
691
48499
void FSReqCallback::Resolve(Local<Value> value) {
692
  Local<Value> argv[2] {
693
    Null(env()->isolate()),
694
    value
695
48499
  };
696
  MakeCallback(env()->oncomplete_string(),
697
89834
               value->IsUndefined() ? 1 : arraysize(argv),
698
138333
               argv);
699
48493
}
700
701
53365
void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
702
53365
  args.GetReturnValue().SetUndefined();
703
53365
}
704
705
53365
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
706
53365
  CHECK(args.IsConstructCall());
707
53365
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
708
106730
  new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
709
53365
}
710
711
58751
FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
712
    : wrap_(wrap),
713
      req_(req),
714
      handle_scope_(wrap->env()->isolate()),
715
58751
      context_scope_(wrap->env()->context()) {
716
58751
  CHECK_EQ(wrap_->req(), req);
717
58751
}
718
719
117486
FSReqAfterScope::~FSReqAfterScope() {
720
58743
  Clear();
721
58743
}
722
723
64198
void FSReqAfterScope::Clear() {
724
64198
  if (!wrap_) return;
725
726
58745
  uv_fs_req_cleanup(wrap_->req());
727
58745
  wrap_->Detach();
728
58745
  wrap_.reset();
729
}
730
731
// TODO(joyeecheung): create a normal context object, and
732
// construct the actual errors in the JS land using the context.
733
// The context should include fds for some fs APIs, currently they are
734
// missing in the error messages. The path, dest, syscall, fd, .etc
735
// can be put into the context before the binding is even invoked,
736
// the only information that has to come from the C++ layer is the
737
// error number (and possibly the syscall for abstraction),
738
// which is also why the errors should have been constructed
739
// in JS for more flexibility.
740
5275
void FSReqAfterScope::Reject(uv_fs_t* req) {
741
10548
  BaseObjectPtr<FSReqBase> wrap { wrap_ };
742
5275
  Local<Value> exception = UVException(wrap_->env()->isolate(),
743
5275
                                       static_cast<int>(req->result),
744
                                       wrap_->syscall(),
745
                                       nullptr,
746
                                       req->path,
747
5275
                                       wrap_->data());
748
5275
  Clear();
749
5275
  wrap->Reject(exception);
750
5273
}
751
752
58751
bool FSReqAfterScope::Proceed() {
753
58751
  if (!wrap_->env()->can_call_into_js()) {
754
142
    return false;
755
  }
756
757
58609
  if (req_->result < 0) {
758
5275
    Reject(req_);
759
5273
    return false;
760
  }
761
53334
  return true;
762
}
763
764
7593
void AfterNoArgs(uv_fs_t* req) {
765
7593
  FSReqBase* req_wrap = FSReqBase::from_req(req);
766
15181
  FSReqAfterScope after(req_wrap, req);
767

7892
  FS_ASYNC_TRACE_END1(
768
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
769
7593
  if (after.Proceed())
770
14640
    req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
771
7588
}
772
773
8842
void AfterStat(uv_fs_t* req) {
774
8842
  FSReqBase* req_wrap = FSReqBase::from_req(req);
775
17684
  FSReqAfterScope after(req_wrap, req);
776

9291
  FS_ASYNC_TRACE_END1(
777
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
778
8842
  if (after.Proceed()) {
779
4185
    req_wrap->ResolveStat(&req->statbuf);
780
  }
781
8842
}
782
783
39609
void AfterInteger(uv_fs_t* req) {
784
39609
  FSReqBase* req_wrap = FSReqBase::from_req(req);
785
79216
  FSReqAfterScope after(req_wrap, req);
786

40160
  FS_ASYNC_TRACE_END1(
787
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
788
39609
  int result = static_cast<int>(req->result);
789

39609
  if (result >= 0 && req_wrap->is_plain_open())
790
5483
    req_wrap->env()->AddUnmanagedFd(result);
791
792
39609
  if (after.Proceed())
793
78860
    req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
794
39607
}
795
796
1651
void AfterOpenFileHandle(uv_fs_t* req) {
797
1651
  FSReqBase* req_wrap = FSReqBase::from_req(req);
798
1651
  FSReqAfterScope after(req_wrap, req);
799

2049
  FS_ASYNC_TRACE_END1(
800
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
801
1651
  if (after.Proceed()) {
802
1364
    FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
803
1364
                                     static_cast<int>(req->result));
804
1364
    if (fd == nullptr) return;
805
2728
    req_wrap->Resolve(fd->object());
806
  }
807
}
808
809
// Reverse the logic applied by path.toNamespacedPath() to create a
810
// namespace-prefixed path.
811
513
void FromNamespacedPath(std::string* path) {
812
#ifdef _WIN32
813
  if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
814
    *path = path->substr(8);
815
    path->insert(0, "\\\\");
816
  } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
817
    *path = path->substr(4);
818
  }
819
#endif
820
513
}
821
822
363
void AfterMkdirp(uv_fs_t* req) {
823
363
  FSReqBase* req_wrap = FSReqBase::from_req(req);
824
363
  FSReqAfterScope after(req_wrap, req);
825

468
  FS_ASYNC_TRACE_END1(
826
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
827
363
  if (after.Proceed()) {
828
714
    std::string first_path(req_wrap->continuation_data()->first_path());
829
357
    if (first_path.empty())
830
252
      return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
831
231
    FromNamespacedPath(&first_path);
832
    Local<Value> path;
833
    Local<Value> error;
834
231
    if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
835
                             req_wrap->encoding(),
836
462
                             &error).ToLocal(&path)) {
837
      return req_wrap->Reject(error);
838
    }
839
231
    return req_wrap->Resolve(path);
840
  }
841
}
842
843
10
void AfterStringPath(uv_fs_t* req) {
844
10
  FSReqBase* req_wrap = FSReqBase::from_req(req);
845
20
  FSReqAfterScope after(req_wrap, req);
846

16
  FS_ASYNC_TRACE_END1(
847
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
848
  MaybeLocal<Value> link;
849
  Local<Value> error;
850
851
10
  if (after.Proceed()) {
852
    link = StringBytes::Encode(req_wrap->env()->isolate(),
853
                               req->path,
854
                               req_wrap->encoding(),
855
9
                               &error);
856
9
    if (link.IsEmpty())
857
      req_wrap->Reject(error);
858
    else
859
18
      req_wrap->Resolve(link.ToLocalChecked());
860
  }
861
10
}
862
863
66
void AfterStringPtr(uv_fs_t* req) {
864
66
  FSReqBase* req_wrap = FSReqBase::from_req(req);
865
131
  FSReqAfterScope after(req_wrap, req);
866

78
  FS_ASYNC_TRACE_END1(
867
      req->fs_type, req_wrap, "result", static_cast<int>(req->result))
868
  MaybeLocal<Value> link;
869
  Local<Value> error;
870
871
66
  if (after.Proceed()) {
872
    link = StringBytes::Encode(req_wrap->env()->isolate(),
873
60
                               static_cast<const char*>(req->ptr),
874
                               req_wrap->encoding(),
875
60
                               &error);
876
60
    if (link.IsEmpty())
877
      req_wrap->Reject(error);
878
    else
879
120
      req_wrap->Resolve(link.ToLocalChecked());
880
  }
881
65
}
882
883
223
void AfterScanDir(uv_fs_t* req) {
884
223
  FSReqBase* req_wrap = FSReqBase::from_req(req);
885
223
  FSReqAfterScope after(req_wrap, req);
886

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

67
    FS_ASYNC_TRACE_BEGIN1(
949
        UV_FS_ACCESS, req_wrap_async, "path", TRACE_STR_COPY(*path))
950
46
    AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
951
              uv_fs_access, *path, mode);
952
  } else {  // access(path, mode, undefined, ctx)
953
4177
    CHECK_EQ(argc, 4);
954
8354
    FSReqWrapSync req_wrap_sync;
955

4179
    FS_SYNC_TRACE_BEGIN(access);
956
8354
    SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
957

4179
    FS_SYNC_TRACE_END(access);
958
  }
959
4223
}
960
961
962
67548
void Close(const FunctionCallbackInfo<Value>& args) {
963
67548
  Environment* env = Environment::GetCurrent(args);
964
965
67548
  const int argc = args.Length();
966
67548
  CHECK_GE(argc, 2);
967
968
67548
  CHECK(args[0]->IsInt32());
969
135096
  int fd = args[0].As<Int32>()->Value();
970
67548
  env->RemoveUnmanagedFd(fd);
971
972
67548
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
973
67548
  if (req_wrap_async != nullptr) {  // close(fd, req)
974

5630
    FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, req_wrap_async)
975
5398
    AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
976
              uv_fs_close, fd);
977
  } else {  // close(fd, undefined, ctx)
978
62150
    CHECK_EQ(argc, 3);
979
124300
    FSReqWrapSync req_wrap_sync;
980

62207
    FS_SYNC_TRACE_BEGIN(close);
981
62150
    SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
982

62207
    FS_SYNC_TRACE_END(close);
983
  }
984
67548
}
985
986
987
// Used to speed up module loading. Returns an array [string, boolean]
988
58961
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
989
58961
  Environment* env = Environment::GetCurrent(args);
990
58961
  Isolate* isolate = env->isolate();
991
58961
  uv_loop_t* loop = env->event_loop();
992
993
117922
  CHECK(args[0]->IsString());
994
58961
  node::Utf8Value path(isolate, args[0]);
995
996
58961
  if (strlen(*path) != path.length()) {
997
3
    args.GetReturnValue().Set(Array::New(isolate));
998
3
    return;  // Contains a nul byte.
999
  }
1000
  uv_fs_t open_req;
1001
58958
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
1002
58958
  uv_fs_req_cleanup(&open_req);
1003
1004
58958
  if (fd < 0) {
1005
52629
    args.GetReturnValue().Set(Array::New(isolate));
1006
52629
    return;
1007
  }
1008
1009
6329
  auto defer_close = OnScopeLeave([fd, loop]() {
1010
    uv_fs_t close_req;
1011
6329
    CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
1012
6329
    uv_fs_req_cleanup(&close_req);
1013
6329
  });
1014
1015
6329
  const size_t kBlockSize = 32 << 10;
1016
6329
  std::vector<char> chars;
1017
6329
  int64_t offset = 0;
1018
  ssize_t numchars;
1019
  do {
1020
6329
    const size_t start = chars.size();
1021
6329
    chars.resize(start + kBlockSize);
1022
1023
    uv_buf_t buf;
1024
6329
    buf.base = &chars[start];
1025
6329
    buf.len = kBlockSize;
1026
1027
    uv_fs_t read_req;
1028
6329
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
1029
6329
    uv_fs_req_cleanup(&read_req);
1030
1031
6329
    if (numchars < 0) {
1032
1
      args.GetReturnValue().Set(Array::New(isolate));
1033
1
      return;
1034
    }
1035
6328
    offset += numchars;
1036
6328
  } while (static_cast<size_t>(numchars) == kBlockSize);
1037
1038
6328
  size_t start = 0;
1039

6328
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
1040
1
    start = 3;  // Skip UTF-8 BOM.
1041
  }
1042
1043
6328
  const size_t size = offset - start;
1044
6328
  char* p = &chars[start];
1045
6328
  char* pe = &chars[size];
1046
  char* pos[2];
1047
6328
  char** ppos = &pos[0];
1048
1049
100946
  while (p < pe) {
1050
100938
    char c = *p++;
1051

100938
    if (c == '\\' && p < pe && *p == '"') p++;
1052
100938
    if (c != '"') continue;
1053
15214
    *ppos++ = p;
1054
15214
    if (ppos < &pos[2]) continue;
1055
7607
    ppos = &pos[0];
1056
1057
7607
    char* s = &pos[0][0];
1058
7607
    char* se = &pos[1][-1];  // Exclude quote.
1059
7607
    size_t n = se - s;
1060
1061
7607
    if (n == 4) {
1062
6311
      if (0 == memcmp(s, "main", 4)) break;
1063
6285
      if (0 == memcmp(s, "name", 4)) break;
1064
41
      if (0 == memcmp(s, "type", 4)) break;
1065
1296
    } else if (n == 7) {
1066
14
      if (0 == memcmp(s, "exports", 7)) break;
1067
8
      if (0 == memcmp(s, "imports", 7)) break;
1068
    }
1069
  }
1070
1071
1072
  Local<Value> return_value[] = {
1073
6328
    String::NewFromUtf8(isolate,
1074
6328
                        &chars[start],
1075
                        v8::NewStringType::kNormal,
1076
6328
                        size).ToLocalChecked(),
1077
    Boolean::New(isolate, p < pe ? true : false)
1078
18984
  };
1079
12656
  args.GetReturnValue().Set(
1080
    Array::New(isolate, return_value, arraysize(return_value)));
1081
}
1082
1083
// Used to speed up module loading.  Returns 0 if the path refers to
1084
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
1085
// The speedup comes from not creating thousands of Stat and Error objects.
1086
158572
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
1087
158572
  Environment* env = Environment::GetCurrent(args);
1088
1089
317144
  CHECK(args[0]->IsString());
1090
158572
  node::Utf8Value path(env->isolate(), args[0]);
1091
1092
  uv_fs_t req;
1093
158572
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1094
158572
  if (rc == 0) {
1095
72412
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1096
72412
    rc = !!(s->st_mode & S_IFDIR);
1097
  }
1098
158572
  uv_fs_req_cleanup(&req);
1099
1100
317144
  args.GetReturnValue().Set(rc);
1101
158572
}
1102
1103
18364
static void Stat(const FunctionCallbackInfo<Value>& args) {
1104
18364
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1105
18364
  Environment* env = binding_data->env();
1106
1107
18364
  const int argc = args.Length();
1108
18364
  CHECK_GE(argc, 2);
1109
1110
18364
  BufferValue path(env->isolate(), args[0]);
1111
18364
  CHECK_NOT_NULL(*path);
1112
1113
18364
  bool use_bigint = args[1]->IsTrue();
1114
18364
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1115
18364
  if (req_wrap_async != nullptr) {  // stat(path, use_bigint, req)
1116

2867
    FS_ASYNC_TRACE_BEGIN1(
1117
        UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1118
2740
    AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1119
              uv_fs_stat, *path);
1120
  } else {  // stat(path, use_bigint, undefined, ctx)
1121
15624
    CHECK_EQ(argc, 4);
1122
15624
    FSReqWrapSync req_wrap_sync;
1123

15626
    FS_SYNC_TRACE_BEGIN(stat);
1124
31248
    int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1125

15626
    FS_SYNC_TRACE_END(stat);
1126
15624
    if (err != 0) {
1127
651
      return;  // error info is in ctx
1128
    }
1129
1130
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1131
14973
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1132
29946
    args.GetReturnValue().Set(arr);
1133
  }
1134
}
1135
1136
120350
static void LStat(const FunctionCallbackInfo<Value>& args) {
1137
120350
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1138
120350
  Environment* env = binding_data->env();
1139
1140
120350
  const int argc = args.Length();
1141
120350
  CHECK_GE(argc, 3);
1142
1143
120350
  BufferValue path(env->isolate(), args[0]);
1144
120350
  CHECK_NOT_NULL(*path);
1145
1146
120350
  bool use_bigint = args[1]->IsTrue();
1147
120350
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1148
120350
  if (req_wrap_async != nullptr) {  // lstat(path, use_bigint, req)
1149

4929
    FS_ASYNC_TRACE_BEGIN1(
1150
        UV_FS_LSTAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1151
4811
    AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1152
              uv_fs_lstat, *path);
1153
  } else {  // lstat(path, use_bigint, undefined, ctx)
1154
115539
    CHECK_EQ(argc, 4);
1155
115539
    FSReqWrapSync req_wrap_sync;
1156

115556
    FS_SYNC_TRACE_BEGIN(lstat);
1157
231078
    int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1158
                       *path);
1159

115556
    FS_SYNC_TRACE_END(lstat);
1160
115539
    if (err != 0) {
1161
494
      return;  // error info is in ctx
1162
    }
1163
1164
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1165
115045
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1166
230090
    args.GetReturnValue().Set(arr);
1167
  }
1168
}
1169
1170
56685
static void FStat(const FunctionCallbackInfo<Value>& args) {
1171
56685
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1172
56685
  Environment* env = binding_data->env();
1173
1174
56685
  const int argc = args.Length();
1175
56685
  CHECK_GE(argc, 2);
1176
1177
56685
  CHECK(args[0]->IsInt32());
1178
113370
  int fd = args[0].As<Int32>()->Value();
1179
1180
56685
  bool use_bigint = args[1]->IsTrue();
1181
56685
  FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1182
56685
  if (req_wrap_async != nullptr) {  // fstat(fd, use_bigint, req)
1183

1723
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FSTAT, req_wrap_async)
1184
1293
    AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1185
              uv_fs_fstat, fd);
1186
  } else {  // fstat(fd, use_bigint, undefined, ctx)
1187
55392
    CHECK_EQ(argc, 4);
1188
55392
    FSReqWrapSync req_wrap_sync;
1189

55401
    FS_SYNC_TRACE_BEGIN(fstat);
1190
55392
    int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1191

55401
    FS_SYNC_TRACE_END(fstat);
1192
55392
    if (err != 0) {
1193
21
      return;  // error info is in ctx
1194
    }
1195
1196
    Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1197
55371
        static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1198
110742
    args.GetReturnValue().Set(arr);
1199
  }
1200
}
1201
1202
466
static void Symlink(const FunctionCallbackInfo<Value>& args) {
1203
466
  Environment* env = Environment::GetCurrent(args);
1204
466
  Isolate* isolate = env->isolate();
1205
1206
466
  const int argc = args.Length();
1207
466
  CHECK_GE(argc, 4);
1208
1209
932
  BufferValue target(isolate, args[0]);
1210
466
  CHECK_NOT_NULL(*target);
1211
932
  BufferValue path(isolate, args[1]);
1212
466
  CHECK_NOT_NULL(*path);
1213
1214
466
  CHECK(args[2]->IsInt32());
1215
932
  int flags = args[2].As<Int32>()->Value();
1216
1217
466
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1218
466
  if (req_wrap_async != nullptr) {  // symlink(target, path, flags, req)
1219

241
    FS_ASYNC_TRACE_BEGIN2(UV_FS_SYMLINK,
1220
                          req_wrap_async,
1221
                          "target",
1222
                          TRACE_STR_COPY(*target),
1223
                          "path",
1224
                          TRACE_STR_COPY(*path))
1225
131
    AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1226
                  UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1227
  } else {  // symlink(target, path, flags, undefinec, ctx)
1228
335
    CHECK_EQ(argc, 5);
1229
670
    FSReqWrapSync req_wrap_sync;
1230

339
    FS_SYNC_TRACE_BEGIN(symlink);
1231
670
    SyncCall(env, args[4], &req_wrap_sync, "symlink",
1232
             uv_fs_symlink, *target, *path, flags);
1233

339
    FS_SYNC_TRACE_END(symlink);
1234
  }
1235
466
}
1236
1237
12
static void Link(const FunctionCallbackInfo<Value>& args) {
1238
12
  Environment* env = Environment::GetCurrent(args);
1239
12
  Isolate* isolate = env->isolate();
1240
1241
12
  const int argc = args.Length();
1242
12
  CHECK_GE(argc, 3);
1243
1244
24
  BufferValue src(isolate, args[0]);
1245
12
  CHECK_NOT_NULL(*src);
1246
1247
24
  BufferValue dest(isolate, args[1]);
1248
12
  CHECK_NOT_NULL(*dest);
1249
1250
12
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1251
12
  if (req_wrap_async != nullptr) {  // link(src, dest, req)
1252

9
    FS_ASYNC_TRACE_BEGIN2(UV_FS_LINK,
1253
                          req_wrap_async,
1254
                          "src",
1255
                          TRACE_STR_COPY(*src),
1256
                          "dest",
1257
                          TRACE_STR_COPY(*dest))
1258
5
    AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1259
                  AfterNoArgs, uv_fs_link, *src, *dest);
1260
  } else {  // link(src, dest)
1261
7
    CHECK_EQ(argc, 4);
1262
14
    FSReqWrapSync req_wrap_sync;
1263

13
    FS_SYNC_TRACE_BEGIN(link);
1264
14
    SyncCall(env, args[3], &req_wrap_sync, "link",
1265
             uv_fs_link, *src, *dest);
1266

13
    FS_SYNC_TRACE_END(link);
1267
  }
1268
12
}
1269
1270
109
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1271
109
  Environment* env = Environment::GetCurrent(args);
1272
109
  Isolate* isolate = env->isolate();
1273
1274
109
  const int argc = args.Length();
1275
109
  CHECK_GE(argc, 3);
1276
1277
109
  BufferValue path(isolate, args[0]);
1278
109
  CHECK_NOT_NULL(*path);
1279
1280
109
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1281
1282
109
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1283
109
  if (req_wrap_async != nullptr) {  // readlink(path, encoding, req)
1284

53
    FS_ASYNC_TRACE_BEGIN1(
1285
        UV_FS_READLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1286
43
    AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1287
              uv_fs_readlink, *path);
1288
  } else {
1289
66
    CHECK_EQ(argc, 4);
1290
66
    FSReqWrapSync req_wrap_sync;
1291

68
    FS_SYNC_TRACE_BEGIN(readlink);
1292
132
    int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1293
                       uv_fs_readlink, *path);
1294

68
    FS_SYNC_TRACE_END(readlink);
1295
66
    if (err < 0) {
1296
2
      return;  // syscall failed, no need to continue, error info is in ctx
1297
    }
1298
64
    const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1299
1300
    Local<Value> error;
1301
    MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1302
                                               link_path,
1303
                                               encoding,
1304
64
                                               &error);
1305
64
    if (rc.IsEmpty()) {
1306
      Local<Object> ctx = args[3].As<Object>();
1307
      ctx->Set(env->context(), env->error_string(), error).Check();
1308
      return;
1309
    }
1310
1311
128
    args.GetReturnValue().Set(rc.ToLocalChecked());
1312
  }
1313
}
1314
1315
7
static void Rename(const FunctionCallbackInfo<Value>& args) {
1316
7
  Environment* env = Environment::GetCurrent(args);
1317
7
  Isolate* isolate = env->isolate();
1318
1319
7
  const int argc = args.Length();
1320
7
  CHECK_GE(argc, 3);
1321
1322
14
  BufferValue old_path(isolate, args[0]);
1323
7
  CHECK_NOT_NULL(*old_path);
1324
14
  BufferValue new_path(isolate, args[1]);
1325
7
  CHECK_NOT_NULL(*new_path);
1326
1327
7
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1328
7
  if (req_wrap_async != nullptr) {
1329

7
    FS_ASYNC_TRACE_BEGIN2(UV_FS_RENAME,
1330
                          req_wrap_async,
1331
                          "old_path",
1332
                          TRACE_STR_COPY(*old_path),
1333
                          "new_path",
1334
                          TRACE_STR_COPY(*new_path))
1335
4
    AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1336
                  new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1337
                  *old_path, *new_path);
1338
  } else {
1339
3
    CHECK_EQ(argc, 4);
1340
6
    FSReqWrapSync req_wrap_sync;
1341

5
    FS_SYNC_TRACE_BEGIN(rename);
1342
6
    SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1343
             *old_path, *new_path);
1344

5
    FS_SYNC_TRACE_END(rename);
1345
  }
1346
7
}
1347
1348
70
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1349
70
  Environment* env = Environment::GetCurrent(args);
1350
1351
70
  const int argc = args.Length();
1352
70
  CHECK_GE(argc, 3);
1353
1354
70
  CHECK(args[0]->IsInt32());
1355
140
  const int fd = args[0].As<Int32>()->Value();
1356
1357
70
  CHECK(IsSafeJsInt(args[1]));
1358
140
  const int64_t len = args[1].As<Integer>()->Value();
1359
1360
70
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1361
70
  if (req_wrap_async != nullptr) {
1362

71
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FTRUNCATE, req_wrap_async)
1363
55
    AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1364
              uv_fs_ftruncate, fd, len);
1365
  } else {
1366
15
    CHECK_EQ(argc, 4);
1367
30
    FSReqWrapSync req_wrap_sync;
1368

17
    FS_SYNC_TRACE_BEGIN(ftruncate);
1369
15
    SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1370
             len);
1371

17
    FS_SYNC_TRACE_END(ftruncate);
1372
  }
1373
70
}
1374
1375
8
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1376
8
  Environment* env = Environment::GetCurrent(args);
1377
1378
8
  const int argc = args.Length();
1379
8
  CHECK_GE(argc, 2);
1380
1381
8
  CHECK(args[0]->IsInt32());
1382
16
  const int fd = args[0].As<Int32>()->Value();
1383
1384
8
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1385
8
  if (req_wrap_async != nullptr) {
1386

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FDATASYNC, req_wrap_async)
1387
5
    AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1388
              uv_fs_fdatasync, fd);
1389
  } else {
1390
3
    CHECK_EQ(argc, 3);
1391
6
    FSReqWrapSync req_wrap_sync;
1392

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

5
    FS_SYNC_TRACE_END(fdatasync);
1395
  }
1396
8
}
1397
1398
22
static void Fsync(const FunctionCallbackInfo<Value>& args) {
1399
22
  Environment* env = Environment::GetCurrent(args);
1400
1401
22
  const int argc = args.Length();
1402
22
  CHECK_GE(argc, 2);
1403
1404
22
  CHECK(args[0]->IsInt32());
1405
44
  const int fd = args[0].As<Int32>()->Value();
1406
1407
22
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1408
22
  if (req_wrap_async != nullptr) {
1409

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FSYNC, req_wrap_async)
1410
5
    AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1411
              uv_fs_fsync, fd);
1412
  } else {
1413
17
    CHECK_EQ(argc, 3);
1414
34
    FSReqWrapSync req_wrap_sync;
1415

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

19
    FS_SYNC_TRACE_END(fsync);
1418
  }
1419
22
}
1420
1421
2780
static void Unlink(const FunctionCallbackInfo<Value>& args) {
1422
2780
  Environment* env = Environment::GetCurrent(args);
1423
1424
2780
  const int argc = args.Length();
1425
2780
  CHECK_GE(argc, 2);
1426
1427
5560
  BufferValue path(env->isolate(), args[0]);
1428
2780
  CHECK_NOT_NULL(*path);
1429
1430
2780
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1431
2780
  if (req_wrap_async != nullptr) {
1432

1246
    FS_ASYNC_TRACE_BEGIN1(
1433
        UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1434
1137
    AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1435
              uv_fs_unlink, *path);
1436
  } else {
1437
1643
    CHECK_EQ(argc, 3);
1438
3286
    FSReqWrapSync req_wrap_sync;
1439

1698
    FS_SYNC_TRACE_BEGIN(unlink);
1440
3286
    SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1441

1698
    FS_SYNC_TRACE_END(unlink);
1442
  }
1443
2780
}
1444
1445
2011
static void RMDir(const FunctionCallbackInfo<Value>& args) {
1446
2011
  Environment* env = Environment::GetCurrent(args);
1447
1448
2011
  const int argc = args.Length();
1449
2011
  CHECK_GE(argc, 2);
1450
1451
4022
  BufferValue path(env->isolate(), args[0]);
1452
2011
  CHECK_NOT_NULL(*path);
1453
1454
2011
  FSReqBase* req_wrap_async = GetReqWrap(args, 1);  // rmdir(path, req)
1455
2011
  if (req_wrap_async != nullptr) {
1456

273
    FS_ASYNC_TRACE_BEGIN1(
1457
        UV_FS_RMDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1458
262
    AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1459
              uv_fs_rmdir, *path);
1460
  } else {  // rmdir(path, undefined, ctx)
1461
1749
    CHECK_EQ(argc, 3);
1462
3498
    FSReqWrapSync req_wrap_sync;
1463

1755
    FS_SYNC_TRACE_BEGIN(rmdir);
1464
3498
    SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1465
             uv_fs_rmdir, *path);
1466

1755
    FS_SYNC_TRACE_END(rmdir);
1467
  }
1468
2011
}
1469
1470
6615
int MKDirpSync(uv_loop_t* loop,
1471
               uv_fs_t* req,
1472
               const std::string& path,
1473
               int mode,
1474
               uv_fs_cb cb) {
1475
6615
  FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1476
1477
  // on the first iteration of algorithm, stash state information.
1478
6615
  if (req_wrap->continuation_data() == nullptr) {
1479
6615
    req_wrap->set_continuation_data(
1480
13230
        std::make_unique<FSContinuationData>(req, mode, cb));
1481
6615
    req_wrap->continuation_data()->PushPath(std::move(path));
1482
  }
1483
1484
13076
  while (req_wrap->continuation_data()->paths().size() > 0) {
1485
6769
    std::string next_path = req_wrap->continuation_data()->PopPath();
1486
6769
    int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1487
    while (true) {
1488

6770
      switch (err) {
1489
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1490
        // ~FSReqWrapSync():
1491
380
        case 0:
1492
380
          req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1493
380
          if (req_wrap->continuation_data()->paths().size() == 0) {
1494
304
            return 0;
1495
          }
1496
76
          break;
1497
2
        case UV_EACCES:
1498
        case UV_ENOSPC:
1499
        case UV_ENOTDIR:
1500
        case UV_EPERM: {
1501
2
          return err;
1502
        }
1503
78
        case UV_ENOENT: {
1504
          std::string dirname = next_path.substr(0,
1505
78
                                        next_path.find_last_of(kPathSeparator));
1506
78
          if (dirname != next_path) {
1507
77
            req_wrap->continuation_data()->PushPath(std::move(next_path));
1508
77
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1509
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1510
1
            err = UV_EEXIST;
1511
1
            continue;
1512
          }
1513
77
          break;
1514
        }
1515
6310
        default:
1516
6310
          uv_fs_req_cleanup(req);
1517
6310
          int orig_err = err;
1518
6310
          err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1519

6310
          if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1520
1
            uv_fs_req_cleanup(req);
1521

2
            if (orig_err == UV_EEXIST &&
1522
1
              req_wrap->continuation_data()->paths().size() > 0) {
1523
              return UV_ENOTDIR;
1524
            }
1525
1
            return UV_EEXIST;
1526
          }
1527
6309
          if (err < 0) return err;
1528
6308
          break;
1529
      }
1530
6461
      break;
1531
1
    }
1532
6461
    uv_fs_req_cleanup(req);
1533
  }
1534
1535
6307
  return 0;
1536
}
1537
1538
811
int MKDirpAsync(uv_loop_t* loop,
1539
                uv_fs_t* req,
1540
                const char* path,
1541
                int mode,
1542
                uv_fs_cb cb) {
1543
811
  FSReqBase* req_wrap = FSReqBase::from_req(req);
1544
  // on the first iteration of algorithm, stash state information.
1545
811
  if (req_wrap->continuation_data() == nullptr) {
1546
363
    req_wrap->set_continuation_data(
1547
726
        std::make_unique<FSContinuationData>(req, mode, cb));
1548
363
    req_wrap->continuation_data()->PushPath(std::move(path));
1549
  }
1550
1551
  // on each iteration of algorithm, mkdir directory on top of stack.
1552
811
  std::string next_path = req_wrap->continuation_data()->PopPath();
1553
811
  int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1554
811
                        uv_fs_callback_t{[](uv_fs_t* req) {
1555
811
    FSReqBase* req_wrap = FSReqBase::from_req(req);
1556
811
    Environment* env = req_wrap->env();
1557
811
    uv_loop_t* loop = env->event_loop();
1558
1622
    std::string path = req->path;
1559
811
    int err = static_cast<int>(req->result);
1560
1561
    while (true) {
1562

812
      switch (err) {
1563
        // Note: uv_fs_req_cleanup in terminal paths will be called by
1564
        // FSReqAfterScope::~FSReqAfterScope()
1565
337
        case 0: {
1566
337
          if (req_wrap->continuation_data()->paths().size() == 0) {
1567
231
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1568
231
            req_wrap->continuation_data()->Done(0);
1569
          } else {
1570
106
            req_wrap->continuation_data()->MaybeSetFirstPath(path);
1571
106
            uv_fs_req_cleanup(req);
1572
106
            MKDirpAsync(loop, req, path.c_str(),
1573
                        req_wrap->continuation_data()->mode(), nullptr);
1574
          }
1575
337
          break;
1576
        }
1577
3
        case UV_EACCES:
1578
        case UV_ENOTDIR:
1579
        case UV_EPERM: {
1580
3
          req_wrap->continuation_data()->Done(err);
1581
3
          break;
1582
        }
1583
225
        case UV_ENOENT: {
1584
          std::string dirname = path.substr(0,
1585
225
                                            path.find_last_of(kPathSeparator));
1586
225
          if (dirname != path) {
1587
224
            req_wrap->continuation_data()->PushPath(std::move(path));
1588
224
            req_wrap->continuation_data()->PushPath(std::move(dirname));
1589
1
          } else if (req_wrap->continuation_data()->paths().size() == 0) {
1590
1
            err = UV_EEXIST;
1591
1
            continue;
1592
          }
1593
224
          uv_fs_req_cleanup(req);
1594
224
          MKDirpAsync(loop, req, path.c_str(),
1595
                      req_wrap->continuation_data()->mode(), nullptr);
1596
224
          break;
1597
        }
1598
247
        default:
1599
247
          uv_fs_req_cleanup(req);
1600
          // Stash err for use in the callback.
1601
247
          req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1602
247
          int err = uv_fs_stat(loop, req, path.c_str(),
1603
247
                               uv_fs_callback_t{[](uv_fs_t* req) {
1604
247
            FSReqBase* req_wrap = FSReqBase::from_req(req);
1605
247
            int err = static_cast<int>(req->result);
1606

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

118
              if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1609
118
                Environment* env = req_wrap->env();
1610
118
                uv_loop_t* loop = env->event_loop();
1611
118
                std::string path = req->path;
1612
118
                uv_fs_req_cleanup(req);
1613
118
                MKDirpAsync(loop, req, path.c_str(),
1614
                            req_wrap->continuation_data()->mode(), nullptr);
1615
118
                return;
1616
              }
1617
              err = UV_ENOTDIR;
1618
            }
1619
            // verify that the path pointed to is actually a directory.
1620

129
            if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1621
129
            req_wrap->continuation_data()->Done(err);
1622
247
          }});
1623
247
          if (err < 0) req_wrap->continuation_data()->Done(err);
1624
247
          break;
1625
      }
1626
811
      break;
1627
1
    }
1628
811
  }});
1629
1630
811
  return err;
1631
}
1632
1633
288
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1634
                   FSReqWrapSync* req_wrap, const char* path, int mode) {
1635
288
  env->PrintSyncTrace();
1636
288
  int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1637
                       nullptr);
1638
288
  if (err < 0) {
1639
4
    v8::Local<v8::Context> context = env->context();
1640
4
    v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1641
4
    v8::Isolate* isolate = env->isolate();
1642
4
    ctx_obj->Set(context,
1643
                 env->errno_string(),
1644
16
                 v8::Integer::New(isolate, err)).Check();
1645
4
    ctx_obj->Set(context,
1646
                 env->syscall_string(),
1647
16
                 OneByteString(isolate, "mkdir")).Check();
1648
  }
1649
288
  return err;
1650
}
1651
1652
1881
static void MKDir(const FunctionCallbackInfo<Value>& args) {
1653
1881
  Environment* env = Environment::GetCurrent(args);
1654
1655
1881
  const int argc = args.Length();
1656
1881
  CHECK_GE(argc, 4);
1657
1658
1881
  BufferValue path(env->isolate(), args[0]);
1659
1881
  CHECK_NOT_NULL(*path);
1660
1661
1881
  CHECK(args[1]->IsInt32());
1662
3762
  const int mode = args[1].As<Int32>()->Value();
1663
1664
1881
  CHECK(args[2]->IsBoolean());
1665
1881
  bool mkdirp = args[2]->IsTrue();
1666
1667
1881
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1668
1881
  if (req_wrap_async != nullptr) {  // mkdir(path, mode, req)
1669

701
    FS_ASYNC_TRACE_BEGIN1(
1670
        UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1671

589
    AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1672
              mkdirp ? AfterMkdirp : AfterNoArgs,
1673
              mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1674
  } else {  // mkdir(path, mode, undefined, ctx)
1675
1292
    CHECK_EQ(argc, 5);
1676
1292
    FSReqWrapSync req_wrap_sync;
1677

1296
    FS_SYNC_TRACE_BEGIN(mkdir);
1678
1292
    if (mkdirp) {
1679
288
      int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1680

572
      if (err == 0 &&
1681
284
          !req_wrap_sync.continuation_data()->first_path().empty()) {
1682
        Local<Value> error;
1683
282
        std::string first_path(req_wrap_sync.continuation_data()->first_path());
1684
282
        FromNamespacedPath(&first_path);
1685
        MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1686
                                                     first_path.c_str(),
1687
282
                                                     UTF8, &error);
1688
282
        if (path.IsEmpty()) {
1689
          Local<Object> ctx = args[4].As<Object>();
1690
          ctx->Set(env->context(), env->error_string(), error).Check();
1691
          return;
1692
        }
1693
564
        args.GetReturnValue().Set(path.ToLocalChecked());
1694
      }
1695
    } else {
1696
2008
      SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1697
               uv_fs_mkdir, *path, mode);
1698
    }
1699

1296
    FS_SYNC_TRACE_END(mkdir);
1700
  }
1701
}
1702
1703
43
static void RealPath(const FunctionCallbackInfo<Value>& args) {
1704
43
  Environment* env = Environment::GetCurrent(args);
1705
43
  Isolate* isolate = env->isolate();
1706
1707
43
  const int argc = args.Length();
1708
43
  CHECK_GE(argc, 3);
1709
1710
43
  BufferValue path(isolate, args[0]);
1711
43
  CHECK_NOT_NULL(*path);
1712
1713
43
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1714
1715
43
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1716
43
  if (req_wrap_async != nullptr) {  // realpath(path, encoding, req)
1717

28
    FS_ASYNC_TRACE_BEGIN1(
1718
        UV_FS_REALPATH, req_wrap_async, "path", TRACE_STR_COPY(*path))
1719
23
    AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1720
              uv_fs_realpath, *path);
1721
  } else {  // realpath(path, encoding, undefined, ctx)
1722
20
    CHECK_EQ(argc, 4);
1723
20
    FSReqWrapSync req_wrap_sync;
1724

22
    FS_SYNC_TRACE_BEGIN(realpath);
1725
40
    int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1726
                       uv_fs_realpath, *path);
1727

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

236
    FS_ASYNC_TRACE_BEGIN1(
1767
        UV_FS_SCANDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1768
223
    AsyncCall(env,
1769
              req_wrap_async,
1770
              args,
1771
              "scandir",
1772
              encoding,
1773
              AfterScanDir,
1774
              uv_fs_scandir,
1775
              *path,
1776
              0 /*flags*/);
1777
  } else {  // readdir(path, encoding, withTypes, undefined, ctx)
1778
13836
    CHECK_EQ(argc, 5);
1779
13836
    FSReqWrapSync req_wrap_sync;
1780

13838
    FS_SYNC_TRACE_BEGIN(readdir);
1781
27672
    int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1782
                       uv_fs_scandir, *path, 0 /*flags*/);
1783

13838
    FS_SYNC_TRACE_END(readdir);
1784
13836
    if (err < 0) {
1785
134
      return;  // syscall failed, no need to continue, error info is in ctx
1786
    }
1787
1788
13702
    CHECK_GE(req_wrap_sync.req.result, 0);
1789
    int r;
1790
13702
    std::vector<Local<Value>> name_v;
1791
13702
    std::vector<Local<Value>> type_v;
1792
1793
    for (;;) {
1794
      uv_dirent_t ent;
1795
1796
802677
      r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1797
802677
      if (r == UV_EOF)
1798
13702
        break;
1799
788975
      if (r != 0) {
1800
        Local<Object> ctx = args[4].As<Object>();
1801
        ctx->Set(env->context(), env->errno_string(),
1802
                 Integer::New(isolate, r)).Check();
1803
        ctx->Set(env->context(), env->syscall_string(),
1804
                 OneByteString(isolate, "readdir")).Check();
1805
        return;
1806
      }
1807
1808
      Local<Value> error;
1809
      MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1810
                                                       ent.name,
1811
                                                       encoding,
1812
788975
                                                       &error);
1813
1814
788975
      if (filename.IsEmpty()) {
1815
        Local<Object> ctx = args[4].As<Object>();
1816
        ctx->Set(env->context(), env->error_string(), error).Check();
1817
        return;
1818
      }
1819
1820
788975
      name_v.push_back(filename.ToLocalChecked());
1821
1822
788975
      if (with_types) {
1823
51633
        type_v.emplace_back(Integer::New(isolate, ent.type));
1824
      }
1825
788975
    }
1826
1827
1828
13702
    Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1829
13702
    if (with_types) {
1830
      Local<Value> result[] = {
1831
        names,
1832
        Array::New(isolate, type_v.data(), type_v.size())
1833
386
      };
1834
386
      args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1835
    } else {
1836
27018
      args.GetReturnValue().Set(names);
1837
    }
1838
  }
1839
}
1840
1841
68283
static void Open(const FunctionCallbackInfo<Value>& args) {
1842
68283
  Environment* env = Environment::GetCurrent(args);
1843
1844
68283
  const int argc = args.Length();
1845
68283
  CHECK_GE(argc, 3);
1846
1847
136566
  BufferValue path(env->isolate(), args[0]);
1848
68283
  CHECK_NOT_NULL(*path);
1849
1850
68283
  CHECK(args[1]->IsInt32());
1851
136566
  const int flags = args[1].As<Int32>()->Value();
1852
1853
68283
  CHECK(args[2]->IsInt32());
1854
136566
  const int mode = args[2].As<Int32>()->Value();
1855
1856
68283
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1857
68283
  if (req_wrap_async != nullptr) {  // open(path, flags, mode, req)
1858
5655
    req_wrap_async->set_is_plain_open(true);
1859

5927
    FS_ASYNC_TRACE_BEGIN1(
1860
        UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1861
5655
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1862
              uv_fs_open, *path, flags, mode);
1863
  } else {  // open(path, flags, mode, undefined, ctx)
1864
62628
    CHECK_EQ(argc, 5);
1865
62628
    FSReqWrapSync req_wrap_sync;
1866

62691
    FS_SYNC_TRACE_BEGIN(open);
1867
125256
    int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1868
                          uv_fs_open, *path, flags, mode);
1869

62691
    FS_SYNC_TRACE_END(open);
1870
62628
    if (result >= 0) env->AddUnmanagedFd(result);
1871
125256
    args.GetReturnValue().Set(result);
1872
  }
1873
68283
}
1874
1875
1654
static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1876
1654
  BindingData* binding_data = Environment::GetBindingData<BindingData>(args);
1877
1654
  Environment* env = binding_data->env();
1878
1654
  Isolate* isolate = env->isolate();
1879
1880
1654
  const int argc = args.Length();
1881
1654
  CHECK_GE(argc, 3);
1882
1883
1654
  BufferValue path(isolate, args[0]);
1884
1654
  CHECK_NOT_NULL(*path);
1885
1886
1654
  CHECK(args[1]->IsInt32());
1887
3308
  const int flags = args[1].As<Int32>()->Value();
1888
1889
1654
  CHECK(args[2]->IsInt32());
1890
3308
  const int mode = args[2].As<Int32>()->Value();
1891
1892
1654
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1893
1654
  if (req_wrap_async != nullptr) {  // openFileHandle(path, flags, mode, req)
1894

2052
    FS_ASYNC_TRACE_BEGIN1(
1895
        UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1896
1653
    AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1897
              uv_fs_open, *path, flags, mode);
1898
  } else {  // openFileHandle(path, flags, mode, undefined, ctx)
1899
1
    CHECK_EQ(argc, 5);
1900
1
    FSReqWrapSync req_wrap_sync;
1901

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

1
    FS_SYNC_TRACE_END(open);
1905
1
    if (result < 0) {
1906
      return;  // syscall failed, no need to continue, error info is in ctx
1907
    }
1908
1
    FileHandle* fd = FileHandle::New(binding_data, result);
1909
1
    if (fd == nullptr) return;
1910
2
    args.GetReturnValue().Set(fd->object());
1911
  }
1912
}
1913
1914
222
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1915
222
  Environment* env = Environment::GetCurrent(args);
1916
222
  Isolate* isolate = env->isolate();
1917
1918
222
  const int argc = args.Length();
1919
222
  CHECK_GE(argc, 3);
1920
1921
444
  BufferValue src(isolate, args[0]);
1922
222
  CHECK_NOT_NULL(*src);
1923
1924
444
  BufferValue dest(isolate, args[1]);
1925
222
  CHECK_NOT_NULL(*dest);
1926
1927
222
  CHECK(args[2]->IsInt32());
1928
444
  const int flags = args[2].As<Int32>()->Value();
1929
1930
222
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1931
222
  if (req_wrap_async != nullptr) {  // copyFile(src, dest, flags, req)
1932

111
    FS_ASYNC_TRACE_BEGIN2(UV_FS_COPYFILE,
1933
                          req_wrap_async,
1934
                          "src",
1935
                          TRACE_STR_COPY(*src),
1936
                          "dest",
1937
                          TRACE_STR_COPY(*dest))
1938
208
    AsyncDestCall(env, req_wrap_async, args, "copyfile",
1939
104
                  *dest, dest.length(), UTF8, AfterNoArgs,
1940
                  uv_fs_copyfile, *src, *dest, flags);
1941
  } else {  // copyFile(src, dest, flags, undefined, ctx)
1942
118
    CHECK_EQ(argc, 5);
1943
236
    FSReqWrapSync req_wrap_sync;
1944

120
    FS_SYNC_TRACE_BEGIN(copyfile);
1945
236
    SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1946
             uv_fs_copyfile, *src, *dest, flags);
1947

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

18049
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
1995
17879
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1996
              uv_fs_write, fd, &uvbuf, 1, pos);
1997
  } else {  // write(fd, buffer, off, len, pos, undefined, ctx)
1998
75509
    CHECK_EQ(argc, 7);
1999
75509
    FSReqWrapSync req_wrap_sync;
2000

75559
    FS_SYNC_TRACE_BEGIN(write);
2001
75509
    int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
2002
75509
                                uv_fs_write, fd, &uvbuf, 1, pos);
2003

75559
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2004
151018
    args.GetReturnValue().Set(bytesWritten);
2005
  }
2006
93388
}
2007
2008
2009
// Wrapper for writev(2).
2010
//
2011
// bytesWritten = writev(fd, chunks, position, callback)
2012
// 0 fd        integer. file descriptor
2013
// 1 chunks    array of buffers to write
2014
// 2 position  if integer, position to write at in the file.
2015
//             if null, write from the current position
2016
18
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
2017
18
  Environment* env = Environment::GetCurrent(args);
2018
2019
18
  const int argc = args.Length();
2020
18
  CHECK_GE(argc, 3);
2021
2022
18
  CHECK(args[0]->IsInt32());
2023
36
  const int fd = args[0].As<Int32>()->Value();
2024
2025
18
  CHECK(args[1]->IsArray());
2026
36
  Local<Array> chunks = args[1].As<Array>();
2027
2028
18
  int64_t pos = GetOffset(args[2]);
2029
2030
36
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
2031
2032
72
  for (uint32_t i = 0; i < iovs.length(); i++) {
2033
54
    Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
2034
54
    CHECK(Buffer::HasInstance(chunk));
2035
54
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
2036
  }
2037
2038
18
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2039
18
  if (req_wrap_async != nullptr) {  // writeBuffers(fd, chunks, pos, req)
2040

23
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2041
14
    AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
2042
              uv_fs_write, fd, *iovs, iovs.length(), pos);
2043
  } else {  // writeBuffers(fd, chunks, pos, undefined, ctx)
2044
4
    CHECK_EQ(argc, 5);
2045
4
    FSReqWrapSync req_wrap_sync;
2046

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

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

403350
  if (!is_async && value->IsString()) {
2092
134423
    auto string = value.As<String>();
2093


134424
    if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
2094
1
      auto ext = string->GetExternalOneByteStringResource();
2095
1
      buf = const_cast<char*>(ext->data());
2096
1
      len = ext->length();
2097


134423
    } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
2098
1
      auto ext = string->GetExternalStringResource();
2099
1
      buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
2100
1
      len = ext->length() * sizeof(*ext->data());
2101
    }
2102
  }
2103
2104
134504
  if (is_async) {  // write(fd, string, pos, enc, req)
2105
81
    CHECK_NOT_NULL(req_wrap_async);
2106
162
    if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
2107
    FSReqBase::FSReqBuffer& stack_buffer =
2108
81
        req_wrap_async->Init("write", len, enc);
2109
    // StorageSize may return too large a char, so correct the actual length
2110
    // by the write size
2111
81
    len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
2112
81
    stack_buffer.SetLengthAndZeroTerminate(len);
2113
81
    uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
2114

93
    FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2115
81
    int err = req_wrap_async->Dispatch(uv_fs_write,
2116
                                       fd,
2117
                                       &uvbuf,
2118
                                       1,
2119
                                       pos,
2120
                                       AfterInteger);
2121
81
    if (err < 0) {
2122
      uv_fs_t* uv_req = req_wrap_async->req();
2123
      uv_req->result = err;
2124
      uv_req->path = nullptr;
2125
      AfterInteger(uv_req);  // after may delete req_wrap_async if there is
2126
                             // an error
2127
    } else {
2128
81
      req_wrap_async->SetReturnValue(args);
2129
    }
2130
  } else {  // write(fd, string, pos, enc, undefined, ctx)
2131
134423
    CHECK_EQ(argc, 6);
2132
134423
    FSReqWrapSync req_wrap_sync;
2133
134423
    FSReqBase::FSReqBuffer stack_buffer;
2134
134423
    if (buf == nullptr) {
2135
268842
      if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
2136
        return;
2137
134421
      stack_buffer.AllocateSufficientStorage(len + 1);
2138
      // StorageSize may return too large a char, so correct the actual length
2139
      // by the write size
2140
134421
      len = StringBytes::Write(isolate, *stack_buffer,
2141
                               len, args[1], enc);
2142
134421
      stack_buffer.SetLengthAndZeroTerminate(len);
2143
134421
      buf = *stack_buffer;
2144
    }
2145
134423
    uv_buf_t uvbuf = uv_buf_init(buf, len);
2146

134423
    FS_SYNC_TRACE_BEGIN(write);
2147
134423
    int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2148
134423
                                uv_fs_write, fd, &uvbuf, 1, pos);
2149

134423
    FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2150
268846
    args.GetReturnValue().Set(bytesWritten);
2151
  }
2152
}
2153
2154
2155
/*
2156
 * Wrapper for read(2).
2157
 *
2158
 * bytesRead = fs.read(fd, buffer, offset, length, position)
2159
 *
2160
 * 0 fd        int32. file descriptor
2161
 * 1 buffer    instance of Buffer
2162
 * 2 offset    int64. offset to start reading into inside buffer
2163
 * 3 length    int32. length to read
2164
 * 4 position  int64. file position - -1 for current position
2165
 */
2166
216754
static void Read(const FunctionCallbackInfo<Value>& args) {
2167
216754
  Environment* env = Environment::GetCurrent(args);
2168
2169
216754
  const int argc = args.Length();
2170
216754
  CHECK_GE(argc, 5);
2171
2172
216754
  CHECK(args[0]->IsInt32());
2173
433508
  const int fd = args[0].As<Int32>()->Value();
2174
2175
216754
  CHECK(Buffer::HasInstance(args[1]));
2176
216754
  Local<Object> buffer_obj = args[1].As<Object>();
2177
216754
  char* buffer_data = Buffer::Data(buffer_obj);
2178
216754
  size_t buffer_length = Buffer::Length(buffer_obj);
2179
2180
216754
  CHECK(IsSafeJsInt(args[2]));
2181
433508
  const int64_t off_64 = args[2].As<Integer>()->Value();
2182
216754
  CHECK_GE(off_64, 0);
2183
216754
  CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2184
216754
  const size_t off = static_cast<size_t>(off_64);
2185
2186
216754
  CHECK(args[3]->IsInt32());
2187
433508
  const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2188
216754
  CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2189
2190

216784
  CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2191
216754
  const int64_t pos = args[4]->IsNumber() ?
2192
433448
                      args[4].As<Integer>()->Value() :
2193
60
                      args[4].As<BigInt>()->Int64Value();
2194
2195
216754
  char* buf = buffer_data + off;
2196
216754
  uv_buf_t uvbuf = uv_buf_init(buf, len);
2197
2198
216754
  FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2199
216754
  if (req_wrap_async != nullptr) {  // read(fd, buffer, offset, len, pos, req)
2200

16440
    FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2201
15973
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2202
              uv_fs_read, fd, &uvbuf, 1, pos);
2203
  } else {  // read(fd, buffer, offset, len, pos, undefined, ctx)
2204
200781
    CHECK_EQ(argc, 7);
2205
200781
    FSReqWrapSync req_wrap_sync;
2206

200820
    FS_SYNC_TRACE_BEGIN(read);
2207
200781
    const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2208
200781
                                   uv_fs_read, fd, &uvbuf, 1, pos);
2209

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

10
    FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2248
7
    AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2249
              uv_fs_read, fd, *iovs, iovs.length(), pos);
2250
  } else {  // readBuffers(fd, buffers, undefined, ctx)
2251
4
    CHECK_EQ(argc, 5);
2252
4
    FSReqWrapSync req_wrap_sync;
2253

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

4
    FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2257
8
    args.GetReturnValue().Set(bytesRead);
2258
  }
2259
11
}
2260
2261
2262
/* fs.chmod(path, mode);
2263
 * Wrapper for chmod(1) / EIO_CHMOD
2264
 */
2265
311
static void Chmod(const FunctionCallbackInfo<Value>& args) {
2266
311
  Environment* env = Environment::GetCurrent(args);
2267
2268
311
  const int argc = args.Length();
2269
311
  CHECK_GE(argc, 2);
2270
2271
622
  BufferValue path(env->isolate(), args[0]);
2272
311
  CHECK_NOT_NULL(*path);
2273
2274
311
  CHECK(args[1]->IsInt32());
2275
622
  int mode = args[1].As<Int32>()->Value();
2276
2277
311
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2278
311
  if (req_wrap_async != nullptr) {  // chmod(path, mode, req)
2279

149
    FS_ASYNC_TRACE_BEGIN1(
2280
        UV_FS_CHMOD, req_wrap_async, "path", TRACE_STR_COPY(*path))
2281
142
    AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2282
              uv_fs_chmod, *path, mode);
2283
  } else {  // chmod(path, mode, undefined, ctx)
2284
169
    CHECK_EQ(argc, 4);
2285
338
    FSReqWrapSync req_wrap_sync;
2286

171
    FS_SYNC_TRACE_BEGIN(chmod);
2287
338
    SyncCall(env, args[3], &req_wrap_sync, "chmod",
2288
             uv_fs_chmod, *path, mode);
2289

171
    FS_SYNC_TRACE_END(chmod);
2290
  }
2291
311
}
2292
2293
2294
/* fs.fchmod(fd, mode);
2295
 * Wrapper for fchmod(1) / EIO_FCHMOD
2296
 */
2297
13
static void FChmod(const FunctionCallbackInfo<Value>& args) {
2298
13
  Environment* env = Environment::GetCurrent(args);
2299
2300
13
  const int argc = args.Length();
2301
13
  CHECK_GE(argc, 2);
2302
2303
13
  CHECK(args[0]->IsInt32());
2304
26
  const int fd = args[0].As<Int32>()->Value();
2305
2306
13
  CHECK(args[1]->IsInt32());
2307
26
  const int mode = args[1].As<Int32>()->Value();
2308
2309
13
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2310
13
  if (req_wrap_async != nullptr) {  // fchmod(fd, mode, req)
2311

14
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
2312
8
    AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2313
              uv_fs_fchmod, fd, mode);
2314
  } else {  // fchmod(fd, mode, undefined, ctx)
2315
5
    CHECK_EQ(argc, 4);
2316
10
    FSReqWrapSync req_wrap_sync;
2317

7
    FS_SYNC_TRACE_BEGIN(fchmod);
2318
5
    SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2319
             uv_fs_fchmod, fd, mode);
2320

7
    FS_SYNC_TRACE_END(fchmod);
2321
  }
2322
13
}
2323
2324
2325
/* fs.chown(path, uid, gid);
2326
 * Wrapper for chown(1) / EIO_CHOWN
2327
 */
2328
5
static void Chown(const FunctionCallbackInfo<Value>& args) {
2329
5
  Environment* env = Environment::GetCurrent(args);
2330
2331
5
  const int argc = args.Length();
2332
5
  CHECK_GE(argc, 3);
2333
2334
10
  BufferValue path(env->isolate(), args[0]);
2335
5
  CHECK_NOT_NULL(*path);
2336
2337
5
  CHECK(IsSafeJsInt(args[1]));
2338
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2339
2340
5
  CHECK(IsSafeJsInt(args[2]));
2341
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2342
2343
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2344
5
  if (req_wrap_async != nullptr) {  // chown(path, uid, gid, req)
2345

6
    FS_ASYNC_TRACE_BEGIN1(
2346
        UV_FS_CHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2347
3
    AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2348
              uv_fs_chown, *path, uid, gid);
2349
  } else {  // chown(path, uid, gid, undefined, ctx)
2350
2
    CHECK_EQ(argc, 5);
2351
4
    FSReqWrapSync req_wrap_sync;
2352

4
    FS_SYNC_TRACE_BEGIN(chown);
2353
4
    SyncCall(env, args[4], &req_wrap_sync, "chown",
2354
             uv_fs_chown, *path, uid, gid);
2355

4
    FS_SYNC_TRACE_END(chown);
2356
  }
2357
5
}
2358
2359
2360
/* fs.fchown(fd, uid, gid);
2361
 * Wrapper for fchown(1) / EIO_FCHOWN
2362
 */
2363
5
static void FChown(const FunctionCallbackInfo<Value>& args) {
2364
5
  Environment* env = Environment::GetCurrent(args);
2365
2366
5
  const int argc = args.Length();
2367
5
  CHECK_GE(argc, 3);
2368
2369
5
  CHECK(args[0]->IsInt32());
2370
10
  const int fd = args[0].As<Int32>()->Value();
2371
2372
5
  CHECK(IsSafeJsInt(args[1]));
2373
10
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2374
2375
5
  CHECK(IsSafeJsInt(args[2]));
2376
10
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2377
2378
5
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2379
5
  if (req_wrap_async != nullptr) {  // fchown(fd, uid, gid, req)
2380

6
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHOWN, req_wrap_async)
2381
3
    AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2382
              uv_fs_fchown, fd, uid, gid);
2383
  } else {  // fchown(fd, uid, gid, undefined, ctx)
2384
2
    CHECK_EQ(argc, 5);
2385
4
    FSReqWrapSync req_wrap_sync;
2386

4
    FS_SYNC_TRACE_BEGIN(fchown);
2387
2
    SyncCall(env, args[4], &req_wrap_sync, "fchown",
2388
             uv_fs_fchown, fd, uid, gid);
2389

4
    FS_SYNC_TRACE_END(fchown);
2390
  }
2391
5
}
2392
2393
2394
6
static void LChown(const FunctionCallbackInfo<Value>& args) {
2395
6
  Environment* env = Environment::GetCurrent(args);
2396
2397
6
  const int argc = args.Length();
2398
6
  CHECK_GE(argc, 3);
2399
2400
12
  BufferValue path(env->isolate(), args[0]);
2401
6
  CHECK_NOT_NULL(*path);
2402
2403
6
  CHECK(IsSafeJsInt(args[1]));
2404
12
  const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2405
2406
6
  CHECK(IsSafeJsInt(args[2]));
2407
12
  const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2408
2409
6
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2410
6
  if (req_wrap_async != nullptr) {  // lchown(path, uid, gid, req)
2411

7
    FS_ASYNC_TRACE_BEGIN1(
2412
        UV_FS_LCHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2413
4
    AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2414
              uv_fs_lchown, *path, uid, gid);
2415
  } else {  // lchown(path, uid, gid, undefined, ctx)
2416
2
    CHECK_EQ(argc, 5);
2417
4
    FSReqWrapSync req_wrap_sync;
2418

4
    FS_SYNC_TRACE_BEGIN(lchown);
2419
4
    SyncCall(env, args[4], &req_wrap_sync, "lchown",
2420
             uv_fs_lchown, *path, uid, gid);
2421

4
    FS_SYNC_TRACE_END(lchown);
2422
  }
2423
6
}
2424
2425
2426
63
static void UTimes(const FunctionCallbackInfo<Value>& args) {
2427
63
  Environment* env = Environment::GetCurrent(args);
2428
2429
63
  const int argc = args.Length();
2430
63
  CHECK_GE(argc, 3);
2431
2432
126
  BufferValue path(env->isolate(), args[0]);
2433
63
  CHECK_NOT_NULL(*path);
2434
2435
63
  CHECK(args[1]->IsNumber());
2436
126
  const double atime = args[1].As<Number>()->Value();
2437
2438
63
  CHECK(args[2]->IsNumber());
2439
126
  const double mtime = args[2].As<Number>()->Value();
2440
2441
63
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2442
63
  if (req_wrap_async != nullptr) {  // utimes(path, atime, mtime, req)
2443

42
    FS_ASYNC_TRACE_BEGIN1(
2444
        UV_FS_UTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2445
36
    AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2446
              uv_fs_utime, *path, atime, mtime);
2447
  } else {  // utimes(path, atime, mtime, undefined, ctx)
2448
27
    CHECK_EQ(argc, 5);
2449
54
    FSReqWrapSync req_wrap_sync;
2450

29
    FS_SYNC_TRACE_BEGIN(utimes);
2451
54
    SyncCall(env, args[4], &req_wrap_sync, "utime",
2452
             uv_fs_utime, *path, atime, mtime);
2453

29
    FS_SYNC_TRACE_END(utimes);
2454
  }
2455
63
}
2456
2457
19
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2458
19
  Environment* env = Environment::GetCurrent(args);
2459
2460
19
  const int argc = args.Length();
2461
19
  CHECK_GE(argc, 3);
2462
2463
19
  CHECK(args[0]->IsInt32());
2464
38
  const int fd = args[0].As<Int32>()->Value();
2465
2466
19
  CHECK(args[1]->IsNumber());
2467
38
  const double atime = args[1].As<Number>()->Value();
2468
2469
19
  CHECK(args[2]->IsNumber());
2470
38
  const double mtime = args[2].As<Number>()->Value();
2471
2472
19
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2473
19
  if (req_wrap_async != nullptr) {  // futimes(fd, atime, mtime, req)
2474

14
    FS_ASYNC_TRACE_BEGIN0(UV_FS_FUTIME, req_wrap_async)
2475
10
    AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2476
              uv_fs_futime, fd, atime, mtime);
2477
  } else {  // futimes(fd, atime, mtime, undefined, ctx)
2478
9
    CHECK_EQ(argc, 5);
2479
18
    FSReqWrapSync req_wrap_sync;
2480

11
    FS_SYNC_TRACE_BEGIN(futimes);
2481
9
    SyncCall(env, args[4], &req_wrap_sync, "futime",
2482
             uv_fs_futime, fd, atime, mtime);
2483

11
    FS_SYNC_TRACE_END(futimes);
2484
  }
2485
19
}
2486
2487
16
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2488
16
  Environment* env = Environment::GetCurrent(args);
2489
2490
16
  const int argc = args.Length();
2491
16
  CHECK_GE(argc, 3);
2492
2493
32
  BufferValue path(env->isolate(), args[0]);
2494
16
  CHECK_NOT_NULL(*path);
2495
2496
16
  CHECK(args[1]->IsNumber());
2497
32
  const double atime = args[1].As<Number>()->Value();
2498
2499
16
  CHECK(args[2]->IsNumber());
2500
32
  const double mtime = args[2].As<Number>()->Value();
2501
2502
16
  FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2503
16
  if (req_wrap_async != nullptr) {  // lutimes(path, atime, mtime, req)
2504

12
    FS_ASYNC_TRACE_BEGIN1(
2505
        UV_FS_LUTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2506
9
    AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2507
              uv_fs_lutime, *path, atime, mtime);
2508
  } else {  // lutimes(path, atime, mtime, undefined, ctx)
2509
7
    CHECK_EQ(argc, 5);
2510
14
    FSReqWrapSync req_wrap_sync;
2511

7
    FS_SYNC_TRACE_BEGIN(lutimes);
2512
14
    SyncCall(env, args[4], &req_wrap_sync, "lutime",
2513
             uv_fs_lutime, *path, atime, mtime);
2514

7
    FS_SYNC_TRACE_END(lutimes);
2515
  }
2516
16
}
2517
2518
27
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2519
27
  Environment* env = Environment::GetCurrent(args);
2520
27
  Isolate* isolate = env->isolate();
2521
2522
27
  const int argc = args.Length();
2523
27
  CHECK_GE(argc, 2);
2524
2525
27
  BufferValue tmpl(isolate, args[0]);
2526
27
  CHECK_NOT_NULL(*tmpl);
2527
2528
27
  const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2529
2530
27
  FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2531
27
  if (req_wrap_async != nullptr) {  // mkdtemp(tmpl, encoding, req)
2532

16
    FS_ASYNC_TRACE_BEGIN1(
2533
        UV_FS_MKDTEMP, req_wrap_async, "path", TRACE_STR_COPY(*tmpl))
2534
10
    AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2535
              uv_fs_mkdtemp, *tmpl);
2536
  } else {  // mkdtemp(tmpl, encoding, undefined, ctx)
2537
17
    CHECK_EQ(argc, 4);
2538
17
    FSReqWrapSync req_wrap_sync;
2539

19
    FS_SYNC_TRACE_BEGIN(mkdtemp);
2540
34
    SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2541
             uv_fs_mkdtemp, *tmpl);
2542

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