1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 #include "aliased_buffer.h"
23 #include "node_buffer.h"
24 #include "node_internals.h"
25 #include "node_stat_watcher.h"
26 #include "node_file.h"
27 #include "tracing/trace_event.h"
28
29 #include "req_wrap-inl.h"
30 #include "stream_base-inl.h"
31 #include "string_bytes.h"
32 #include "string_search.h"
33
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <limits.h>
40
41 #if defined(__MINGW32__) || defined(_MSC_VER)
42 # include <io.h>
43 #endif
44
45 #include <memory>
46
47 namespace node {
48
49 namespace fs {
50
51 using v8::Array;
52 using v8::BigUint64Array;
53 using v8::Context;
54 using v8::EscapableHandleScope;
55 using v8::Float64Array;
56 using v8::Function;
57 using v8::FunctionCallbackInfo;
58 using v8::FunctionTemplate;
59 using v8::HandleScope;
60 using v8::Int32;
61 using v8::Integer;
62 using v8::Isolate;
63 using v8::Local;
64 using v8::MaybeLocal;
65 using v8::Number;
66 using v8::Object;
67 using v8::ObjectTemplate;
68 using v8::Promise;
69 using v8::String;
70 using v8::Symbol;
71 using v8::Uint32;
72 using v8::Undefined;
73 using v8::Value;
74
75 #ifndef MIN
76 # define MIN(a, b) ((a) < (b) ? (a) : (b))
77 #endif
78
79 #ifndef S_ISDIR
80 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
81 #endif
82
83 #ifdef __POSIX__
84 const char* kPathSeparator = "/";
85 #else
86 const char* kPathSeparator = "\\/";
87 #endif
88
89 #define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
90 #define TRACE_NAME(name) "fs.sync." #name
91 #define GET_TRACE_ENABLED \
92 (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
93 (TRACING_CATEGORY_NODE2(fs, sync)) != 0)
94 #define FS_SYNC_TRACE_BEGIN(syscall, ...) \
95 if (GET_TRACE_ENABLED) \
96 TRACE_EVENT_BEGIN(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
97 ##__VA_ARGS__);
98 #define FS_SYNC_TRACE_END(syscall, ...) \
99 if (GET_TRACE_ENABLED) \
100 TRACE_EVENT_END(TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), \
101 ##__VA_ARGS__);
102
103 // We sometimes need to convert a C++ lambda function to a raw C-style function.
104 // This is helpful, because ReqWrap::Dispatch() does not recognize lambda
105 // functions, and thus does not wrap them properly.
106 typedef void(*uv_fs_callback_t)(uv_fs_t*);
107
108 // The FileHandle object wraps a file descriptor and will close it on garbage
109 // collection if necessary. If that happens, a process warning will be
110 // emitted (or a fatal exception will occur if the fd cannot be closed.)
FileHandle(Environment * env,int fd,Local<Object> obj)111 FileHandle::FileHandle(Environment* env, int fd, Local<Object> obj)
112 : AsyncWrap(env,
113 obj.IsEmpty() ? env->fd_constructor_template()
114 ->NewInstance(env->context()).ToLocalChecked() : obj,
115 AsyncWrap::PROVIDER_FILEHANDLE),
116 StreamBase(env),
117 fd_(fd) {
118 MakeWeak();
119 v8::PropertyAttribute attr =
120 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
121 object()->DefineOwnProperty(env->context(),
122 FIXED_ONE_BYTE_STRING(env->isolate(), "fd"),
123 Integer::New(env->isolate(), fd),
124 attr).FromJust();
125 }
126
New(const FunctionCallbackInfo<Value> & args)127 void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
128 Environment* env = Environment::GetCurrent(args);
129 CHECK(args.IsConstructCall());
130 CHECK(args[0]->IsInt32());
131
132 FileHandle* handle =
133 new FileHandle(env, args[0].As<Int32>()->Value(), args.This());
134 if (args[1]->IsNumber())
135 handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
136 if (args[2]->IsNumber())
137 handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
138 }
139
~FileHandle()140 FileHandle::~FileHandle() {
141 CHECK(!closing_); // We should not be deleting while explicitly closing!
142 Close(); // Close synchronously and emit warning
143 CHECK(closed_); // We have to be closed at the point
144 }
145
146
147 // Close the file descriptor if it hasn't already been closed. A process
148 // warning will be emitted using a SetImmediate to avoid calling back to
149 // JS during GC. If closing the fd fails at this point, a fatal exception
150 // will crash the process immediately.
Close()151 inline void FileHandle::Close() {
152 if (closed_) return;
153 uv_fs_t req;
154 int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
155 uv_fs_req_cleanup(&req);
156 AfterClose();
157
158 struct err_detail { int ret; int fd; };
159
160 err_detail* detail = new err_detail { ret, fd_ };
161
162 if (ret < 0) {
163 // Do not unref this
164 env()->SetImmediate([](Environment* env, void* data) {
165 char msg[70];
166 std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
167 snprintf(msg, arraysize(msg),
168 "Closing file descriptor %d on garbage collection failed",
169 detail->fd);
170 // This exception will end up being fatal for the process because
171 // it is being thrown from within the SetImmediate handler and
172 // there is no JS stack to bubble it to. In other words, tearing
173 // down the process is the only reasonable thing we can do here.
174 HandleScope handle_scope(env->isolate());
175 env->ThrowUVException(detail->ret, "close", msg);
176 }, detail);
177 return;
178 }
179
180 // If the close was successful, we still want to emit a process warning
181 // to notify that the file descriptor was gc'd. We want to be noisy about
182 // this because not explicitly closing the FileHandle is a bug.
183 env()->SetUnrefImmediate([](Environment* env, void* data) {
184 std::unique_ptr<err_detail> detail(static_cast<err_detail*>(data));
185 ProcessEmitWarning(env,
186 "Closing file descriptor %d on garbage collection",
187 detail->fd);
188 }, detail);
189 }
190
Resolve()191 void FileHandle::CloseReq::Resolve() {
192 Isolate* isolate = env()->isolate();
193 HandleScope scope(isolate);
194 InternalCallbackScope callback_scope(this);
195 Local<Promise> promise = promise_.Get(isolate);
196 Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
197 resolver->Resolve(env()->context(), Undefined(isolate)).FromJust();
198 }
199
Reject(Local<Value> reason)200 void FileHandle::CloseReq::Reject(Local<Value> reason) {
201 Isolate* isolate = env()->isolate();
202 HandleScope scope(isolate);
203 InternalCallbackScope callback_scope(this);
204 Local<Promise> promise = promise_.Get(isolate);
205 Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
206 resolver->Reject(env()->context(), reason).FromJust();
207 }
208
file_handle()209 FileHandle* FileHandle::CloseReq::file_handle() {
210 Isolate* isolate = env()->isolate();
211 HandleScope scope(isolate);
212 Local<Value> val = ref_.Get(isolate);
213 Local<Object> obj = val.As<Object>();
214 return Unwrap<FileHandle>(obj);
215 }
216
217 // Closes this FileHandle asynchronously and returns a Promise that will be
218 // resolved when the callback is invoked, or rejects with a UVException if
219 // there was a problem closing the fd. This is the preferred mechanism for
220 // closing the FD object even tho the object will attempt to close
221 // automatically on gc.
ClosePromise()222 inline MaybeLocal<Promise> FileHandle::ClosePromise() {
223 Isolate* isolate = env()->isolate();
224 EscapableHandleScope scope(isolate);
225 Local<Context> context = env()->context();
226 auto maybe_resolver = Promise::Resolver::New(context);
227 CHECK(!maybe_resolver.IsEmpty());
228 Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
229 Local<Promise> promise = resolver.As<Promise>();
230 CHECK(!reading_);
231 if (!closed_ && !closing_) {
232 closing_ = true;
233 CloseReq* req = new CloseReq(env(), promise, object());
234 auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
235 std::unique_ptr<CloseReq> close(CloseReq::from_req(req));
236 CHECK_NOT_NULL(close);
237 close->file_handle()->AfterClose();
238 Isolate* isolate = close->env()->isolate();
239 if (req->result < 0) {
240 close->Reject(UVException(isolate, req->result, "close"));
241 } else {
242 close->Resolve();
243 }
244 }};
245 int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
246 if (ret < 0) {
247 req->Reject(UVException(isolate, ret, "close"));
248 delete req;
249 }
250 } else {
251 // Already closed. Just reject the promise immediately
252 resolver->Reject(context, UVException(isolate, UV_EBADF, "close"))
253 .FromJust();
254 }
255 return scope.Escape(promise);
256 }
257
Close(const FunctionCallbackInfo<Value> & args)258 void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
259 FileHandle* fd;
260 ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
261 args.GetReturnValue().Set(fd->ClosePromise().ToLocalChecked());
262 }
263
264
ReleaseFD(const FunctionCallbackInfo<Value> & args)265 void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
266 FileHandle* fd;
267 ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
268 // Just act as if this FileHandle has been closed.
269 fd->AfterClose();
270 }
271
272
AfterClose()273 void FileHandle::AfterClose() {
274 closing_ = false;
275 closed_ = true;
276 if (reading_ && !persistent().IsEmpty())
277 EmitRead(UV_EOF);
278 }
279
MemoryInfo(MemoryTracker * tracker) const280 void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
281 tracker->TrackField("buffer", buffer_);
282 tracker->TrackField("file_handle", this->file_handle_);
283 }
284
FileHandleReadWrap(FileHandle * handle,Local<Object> obj)285 FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
286 : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQWRAP),
287 file_handle_(handle) {}
288
ReadStart()289 int FileHandle::ReadStart() {
290 if (!IsAlive() || IsClosing())
291 return UV_EOF;
292
293 reading_ = true;
294
295 if (current_read_)
296 return 0;
297
298 std::unique_ptr<FileHandleReadWrap> read_wrap;
299
300 if (read_length_ == 0) {
301 EmitRead(UV_EOF);
302 return 0;
303 }
304
305 {
306 // Create a new FileHandleReadWrap or re-use one.
307 // Either way, we need these two scopes for AsyncReset() or otherwise
308 // for creating the new instance.
309 HandleScope handle_scope(env()->isolate());
310 AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
311
312 auto& freelist = env()->file_handle_read_wrap_freelist();
313 if (freelist.size() > 0) {
314 read_wrap = std::move(freelist.back());
315 freelist.pop_back();
316 read_wrap->AsyncReset();
317 read_wrap->file_handle_ = this;
318 } else {
319 Local<Object> wrap_obj = env()->filehandlereadwrap_template()
320 ->NewInstance(env()->context()).ToLocalChecked();
321 read_wrap.reset(new FileHandleReadWrap(this, wrap_obj));
322 }
323 }
324 int64_t recommended_read = 65536;
325 if (read_length_ >= 0 && read_length_ <= recommended_read)
326 recommended_read = read_length_;
327
328 read_wrap->buffer_ = EmitAlloc(recommended_read);
329
330 current_read_ = std::move(read_wrap);
331
332 current_read_->Dispatch(uv_fs_read,
333 fd_,
334 ¤t_read_->buffer_,
335 1,
336 read_offset_,
337 uv_fs_callback_t{[](uv_fs_t* req) {
338 FileHandle* handle;
339 {
340 FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
341 handle = req_wrap->file_handle_;
342 CHECK_EQ(handle->current_read_.get(), req_wrap);
343 }
344
345 // ReadStart() checks whether current_read_ is set to determine whether
346 // a read is in progress. Moving it into a local variable makes sure that
347 // the ReadStart() call below doesn't think we're still actively reading.
348 std::unique_ptr<FileHandleReadWrap> read_wrap =
349 std::move(handle->current_read_);
350
351 int result = req->result;
352 uv_buf_t buffer = read_wrap->buffer_;
353
354 uv_fs_req_cleanup(req);
355
356 // Push the read wrap back to the freelist, or let it be destroyed
357 // once we’re exiting the current scope.
358 constexpr size_t wanted_freelist_fill = 100;
359 auto& freelist = handle->env()->file_handle_read_wrap_freelist();
360 if (freelist.size() < wanted_freelist_fill) {
361 read_wrap->Reset();
362 freelist.emplace_back(std::move(read_wrap));
363 }
364
365 if (result >= 0) {
366 // Read at most as many bytes as we originally planned to.
367 if (handle->read_length_ >= 0 && handle->read_length_ < result)
368 result = handle->read_length_;
369
370 // If we read data and we have an expected length, decrease it by
371 // how much we have read.
372 if (handle->read_length_ >= 0)
373 handle->read_length_ -= result;
374
375 // If we have an offset, increase it by how much we have read.
376 if (handle->read_offset_ >= 0)
377 handle->read_offset_ += result;
378 }
379
380 // Reading 0 bytes from a file always means EOF, or that we reached
381 // the end of the requested range.
382 if (result == 0)
383 result = UV_EOF;
384
385 handle->EmitRead(result, buffer);
386
387 // Start over, if EmitRead() didn’t tell us to stop.
388 if (handle->reading_)
389 handle->ReadStart();
390 }});
391
392 return 0;
393 }
394
ReadStop()395 int FileHandle::ReadStop() {
396 reading_ = false;
397 return 0;
398 }
399
400 typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
401
CreateShutdownWrap(Local<Object> object)402 ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
403 return new FileHandleCloseWrap(this, object);
404 }
405
DoShutdown(ShutdownWrap * req_wrap)406 int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
407 FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
408 closing_ = true;
409 wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
410 FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
411 FileHandleCloseWrap::from_req(req));
412 FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
413 handle->AfterClose();
414
415 int result = req->result;
416 uv_fs_req_cleanup(req);
417 wrap->Done(result);
418 }});
419
420 return 0;
421 }
422
423
Reject(Local<Value> reject)424 void FSReqWrap::Reject(Local<Value> reject) {
425 MakeCallback(env()->oncomplete_string(), 1, &reject);
426 }
427
ResolveStat(const uv_stat_t * stat)428 void FSReqWrap::ResolveStat(const uv_stat_t* stat) {
429 Resolve(node::FillGlobalStatsArray(env(), stat, use_bigint()));
430 }
431
Resolve(Local<Value> value)432 void FSReqWrap::Resolve(Local<Value> value) {
433 Local<Value> argv[2] {
434 Null(env()->isolate()),
435 value
436 };
437 MakeCallback(env()->oncomplete_string(),
438 value->IsUndefined() ? 1 : arraysize(argv),
439 argv);
440 }
441
SetReturnValue(const FunctionCallbackInfo<Value> & args)442 void FSReqWrap::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
443 args.GetReturnValue().SetUndefined();
444 }
445
NewFSReqWrap(const FunctionCallbackInfo<Value> & args)446 void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
447 CHECK(args.IsConstructCall());
448 Environment* env = Environment::GetCurrent(args);
449 new FSReqWrap(env, args.This(), args[0]->IsTrue());
450 }
451
FSReqAfterScope(FSReqBase * wrap,uv_fs_t * req)452 FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
453 : wrap_(wrap),
454 req_(req),
455 handle_scope_(wrap->env()->isolate()),
456 context_scope_(wrap->env()->context()) {
457 CHECK_EQ(wrap_->req(), req);
458 }
459
~FSReqAfterScope()460 FSReqAfterScope::~FSReqAfterScope() {
461 uv_fs_req_cleanup(wrap_->req());
462 delete wrap_;
463 }
464
465 // TODO(joyeecheung): create a normal context object, and
466 // construct the actual errors in the JS land using the context.
467 // The context should include fds for some fs APIs, currently they are
468 // missing in the error messages. The path, dest, syscall, fd, .etc
469 // can be put into the context before the binding is even invoked,
470 // the only information that has to come from the C++ layer is the
471 // error number (and possibly the syscall for abstraction),
472 // which is also why the errors should have been constructed
473 // in JS for more flexibility.
Reject(uv_fs_t * req)474 void FSReqAfterScope::Reject(uv_fs_t* req) {
475 wrap_->Reject(UVException(wrap_->env()->isolate(),
476 req->result,
477 wrap_->syscall(),
478 nullptr,
479 req->path,
480 wrap_->data()));
481 }
482
Proceed()483 bool FSReqAfterScope::Proceed() {
484 if (req_->result < 0) {
485 Reject(req_);
486 return false;
487 }
488 return true;
489 }
490
AfterNoArgs(uv_fs_t * req)491 void AfterNoArgs(uv_fs_t* req) {
492 FSReqBase* req_wrap = FSReqBase::from_req(req);
493 FSReqAfterScope after(req_wrap, req);
494
495 if (after.Proceed())
496 req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
497 }
498
AfterStat(uv_fs_t * req)499 void AfterStat(uv_fs_t* req) {
500 FSReqBase* req_wrap = FSReqBase::from_req(req);
501 FSReqAfterScope after(req_wrap, req);
502
503 if (after.Proceed()) {
504 req_wrap->ResolveStat(&req->statbuf);
505 }
506 }
507
AfterInteger(uv_fs_t * req)508 void AfterInteger(uv_fs_t* req) {
509 FSReqBase* req_wrap = FSReqBase::from_req(req);
510 FSReqAfterScope after(req_wrap, req);
511
512 if (after.Proceed())
513 req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
514 }
515
AfterOpenFileHandle(uv_fs_t * req)516 void AfterOpenFileHandle(uv_fs_t* req) {
517 FSReqBase* req_wrap = FSReqBase::from_req(req);
518 FSReqAfterScope after(req_wrap, req);
519
520 if (after.Proceed()) {
521 FileHandle* fd = new FileHandle(req_wrap->env(), req->result);
522 req_wrap->Resolve(fd->object());
523 }
524 }
525
AfterStringPath(uv_fs_t * req)526 void AfterStringPath(uv_fs_t* req) {
527 FSReqBase* req_wrap = FSReqBase::from_req(req);
528 FSReqAfterScope after(req_wrap, req);
529
530 MaybeLocal<Value> link;
531 Local<Value> error;
532
533 if (after.Proceed()) {
534 link = StringBytes::Encode(req_wrap->env()->isolate(),
535 static_cast<const char*>(req->path),
536 req_wrap->encoding(),
537 &error);
538 if (link.IsEmpty())
539 req_wrap->Reject(error);
540 else
541 req_wrap->Resolve(link.ToLocalChecked());
542 }
543 }
544
AfterStringPtr(uv_fs_t * req)545 void AfterStringPtr(uv_fs_t* req) {
546 FSReqBase* req_wrap = FSReqBase::from_req(req);
547 FSReqAfterScope after(req_wrap, req);
548
549 MaybeLocal<Value> link;
550 Local<Value> error;
551
552 if (after.Proceed()) {
553 link = StringBytes::Encode(req_wrap->env()->isolate(),
554 static_cast<const char*>(req->ptr),
555 req_wrap->encoding(),
556 &error);
557 if (link.IsEmpty())
558 req_wrap->Reject(error);
559 else
560 req_wrap->Resolve(link.ToLocalChecked());
561 }
562 }
563
AfterScanDir(uv_fs_t * req)564 void AfterScanDir(uv_fs_t* req) {
565 FSReqBase* req_wrap = FSReqBase::from_req(req);
566 FSReqAfterScope after(req_wrap, req);
567
568 if (!after.Proceed()) {
569 return;
570 }
571 Environment* env = req_wrap->env();
572 Local<Value> error;
573 int r;
574 Local<Array> names = Array::New(env->isolate(), 0);
575 Local<Function> fn = env->push_values_to_array_function();
576 Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
577 size_t name_idx = 0;
578
579 for (int i = 0; ; i++) {
580 uv_dirent_t ent;
581
582 r = uv_fs_scandir_next(req, &ent);
583 if (r == UV_EOF)
584 break;
585 if (r != 0) {
586 return req_wrap->Reject(
587 UVException(r, nullptr, req_wrap->syscall(),
588 static_cast<const char*>(req->path)));
589 }
590
591 MaybeLocal<Value> filename =
592 StringBytes::Encode(env->isolate(),
593 ent.name,
594 req_wrap->encoding(),
595 &error);
596 if (filename.IsEmpty())
597 return req_wrap->Reject(error);
598
599 name_argv[name_idx++] = filename.ToLocalChecked();
600
601 if (name_idx >= arraysize(name_argv)) {
602 MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx,
603 name_argv);
604 if (ret.IsEmpty()) {
605 return;
606 }
607 name_idx = 0;
608 }
609 }
610
611 if (name_idx > 0) {
612 fn->Call(env->context(), names, name_idx, name_argv)
613 .ToLocalChecked();
614 }
615
616 req_wrap->Resolve(names);
617 }
618
AfterScanDirWithTypes(uv_fs_t * req)619 void AfterScanDirWithTypes(uv_fs_t* req) {
620 FSReqBase* req_wrap = FSReqBase::from_req(req);
621 FSReqAfterScope after(req_wrap, req);
622
623 if (!after.Proceed()) {
624 return;
625 }
626
627 Environment* env = req_wrap->env();
628 Isolate* isolate = env->isolate();
629 Local<Value> error;
630 int r;
631 Local<Array> names = Array::New(isolate, 0);
632 Local<Function> fn = env->push_values_to_array_function();
633 Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
634 size_t name_idx = 0;
635 Local<Value> types = Array::New(isolate, 0);
636 Local<Value> type_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
637 size_t type_idx = 0;
638
639 for (int i = 0; ; i++) {
640 uv_dirent_t ent;
641
642 r = uv_fs_scandir_next(req, &ent);
643 if (r == UV_EOF)
644 break;
645 if (r != 0) {
646 return req_wrap->Reject(
647 UVException(r, nullptr, req_wrap->syscall(),
648 static_cast<const char*>(req->path)));
649 }
650
651 MaybeLocal<Value> filename =
652 StringBytes::Encode(isolate,
653 ent.name,
654 req_wrap->encoding(),
655 &error);
656 if (filename.IsEmpty())
657 return req_wrap->Reject(error);
658
659 name_argv[name_idx++] = filename.ToLocalChecked();
660
661 if (name_idx >= arraysize(name_argv)) {
662 MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx,
663 name_argv);
664 if (ret.IsEmpty()) {
665 return;
666 }
667 name_idx = 0;
668 }
669
670 type_argv[type_idx++] = Integer::New(isolate, ent.type);
671
672 if (type_idx >= arraysize(type_argv)) {
673 MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx,
674 type_argv);
675 if (ret.IsEmpty()) {
676 return;
677 }
678 type_idx = 0;
679 }
680 }
681
682 if (name_idx > 0) {
683 MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx,
684 name_argv);
685 if (ret.IsEmpty()) {
686 return;
687 }
688 }
689
690 if (type_idx > 0) {
691 MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx,
692 type_argv);
693 if (ret.IsEmpty()) {
694 return;
695 }
696 }
697
698 Local<Array> result = Array::New(isolate, 2);
699 result->Set(0, names);
700 result->Set(1, types);
701 req_wrap->Resolve(result);
702 }
703
704
705 // This class is only used on sync fs calls.
706 // For async calls FSReqWrap is used.
707 class FSReqWrapSync {
708 public:
FSReqWrapSync()709 FSReqWrapSync() {}
~FSReqWrapSync()710 ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
711 uv_fs_t req;
712
713 private:
714 DISALLOW_COPY_AND_ASSIGN(FSReqWrapSync);
715 };
716
717 // Returns nullptr if the operation fails from the start.
718 template <typename Func, typename... Args>
AsyncDestCall(Environment * env,FSReqBase * req_wrap,const FunctionCallbackInfo<Value> & args,const char * syscall,const char * dest,size_t len,enum encoding enc,uv_fs_cb after,Func fn,Args...fn_args)719 inline FSReqBase* AsyncDestCall(Environment* env,
720 FSReqBase* req_wrap,
721 const FunctionCallbackInfo<Value>& args,
722 const char* syscall, const char* dest, size_t len,
723 enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
724 CHECK_NOT_NULL(req_wrap);
725 req_wrap->Init(syscall, dest, len, enc);
726 int err = req_wrap->Dispatch(fn, fn_args..., after);
727 if (err < 0) {
728 uv_fs_t* uv_req = req_wrap->req();
729 uv_req->result = err;
730 uv_req->path = nullptr;
731 after(uv_req); // after may delete req_wrap if there is an error
732 req_wrap = nullptr;
733 } else {
734 req_wrap->SetReturnValue(args);
735 }
736
737 return req_wrap;
738 }
739
740 // Returns nullptr if the operation fails from the start.
741 template <typename Func, typename... Args>
AsyncCall(Environment * env,FSReqBase * req_wrap,const FunctionCallbackInfo<Value> & args,const char * syscall,enum encoding enc,uv_fs_cb after,Func fn,Args...fn_args)742 inline FSReqBase* AsyncCall(Environment* env,
743 FSReqBase* req_wrap,
744 const FunctionCallbackInfo<Value>& args,
745 const char* syscall, enum encoding enc,
746 uv_fs_cb after, Func fn, Args... fn_args) {
747 return AsyncDestCall(env, req_wrap, args,
748 syscall, nullptr, 0, enc,
749 after, fn, fn_args...);
750 }
751
752 // Template counterpart of SYNC_CALL, except that it only puts
753 // the error number and the syscall in the context instead of
754 // creating an error in the C++ land.
755 // ctx must be checked using value->IsObject() before being passed.
756 template <typename Func, typename... Args>
SyncCall(Environment * env,Local<Value> ctx,FSReqWrapSync * req_wrap,const char * syscall,Func fn,Args...args)757 inline int SyncCall(Environment* env, Local<Value> ctx, FSReqWrapSync* req_wrap,
758 const char* syscall, Func fn, Args... args) {
759 env->PrintSyncTrace();
760 int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
761 if (err < 0) {
762 Local<Context> context = env->context();
763 Local<Object> ctx_obj = ctx.As<Object>();
764 Isolate* isolate = env->isolate();
765 ctx_obj->Set(context,
766 env->errno_string(),
767 Integer::New(isolate, err)).FromJust();
768 ctx_obj->Set(context,
769 env->syscall_string(),
770 OneByteString(isolate, syscall)).FromJust();
771 }
772 return err;
773 }
774
GetReqWrap(Environment * env,Local<Value> value,bool use_bigint=false)775 inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
776 bool use_bigint = false) {
777 if (value->IsObject()) {
778 return Unwrap<FSReqBase>(value.As<Object>());
779 } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
780 if (use_bigint) {
781 return new FSReqPromise<uint64_t, BigUint64Array>(env, use_bigint);
782 } else {
783 return new FSReqPromise<double, Float64Array>(env, use_bigint);
784 }
785 }
786 return nullptr;
787 }
788
Access(const FunctionCallbackInfo<Value> & args)789 void Access(const FunctionCallbackInfo<Value>& args) {
790 Environment* env = Environment::GetCurrent(args);
791 Isolate* isolate = env->isolate();
792 HandleScope scope(isolate);
793
794 const int argc = args.Length();
795 CHECK_GE(argc, 2);
796
797 CHECK(args[1]->IsInt32());
798 int mode = args[1].As<Int32>()->Value();
799
800 BufferValue path(isolate, args[0]);
801 CHECK_NOT_NULL(*path);
802
803 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
804 if (req_wrap_async != nullptr) { // access(path, mode, req)
805 AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
806 uv_fs_access, *path, mode);
807 } else { // access(path, mode, undefined, ctx)
808 CHECK_EQ(argc, 4);
809 FSReqWrapSync req_wrap_sync;
810 FS_SYNC_TRACE_BEGIN(access);
811 SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
812 FS_SYNC_TRACE_END(access);
813 }
814 }
815
816
Close(const FunctionCallbackInfo<Value> & args)817 void Close(const FunctionCallbackInfo<Value>& args) {
818 Environment* env = Environment::GetCurrent(args);
819
820 const int argc = args.Length();
821 CHECK_GE(argc, 2);
822
823 CHECK(args[0]->IsInt32());
824 int fd = args[0].As<Int32>()->Value();
825
826 FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
827 if (req_wrap_async != nullptr) { // close(fd, req)
828 AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
829 uv_fs_close, fd);
830 } else { // close(fd, undefined, ctx)
831 CHECK_EQ(argc, 3);
832 FSReqWrapSync req_wrap_sync;
833 FS_SYNC_TRACE_BEGIN(close);
834 SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
835 FS_SYNC_TRACE_END(close);
836 }
837 }
838
839
840 // Used to speed up module loading. Returns the contents of the file as
841 // a string or undefined when the file cannot be opened or "main" is not found
842 // in the file.
InternalModuleReadJSON(const FunctionCallbackInfo<Value> & args)843 static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
844 Environment* env = Environment::GetCurrent(args);
845 Isolate* isolate = env->isolate();
846 uv_loop_t* loop = env->event_loop();
847
848 CHECK(args[0]->IsString());
849 node::Utf8Value path(isolate, args[0]);
850
851 if (strlen(*path) != path.length())
852 return; // Contains a nul byte.
853
854 uv_fs_t open_req;
855 const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
856 uv_fs_req_cleanup(&open_req);
857
858 if (fd < 0) {
859 return;
860 }
861
862 std::shared_ptr<void> defer_close(nullptr, [fd, loop] (...) {
863 uv_fs_t close_req;
864 CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
865 uv_fs_req_cleanup(&close_req);
866 });
867
868 const size_t kBlockSize = 32 << 10;
869 std::vector<char> chars;
870 int64_t offset = 0;
871 ssize_t numchars;
872 do {
873 const size_t start = chars.size();
874 chars.resize(start + kBlockSize);
875
876 uv_buf_t buf;
877 buf.base = &chars[start];
878 buf.len = kBlockSize;
879
880 uv_fs_t read_req;
881 numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
882 uv_fs_req_cleanup(&read_req);
883
884 if (numchars < 0)
885 return;
886
887 offset += numchars;
888 } while (static_cast<size_t>(numchars) == kBlockSize);
889
890 size_t start = 0;
891 if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
892 start = 3; // Skip UTF-8 BOM.
893 }
894
895 const size_t size = offset - start;
896 if (size == 0 || size == SearchString(&chars[start], size, "\"main\"")) {
897 return;
898 } else {
899 Local<String> chars_string =
900 String::NewFromUtf8(isolate,
901 &chars[start],
902 v8::NewStringType::kNormal,
903 size).ToLocalChecked();
904 args.GetReturnValue().Set(chars_string);
905 }
906 }
907
908 // Used to speed up module loading. Returns 0 if the path refers to
909 // a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
910 // The speedup comes from not creating thousands of Stat and Error objects.
InternalModuleStat(const FunctionCallbackInfo<Value> & args)911 static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
912 Environment* env = Environment::GetCurrent(args);
913
914 CHECK(args[0]->IsString());
915 node::Utf8Value path(env->isolate(), args[0]);
916
917 uv_fs_t req;
918 int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
919 if (rc == 0) {
920 const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
921 rc = !!(s->st_mode & S_IFDIR);
922 }
923 uv_fs_req_cleanup(&req);
924
925 args.GetReturnValue().Set(rc);
926 }
927
Stat(const FunctionCallbackInfo<Value> & args)928 static void Stat(const FunctionCallbackInfo<Value>& args) {
929 Environment* env = Environment::GetCurrent(args);
930
931 const int argc = args.Length();
932 CHECK_GE(argc, 2);
933
934 BufferValue path(env->isolate(), args[0]);
935 CHECK_NOT_NULL(*path);
936
937 bool use_bigint = args[1]->IsTrue();
938 FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
939 if (req_wrap_async != nullptr) { // stat(path, use_bigint, req)
940 AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
941 uv_fs_stat, *path);
942 } else { // stat(path, use_bigint, undefined, ctx)
943 CHECK_EQ(argc, 4);
944 FSReqWrapSync req_wrap_sync;
945 FS_SYNC_TRACE_BEGIN(stat);
946 int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
947 FS_SYNC_TRACE_END(stat);
948 if (err != 0) {
949 return; // error info is in ctx
950 }
951
952 Local<Value> arr = node::FillGlobalStatsArray(env,
953 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
954 args.GetReturnValue().Set(arr);
955 }
956 }
957
LStat(const FunctionCallbackInfo<Value> & args)958 static void LStat(const FunctionCallbackInfo<Value>& args) {
959 Environment* env = Environment::GetCurrent(args);
960
961 const int argc = args.Length();
962 CHECK_GE(argc, 3);
963
964 BufferValue path(env->isolate(), args[0]);
965 CHECK_NOT_NULL(*path);
966
967 bool use_bigint = args[1]->IsTrue();
968 FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
969 if (req_wrap_async != nullptr) { // lstat(path, use_bigint, req)
970 AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
971 uv_fs_lstat, *path);
972 } else { // lstat(path, use_bigint, undefined, ctx)
973 CHECK_EQ(argc, 4);
974 FSReqWrapSync req_wrap_sync;
975 FS_SYNC_TRACE_BEGIN(lstat);
976 int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
977 *path);
978 FS_SYNC_TRACE_END(lstat);
979 if (err != 0) {
980 return; // error info is in ctx
981 }
982
983 Local<Value> arr = node::FillGlobalStatsArray(env,
984 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
985 args.GetReturnValue().Set(arr);
986 }
987 }
988
FStat(const FunctionCallbackInfo<Value> & args)989 static void FStat(const FunctionCallbackInfo<Value>& args) {
990 Environment* env = Environment::GetCurrent(args);
991
992 const int argc = args.Length();
993 CHECK_GE(argc, 2);
994
995 CHECK(args[0]->IsInt32());
996 int fd = args[0].As<Int32>()->Value();
997
998 bool use_bigint = args[1]->IsTrue();
999 FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint);
1000 if (req_wrap_async != nullptr) { // fstat(fd, use_bigint, req)
1001 AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1002 uv_fs_fstat, fd);
1003 } else { // fstat(fd, use_bigint, undefined, ctx)
1004 CHECK_EQ(argc, 4);
1005 FSReqWrapSync req_wrap_sync;
1006 FS_SYNC_TRACE_BEGIN(fstat);
1007 int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1008 FS_SYNC_TRACE_END(fstat);
1009 if (err != 0) {
1010 return; // error info is in ctx
1011 }
1012
1013 Local<Value> arr = node::FillGlobalStatsArray(env,
1014 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
1015 args.GetReturnValue().Set(arr);
1016 }
1017 }
1018
Symlink(const FunctionCallbackInfo<Value> & args)1019 static void Symlink(const FunctionCallbackInfo<Value>& args) {
1020 Environment* env = Environment::GetCurrent(args);
1021 Isolate* isolate = env->isolate();
1022
1023 int argc = args.Length();
1024 CHECK_GE(argc, 4);
1025
1026 BufferValue target(isolate, args[0]);
1027 CHECK_NOT_NULL(*target);
1028 BufferValue path(isolate, args[1]);
1029 CHECK_NOT_NULL(*path);
1030
1031 CHECK(args[2]->IsInt32());
1032 int flags = args[2].As<Int32>()->Value();
1033
1034 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1035 if (req_wrap_async != nullptr) { // symlink(target, path, flags, req)
1036 AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1037 UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1038 } else { // symlink(target, path, flags, undefinec, ctx)
1039 CHECK_EQ(argc, 5);
1040 FSReqWrapSync req_wrap_sync;
1041 FS_SYNC_TRACE_BEGIN(symlink);
1042 SyncCall(env, args[4], &req_wrap_sync, "symlink",
1043 uv_fs_symlink, *target, *path, flags);
1044 FS_SYNC_TRACE_END(symlink);
1045 }
1046 }
1047
Link(const FunctionCallbackInfo<Value> & args)1048 static void Link(const FunctionCallbackInfo<Value>& args) {
1049 Environment* env = Environment::GetCurrent(args);
1050 Isolate* isolate = env->isolate();
1051
1052 int argc = args.Length();
1053 CHECK_GE(argc, 3);
1054
1055 BufferValue src(isolate, args[0]);
1056 CHECK_NOT_NULL(*src);
1057
1058 BufferValue dest(isolate, args[1]);
1059 CHECK_NOT_NULL(*dest);
1060
1061 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1062 if (req_wrap_async != nullptr) { // link(src, dest, req)
1063 AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1064 AfterNoArgs, uv_fs_link, *src, *dest);
1065 } else { // link(src, dest)
1066 CHECK_EQ(argc, 4);
1067 FSReqWrapSync req_wrap_sync;
1068 FS_SYNC_TRACE_BEGIN(link);
1069 SyncCall(env, args[3], &req_wrap_sync, "link",
1070 uv_fs_link, *src, *dest);
1071 FS_SYNC_TRACE_END(link);
1072 }
1073 }
1074
ReadLink(const FunctionCallbackInfo<Value> & args)1075 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1076 Environment* env = Environment::GetCurrent(args);
1077 Isolate* isolate = env->isolate();
1078
1079 int argc = args.Length();
1080 CHECK_GE(argc, 3);
1081
1082 BufferValue path(isolate, args[0]);
1083 CHECK_NOT_NULL(*path);
1084
1085 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1086
1087 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1088 if (req_wrap_async != nullptr) { // readlink(path, encoding, req)
1089 AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1090 uv_fs_readlink, *path);
1091 } else {
1092 CHECK_EQ(argc, 4);
1093 FSReqWrapSync req_wrap_sync;
1094 FS_SYNC_TRACE_BEGIN(readlink);
1095 int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1096 uv_fs_readlink, *path);
1097 FS_SYNC_TRACE_END(readlink);
1098 if (err < 0) {
1099 return; // syscall failed, no need to continue, error info is in ctx
1100 }
1101 const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1102
1103 Local<Value> error;
1104 MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1105 link_path,
1106 encoding,
1107 &error);
1108 if (rc.IsEmpty()) {
1109 Local<Object> ctx = args[3].As<Object>();
1110 ctx->Set(env->context(), env->error_string(), error).FromJust();
1111 return;
1112 }
1113
1114 args.GetReturnValue().Set(rc.ToLocalChecked());
1115 }
1116 }
1117
Rename(const FunctionCallbackInfo<Value> & args)1118 static void Rename(const FunctionCallbackInfo<Value>& args) {
1119 Environment* env = Environment::GetCurrent(args);
1120 Isolate* isolate = env->isolate();
1121
1122 int argc = args.Length();
1123 CHECK_GE(argc, 3);
1124
1125 BufferValue old_path(isolate, args[0]);
1126 CHECK_NOT_NULL(*old_path);
1127 BufferValue new_path(isolate, args[1]);
1128 CHECK_NOT_NULL(*new_path);
1129
1130 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1131 if (req_wrap_async != nullptr) {
1132 AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1133 new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1134 *old_path, *new_path);
1135 } else {
1136 CHECK_EQ(argc, 4);
1137 FSReqWrapSync req_wrap_sync;
1138 FS_SYNC_TRACE_BEGIN(rename);
1139 SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1140 *old_path, *new_path);
1141 FS_SYNC_TRACE_END(rename);
1142 }
1143 }
1144
FTruncate(const FunctionCallbackInfo<Value> & args)1145 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1146 Environment* env = Environment::GetCurrent(args);
1147
1148 const int argc = args.Length();
1149 CHECK_GE(argc, 3);
1150
1151 CHECK(args[0]->IsInt32());
1152 const int fd = args[0].As<Int32>()->Value();
1153
1154 CHECK(args[1]->IsNumber());
1155 const int64_t len = args[1].As<Integer>()->Value();
1156
1157 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1158 if (req_wrap_async != nullptr) {
1159 AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1160 uv_fs_ftruncate, fd, len);
1161 } else {
1162 CHECK_EQ(argc, 4);
1163 FSReqWrapSync req_wrap_sync;
1164 FS_SYNC_TRACE_BEGIN(ftruncate);
1165 SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1166 len);
1167 FS_SYNC_TRACE_END(ftruncate);
1168 }
1169 }
1170
Fdatasync(const FunctionCallbackInfo<Value> & args)1171 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1172 Environment* env = Environment::GetCurrent(args);
1173
1174 const int argc = args.Length();
1175 CHECK_GE(argc, 2);
1176
1177 CHECK(args[0]->IsInt32());
1178 const int fd = args[0].As<Int32>()->Value();
1179
1180 FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1181 if (req_wrap_async != nullptr) {
1182 AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1183 uv_fs_fdatasync, fd);
1184 } else {
1185 CHECK_EQ(argc, 3);
1186 FSReqWrapSync req_wrap_sync;
1187 FS_SYNC_TRACE_BEGIN(fdatasync);
1188 SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1189 FS_SYNC_TRACE_END(fdatasync);
1190 }
1191 }
1192
Fsync(const FunctionCallbackInfo<Value> & args)1193 static void Fsync(const FunctionCallbackInfo<Value>& args) {
1194 Environment* env = Environment::GetCurrent(args);
1195
1196 const int argc = args.Length();
1197 CHECK_GE(argc, 2);
1198
1199 CHECK(args[0]->IsInt32());
1200 const int fd = args[0].As<Int32>()->Value();
1201
1202 FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1203 if (req_wrap_async != nullptr) {
1204 AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1205 uv_fs_fsync, fd);
1206 } else {
1207 CHECK_EQ(argc, 3);
1208 FSReqWrapSync req_wrap_sync;
1209 FS_SYNC_TRACE_BEGIN(fsync);
1210 SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1211 FS_SYNC_TRACE_END(fsync);
1212 }
1213 }
1214
Unlink(const FunctionCallbackInfo<Value> & args)1215 static void Unlink(const FunctionCallbackInfo<Value>& args) {
1216 Environment* env = Environment::GetCurrent(args);
1217
1218 const int argc = args.Length();
1219 CHECK_GE(argc, 2);
1220
1221 BufferValue path(env->isolate(), args[0]);
1222 CHECK_NOT_NULL(*path);
1223
1224 FSReqBase* req_wrap_async = GetReqWrap(env, args[1]);
1225 if (req_wrap_async != nullptr) {
1226 AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1227 uv_fs_unlink, *path);
1228 } else {
1229 CHECK_EQ(argc, 3);
1230 FSReqWrapSync req_wrap_sync;
1231 FS_SYNC_TRACE_BEGIN(unlink);
1232 SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1233 FS_SYNC_TRACE_END(unlink);
1234 }
1235 }
1236
RMDir(const FunctionCallbackInfo<Value> & args)1237 static void RMDir(const FunctionCallbackInfo<Value>& args) {
1238 Environment* env = Environment::GetCurrent(args);
1239
1240 const int argc = args.Length();
1241 CHECK_GE(argc, 2);
1242
1243 BufferValue path(env->isolate(), args[0]);
1244 CHECK_NOT_NULL(*path);
1245
1246 FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); // rmdir(path, req)
1247 if (req_wrap_async != nullptr) {
1248 AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1249 uv_fs_rmdir, *path);
1250 } else { // rmdir(path, undefined, ctx)
1251 CHECK_EQ(argc, 3);
1252 FSReqWrapSync req_wrap_sync;
1253 FS_SYNC_TRACE_BEGIN(rmdir);
1254 SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1255 uv_fs_rmdir, *path);
1256 FS_SYNC_TRACE_END(rmdir);
1257 }
1258 }
1259
MKDirpSync(uv_loop_t * loop,uv_fs_t * req,const std::string & path,int mode,uv_fs_cb cb=nullptr)1260 int MKDirpSync(uv_loop_t* loop, uv_fs_t* req, const std::string& path, int mode,
1261 uv_fs_cb cb = nullptr) {
1262 FSContinuationData continuation_data(req, mode, cb);
1263 continuation_data.PushPath(std::move(path));
1264
1265 while (continuation_data.paths.size() > 0) {
1266 std::string next_path = continuation_data.PopPath();
1267 int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1268 while (true) {
1269 switch (err) {
1270 case 0:
1271 if (continuation_data.paths.size() == 0) {
1272 return 0;
1273 }
1274 break;
1275 case UV_ENOENT: {
1276 std::string dirname = next_path.substr(0,
1277 next_path.find_last_of(kPathSeparator));
1278 if (dirname != next_path) {
1279 continuation_data.PushPath(std::move(next_path));
1280 continuation_data.PushPath(std::move(dirname));
1281 } else if (continuation_data.paths.size() == 0) {
1282 err = UV_EEXIST;
1283 continue;
1284 }
1285 break;
1286 }
1287 case UV_EPERM: {
1288 return err;
1289 }
1290 default:
1291 uv_fs_req_cleanup(req);
1292 int orig_err = err;
1293 err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1294 if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1295 uv_fs_req_cleanup(req);
1296 if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
1297 return UV_ENOTDIR;
1298 }
1299 return UV_EEXIST;
1300 }
1301 if (err < 0) return err;
1302 break;
1303 }
1304 break;
1305 }
1306 uv_fs_req_cleanup(req);
1307 }
1308
1309 return 0;
1310 }
1311
MKDirpAsync(uv_loop_t * loop,uv_fs_t * req,const char * path,int mode,uv_fs_cb cb)1312 int MKDirpAsync(uv_loop_t* loop,
1313 uv_fs_t* req,
1314 const char* path,
1315 int mode,
1316 uv_fs_cb cb) {
1317 FSReqBase* req_wrap = FSReqBase::from_req(req);
1318 // on the first iteration of algorithm, stash state information.
1319 if (req_wrap->continuation_data == nullptr) {
1320 req_wrap->continuation_data = std::unique_ptr<FSContinuationData>{
1321 new FSContinuationData(req, mode, cb)};
1322 req_wrap->continuation_data->PushPath(std::move(path));
1323 }
1324
1325 // on each iteration of algorithm, mkdir directory on top of stack.
1326 std::string next_path = req_wrap->continuation_data->PopPath();
1327 int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1328 uv_fs_callback_t{[](uv_fs_t* req) {
1329 FSReqBase* req_wrap = FSReqBase::from_req(req);
1330 Environment* env = req_wrap->env();
1331 uv_loop_t* loop = env->event_loop();
1332 std::string path = req->path;
1333 int err = req->result;
1334
1335 while (true) {
1336 switch (err) {
1337 case 0: {
1338 if (req_wrap->continuation_data->paths.size() == 0) {
1339 req_wrap->continuation_data->Done(0);
1340 } else {
1341 uv_fs_req_cleanup(req);
1342 MKDirpAsync(loop, req, path.c_str(),
1343 req_wrap->continuation_data->mode, nullptr);
1344 }
1345 break;
1346 }
1347 case UV_ENOENT: {
1348 std::string dirname = path.substr(0,
1349 path.find_last_of(kPathSeparator));
1350 if (dirname != path) {
1351 req_wrap->continuation_data->PushPath(std::move(path));
1352 req_wrap->continuation_data->PushPath(std::move(dirname));
1353 } else if (req_wrap->continuation_data->paths.size() == 0) {
1354 err = UV_EEXIST;
1355 continue;
1356 }
1357 uv_fs_req_cleanup(req);
1358 MKDirpAsync(loop, req, path.c_str(),
1359 req_wrap->continuation_data->mode, nullptr);
1360 break;
1361 }
1362 case UV_EPERM: {
1363 req_wrap->continuation_data->Done(err);
1364 break;
1365 }
1366 default:
1367 uv_fs_req_cleanup(req);
1368 // Stash err for use in the callback.
1369 req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1370 int err = uv_fs_stat(loop, req, path.c_str(),
1371 uv_fs_callback_t{[](uv_fs_t* req) {
1372 FSReqBase* req_wrap = FSReqBase::from_req(req);
1373 int err = req->result;
1374 if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1375 req_wrap->continuation_data->paths.size() > 0) {
1376 if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1377 Environment* env = req_wrap->env();
1378 uv_loop_t* loop = env->event_loop();
1379 std::string path = req->path;
1380 uv_fs_req_cleanup(req);
1381 MKDirpAsync(loop, req, path.c_str(),
1382 req_wrap->continuation_data->mode, nullptr);
1383 return;
1384 }
1385 err = UV_ENOTDIR;
1386 }
1387 // verify that the path pointed to is actually a directory.
1388 if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1389 uv_fs_req_cleanup(req);
1390 req_wrap->continuation_data->Done(err);
1391 }});
1392 if (err < 0) req_wrap->continuation_data->Done(err);
1393 break;
1394 }
1395 break;
1396 }
1397 }});
1398
1399 return err;
1400 }
1401
MKDir(const FunctionCallbackInfo<Value> & args)1402 static void MKDir(const FunctionCallbackInfo<Value>& args) {
1403 Environment* env = Environment::GetCurrent(args);
1404
1405 const int argc = args.Length();
1406 CHECK_GE(argc, 4);
1407
1408 BufferValue path(env->isolate(), args[0]);
1409 CHECK_NOT_NULL(*path);
1410
1411 CHECK(args[1]->IsInt32());
1412 const int mode = args[1].As<Int32>()->Value();
1413
1414 CHECK(args[2]->IsBoolean());
1415 bool mkdirp = args[2]->IsTrue();
1416
1417 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1418 if (req_wrap_async != nullptr) { // mkdir(path, mode, req)
1419 AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1420 AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1421 } else { // mkdir(path, mode, undefined, ctx)
1422 CHECK_EQ(argc, 5);
1423 FSReqWrapSync req_wrap_sync;
1424 FS_SYNC_TRACE_BEGIN(mkdir);
1425 if (mkdirp) {
1426 SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1427 MKDirpSync, *path, mode);
1428 } else {
1429 SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1430 uv_fs_mkdir, *path, mode);
1431 }
1432 FS_SYNC_TRACE_END(mkdir);
1433 }
1434 }
1435
RealPath(const FunctionCallbackInfo<Value> & args)1436 static void RealPath(const FunctionCallbackInfo<Value>& args) {
1437 Environment* env = Environment::GetCurrent(args);
1438 Isolate* isolate = env->isolate();
1439
1440 const int argc = args.Length();
1441 CHECK_GE(argc, 3);
1442
1443 BufferValue path(isolate, args[0]);
1444 CHECK_NOT_NULL(*path);
1445
1446 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1447
1448 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1449 if (req_wrap_async != nullptr) { // realpath(path, encoding, req)
1450 AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1451 uv_fs_realpath, *path);
1452 } else { // realpath(path, encoding, undefined, ctx)
1453 CHECK_EQ(argc, 4);
1454 FSReqWrapSync req_wrap_sync;
1455 FS_SYNC_TRACE_BEGIN(realpath);
1456 int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1457 uv_fs_realpath, *path);
1458 FS_SYNC_TRACE_END(realpath);
1459 if (err < 0) {
1460 return; // syscall failed, no need to continue, error info is in ctx
1461 }
1462
1463 const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1464
1465 Local<Value> error;
1466 MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1467 link_path,
1468 encoding,
1469 &error);
1470 if (rc.IsEmpty()) {
1471 Local<Object> ctx = args[3].As<Object>();
1472 ctx->Set(env->context(), env->error_string(), error).FromJust();
1473 return;
1474 }
1475
1476 args.GetReturnValue().Set(rc.ToLocalChecked());
1477 }
1478 }
1479
ReadDir(const FunctionCallbackInfo<Value> & args)1480 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1481 Environment* env = Environment::GetCurrent(args);
1482 Isolate* isolate = env->isolate();
1483
1484 const int argc = args.Length();
1485 CHECK_GE(argc, 3);
1486
1487 BufferValue path(isolate, args[0]);
1488 CHECK_NOT_NULL(*path);
1489
1490 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1491
1492 bool with_types = args[2]->IsTrue();
1493
1494 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1495 if (req_wrap_async != nullptr) { // readdir(path, encoding, withTypes, req)
1496 if (with_types) {
1497 AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1498 AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/);
1499 } else {
1500 AsyncCall(env, req_wrap_async, args, "scandir", encoding,
1501 AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/);
1502 }
1503 } else { // readdir(path, encoding, withTypes, undefined, ctx)
1504 CHECK_EQ(argc, 5);
1505 FSReqWrapSync req_wrap_sync;
1506 FS_SYNC_TRACE_BEGIN(readdir);
1507 int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1508 uv_fs_scandir, *path, 0 /*flags*/);
1509 FS_SYNC_TRACE_END(readdir);
1510 if (err < 0) {
1511 return; // syscall failed, no need to continue, error info is in ctx
1512 }
1513
1514 CHECK_GE(req_wrap_sync.req.result, 0);
1515 int r;
1516 Local<Array> names = Array::New(isolate, 0);
1517 Local<Function> fn = env->push_values_to_array_function();
1518 Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
1519 size_t name_idx = 0;
1520
1521 Local<Value> types;
1522 Local<Value> type_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
1523 size_t type_idx;
1524 if (with_types) {
1525 types = Array::New(isolate, 0);
1526 type_idx = 0;
1527 }
1528
1529 for (int i = 0; ; i++) {
1530 uv_dirent_t ent;
1531
1532 r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1533 if (r == UV_EOF)
1534 break;
1535 if (r != 0) {
1536 Local<Object> ctx = args[4].As<Object>();
1537 ctx->Set(env->context(), env->errno_string(),
1538 Integer::New(isolate, r)).FromJust();
1539 ctx->Set(env->context(), env->syscall_string(),
1540 OneByteString(isolate, "readdir")).FromJust();
1541 return;
1542 }
1543
1544 Local<Value> error;
1545 MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1546 ent.name,
1547 encoding,
1548 &error);
1549
1550 if (filename.IsEmpty()) {
1551 Local<Object> ctx = args[4].As<Object>();
1552 ctx->Set(env->context(), env->error_string(), error).FromJust();
1553 return;
1554 }
1555
1556 name_v[name_idx++] = filename.ToLocalChecked();
1557
1558 if (name_idx >= arraysize(name_v)) {
1559 MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx,
1560 name_v);
1561 if (ret.IsEmpty()) {
1562 return;
1563 }
1564 name_idx = 0;
1565 }
1566
1567 if (with_types) {
1568 type_v[type_idx++] = Integer::New(isolate, ent.type);
1569
1570 if (type_idx >= arraysize(type_v)) {
1571 MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx,
1572 type_v);
1573 if (ret.IsEmpty()) {
1574 return;
1575 }
1576 type_idx = 0;
1577 }
1578 }
1579 }
1580
1581 if (name_idx > 0) {
1582 MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx, name_v);
1583 if (ret.IsEmpty()) {
1584 return;
1585 }
1586 }
1587
1588 if (with_types && type_idx > 0) {
1589 MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx, type_v);
1590 if (ret.IsEmpty()) {
1591 return;
1592 }
1593 }
1594
1595 if (with_types) {
1596 Local<Array> result = Array::New(isolate, 2);
1597 result->Set(0, names);
1598 result->Set(1, types);
1599 args.GetReturnValue().Set(result);
1600 } else {
1601 args.GetReturnValue().Set(names);
1602 }
1603 }
1604 }
1605
Open(const FunctionCallbackInfo<Value> & args)1606 static void Open(const FunctionCallbackInfo<Value>& args) {
1607 Environment* env = Environment::GetCurrent(args);
1608
1609 const int argc = args.Length();
1610 CHECK_GE(argc, 3);
1611
1612 BufferValue path(env->isolate(), args[0]);
1613 CHECK_NOT_NULL(*path);
1614
1615 CHECK(args[1]->IsInt32());
1616 const int flags = args[1].As<Int32>()->Value();
1617
1618 CHECK(args[2]->IsInt32());
1619 const int mode = args[2].As<Int32>()->Value();
1620
1621 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1622 if (req_wrap_async != nullptr) { // open(path, flags, mode, req)
1623 AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1624 uv_fs_open, *path, flags, mode);
1625 } else { // open(path, flags, mode, undefined, ctx)
1626 CHECK_EQ(argc, 5);
1627 FSReqWrapSync req_wrap_sync;
1628 FS_SYNC_TRACE_BEGIN(open);
1629 int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1630 uv_fs_open, *path, flags, mode);
1631 FS_SYNC_TRACE_END(open);
1632 args.GetReturnValue().Set(result);
1633 }
1634 }
1635
OpenFileHandle(const FunctionCallbackInfo<Value> & args)1636 static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1637 Environment* env = Environment::GetCurrent(args);
1638 Isolate* isolate = env->isolate();
1639
1640 const int argc = args.Length();
1641 CHECK_GE(argc, 3);
1642
1643 BufferValue path(isolate, args[0]);
1644 CHECK_NOT_NULL(*path);
1645
1646 CHECK(args[1]->IsInt32());
1647 const int flags = args[1].As<Int32>()->Value();
1648
1649 CHECK(args[2]->IsInt32());
1650 const int mode = args[2].As<Int32>()->Value();
1651
1652 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1653 if (req_wrap_async != nullptr) { // openFileHandle(path, flags, mode, req)
1654 AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1655 uv_fs_open, *path, flags, mode);
1656 } else { // openFileHandle(path, flags, mode, undefined, ctx)
1657 CHECK_EQ(argc, 5);
1658 FSReqWrapSync req_wrap_sync;
1659 FS_SYNC_TRACE_BEGIN(open);
1660 int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1661 uv_fs_open, *path, flags, mode);
1662 FS_SYNC_TRACE_END(open);
1663 if (result < 0) {
1664 return; // syscall failed, no need to continue, error info is in ctx
1665 }
1666 HandleScope scope(isolate);
1667 FileHandle* fd = new FileHandle(env, result);
1668 args.GetReturnValue().Set(fd->object());
1669 }
1670 }
1671
CopyFile(const FunctionCallbackInfo<Value> & args)1672 static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1673 Environment* env = Environment::GetCurrent(args);
1674 Isolate* isolate = env->isolate();
1675
1676 const int argc = args.Length();
1677 CHECK_GE(argc, 3);
1678
1679 BufferValue src(isolate, args[0]);
1680 CHECK_NOT_NULL(*src);
1681
1682 BufferValue dest(isolate, args[1]);
1683 CHECK_NOT_NULL(*dest);
1684
1685 CHECK(args[2]->IsInt32());
1686 const int flags = args[2].As<Int32>()->Value();
1687
1688 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1689 if (req_wrap_async != nullptr) { // copyFile(src, dest, flags, req)
1690 AsyncDestCall(env, req_wrap_async, args, "copyfile",
1691 *dest, dest.length(), UTF8, AfterNoArgs,
1692 uv_fs_copyfile, *src, *dest, flags);
1693 } else { // copyFile(src, dest, flags, undefined, ctx)
1694 CHECK_EQ(argc, 5);
1695 FSReqWrapSync req_wrap_sync;
1696 FS_SYNC_TRACE_BEGIN(copyfile);
1697 SyncCall(env, args[4], &req_wrap_sync, "copyfile",
1698 uv_fs_copyfile, *src, *dest, flags);
1699 FS_SYNC_TRACE_END(copyfile);
1700 }
1701 }
1702
1703
1704 // Wrapper for write(2).
1705 //
1706 // bytesWritten = write(fd, buffer, offset, length, position, callback)
1707 // 0 fd integer. file descriptor
1708 // 1 buffer the data to write
1709 // 2 offset where in the buffer to start from
1710 // 3 length how much to write
1711 // 4 position if integer, position to write at in the file.
1712 // if null, write from the current position
WriteBuffer(const FunctionCallbackInfo<Value> & args)1713 static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1714 Environment* env = Environment::GetCurrent(args);
1715
1716 const int argc = args.Length();
1717 CHECK_GE(argc, 4);
1718
1719 CHECK(args[0]->IsInt32());
1720 const int fd = args[0].As<Int32>()->Value();
1721
1722 CHECK(Buffer::HasInstance(args[1]));
1723 Local<Object> buffer_obj = args[1].As<Object>();
1724 char* buffer_data = Buffer::Data(buffer_obj);
1725 size_t buffer_length = Buffer::Length(buffer_obj);
1726
1727 CHECK(args[2]->IsInt32());
1728 const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1729 CHECK_LE(off, buffer_length);
1730
1731 CHECK(args[3]->IsInt32());
1732 const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1733 CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1734 CHECK_LE(len, buffer_length);
1735 CHECK_GE(off + len, off);
1736
1737 const int64_t pos = GET_OFFSET(args[4]);
1738
1739 char* buf = buffer_data + off;
1740 uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1741
1742 FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1743 if (req_wrap_async != nullptr) { // write(fd, buffer, off, len, pos, req)
1744 AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1745 uv_fs_write, fd, &uvbuf, 1, pos);
1746 } else { // write(fd, buffer, off, len, pos, undefined, ctx)
1747 CHECK_EQ(argc, 7);
1748 FSReqWrapSync req_wrap_sync;
1749 FS_SYNC_TRACE_BEGIN(write);
1750 int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
1751 uv_fs_write, fd, &uvbuf, 1, pos);
1752 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1753 args.GetReturnValue().Set(bytesWritten);
1754 }
1755 }
1756
1757
1758 // Wrapper for writev(2).
1759 //
1760 // bytesWritten = writev(fd, chunks, position, callback)
1761 // 0 fd integer. file descriptor
1762 // 1 chunks array of buffers to write
1763 // 2 position if integer, position to write at in the file.
1764 // if null, write from the current position
WriteBuffers(const FunctionCallbackInfo<Value> & args)1765 static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1766 Environment* env = Environment::GetCurrent(args);
1767
1768 const int argc = args.Length();
1769 CHECK_GE(argc, 3);
1770
1771 CHECK(args[0]->IsInt32());
1772 const int fd = args[0].As<Int32>()->Value();
1773
1774 CHECK(args[1]->IsArray());
1775 Local<Array> chunks = args[1].As<Array>();
1776
1777 int64_t pos = GET_OFFSET(args[2]);
1778
1779 MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1780
1781 for (uint32_t i = 0; i < iovs.length(); i++) {
1782 Local<Value> chunk = chunks->Get(i);
1783 CHECK(Buffer::HasInstance(chunk));
1784 iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1785 }
1786
1787 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
1788 if (req_wrap_async != nullptr) { // writeBuffers(fd, chunks, pos, req)
1789 AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
1790 uv_fs_write, fd, *iovs, iovs.length(), pos);
1791 } else { // writeBuffers(fd, chunks, pos, undefined, ctx)
1792 CHECK_EQ(argc, 5);
1793 FSReqWrapSync req_wrap_sync;
1794 FS_SYNC_TRACE_BEGIN(write);
1795 int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
1796 uv_fs_write, fd, *iovs, iovs.length(), pos);
1797 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1798 args.GetReturnValue().Set(bytesWritten);
1799 }
1800 }
1801
1802
1803 // Wrapper for write(2).
1804 //
1805 // bytesWritten = write(fd, string, position, enc, callback)
1806 // 0 fd integer. file descriptor
1807 // 1 string non-buffer values are converted to strings
1808 // 2 position if integer, position to write at in the file.
1809 // if null, write from the current position
1810 // 3 enc encoding of string
WriteString(const FunctionCallbackInfo<Value> & args)1811 static void WriteString(const FunctionCallbackInfo<Value>& args) {
1812 Environment* env = Environment::GetCurrent(args);
1813 Isolate* isolate = env->isolate();
1814
1815 const int argc = args.Length();
1816 CHECK_GE(argc, 4);
1817
1818 CHECK(args[0]->IsInt32());
1819 const int fd = args[0].As<Int32>()->Value();
1820
1821 const int64_t pos = GET_OFFSET(args[2]);
1822
1823 const auto enc = ParseEncoding(isolate, args[3], UTF8);
1824
1825 Local<Value> value = args[1];
1826 char* buf = nullptr;
1827 size_t len;
1828
1829 FSReqBase* req_wrap_async = GetReqWrap(env, args[4]);
1830 const bool is_async = req_wrap_async != nullptr;
1831
1832 // Avoid copying the string when it is externalized but only when:
1833 // 1. The target encoding is compatible with the string's encoding, and
1834 // 2. The write is synchronous, otherwise the string might get neutered
1835 // while the request is in flight, and
1836 // 3. For UCS2, when the host system is little-endian. Big-endian systems
1837 // need to call StringBytes::Write() to ensure proper byte swapping.
1838 // The const_casts are conceptually sound: memory is read but not written.
1839 if (!is_async && value->IsString()) {
1840 auto string = value.As<String>();
1841 if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
1842 auto ext = string->GetExternalOneByteStringResource();
1843 buf = const_cast<char*>(ext->data());
1844 len = ext->length();
1845 } else if (enc == UCS2 && IsLittleEndian() && string->IsExternal()) {
1846 auto ext = string->GetExternalStringResource();
1847 buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
1848 len = ext->length() * sizeof(*ext->data());
1849 }
1850 }
1851
1852 if (is_async) { // write(fd, string, pos, enc, req)
1853 CHECK_NOT_NULL(req_wrap_async);
1854 if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
1855 FSReqBase::FSReqBuffer& stack_buffer =
1856 req_wrap_async->Init("write", len, enc);
1857 // StorageSize may return too large a char, so correct the actual length
1858 // by the write size
1859 len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
1860 stack_buffer.SetLengthAndZeroTerminate(len);
1861 uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
1862 int err = req_wrap_async->Dispatch(uv_fs_write,
1863 fd,
1864 &uvbuf,
1865 1,
1866 pos,
1867 AfterInteger);
1868 if (err < 0) {
1869 uv_fs_t* uv_req = req_wrap_async->req();
1870 uv_req->result = err;
1871 uv_req->path = nullptr;
1872 AfterInteger(uv_req); // after may delete req_wrap_async if there is
1873 // an error
1874 } else {
1875 req_wrap_async->SetReturnValue(args);
1876 }
1877 } else { // write(fd, string, pos, enc, undefined, ctx)
1878 CHECK_EQ(argc, 6);
1879 FSReqWrapSync req_wrap_sync;
1880 FSReqBase::FSReqBuffer stack_buffer;
1881 if (buf == nullptr) {
1882 if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
1883 return;
1884 stack_buffer.AllocateSufficientStorage(len + 1);
1885 // StorageSize may return too large a char, so correct the actual length
1886 // by the write size
1887 len = StringBytes::Write(isolate, *stack_buffer,
1888 len, args[1], enc);
1889 stack_buffer.SetLengthAndZeroTerminate(len);
1890 buf = *stack_buffer;
1891 }
1892 uv_buf_t uvbuf = uv_buf_init(buf, len);
1893 FS_SYNC_TRACE_BEGIN(write);
1894 int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
1895 uv_fs_write, fd, &uvbuf, 1, pos);
1896 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
1897 args.GetReturnValue().Set(bytesWritten);
1898 }
1899 }
1900
1901
1902 /*
1903 * Wrapper for read(2).
1904 *
1905 * bytesRead = fs.read(fd, buffer, offset, length, position)
1906 *
1907 * 0 fd int32. file descriptor
1908 * 1 buffer instance of Buffer
1909 * 2 offset int32. offset to start reading into inside buffer
1910 * 3 length int32. length to read
1911 * 4 position int64. file position - -1 for current position
1912 */
Read(const FunctionCallbackInfo<Value> & args)1913 static void Read(const FunctionCallbackInfo<Value>& args) {
1914 Environment* env = Environment::GetCurrent(args);
1915
1916 const int argc = args.Length();
1917 CHECK_GE(argc, 5);
1918
1919 CHECK(args[0]->IsInt32());
1920 const int fd = args[0].As<Int32>()->Value();
1921
1922 CHECK(Buffer::HasInstance(args[1]));
1923 Local<Object> buffer_obj = args[1].As<Object>();
1924 char* buffer_data = Buffer::Data(buffer_obj);
1925 size_t buffer_length = Buffer::Length(buffer_obj);
1926
1927 CHECK(args[2]->IsInt32());
1928 const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1929 CHECK_LT(off, buffer_length);
1930
1931 CHECK(args[3]->IsInt32());
1932 const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
1933 CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
1934
1935 CHECK(args[4]->IsNumber());
1936 const int64_t pos = args[4].As<Integer>()->Value();
1937
1938 char* buf = buffer_data + off;
1939 uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1940
1941 FSReqBase* req_wrap_async = GetReqWrap(env, args[5]);
1942 if (req_wrap_async != nullptr) { // read(fd, buffer, offset, len, pos, req)
1943 AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
1944 uv_fs_read, fd, &uvbuf, 1, pos);
1945 } else { // read(fd, buffer, offset, len, pos, undefined, ctx)
1946 CHECK_EQ(argc, 7);
1947 FSReqWrapSync req_wrap_sync;
1948 FS_SYNC_TRACE_BEGIN(read);
1949 const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
1950 uv_fs_read, fd, &uvbuf, 1, pos);
1951 FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
1952 args.GetReturnValue().Set(bytesRead);
1953 }
1954 }
1955
1956
1957 /* fs.chmod(path, mode);
1958 * Wrapper for chmod(1) / EIO_CHMOD
1959 */
Chmod(const FunctionCallbackInfo<Value> & args)1960 static void Chmod(const FunctionCallbackInfo<Value>& args) {
1961 Environment* env = Environment::GetCurrent(args);
1962
1963 const int argc = args.Length();
1964 CHECK_GE(argc, 2);
1965
1966 BufferValue path(env->isolate(), args[0]);
1967 CHECK_NOT_NULL(*path);
1968
1969 CHECK(args[1]->IsInt32());
1970 int mode = args[1].As<Int32>()->Value();
1971
1972 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
1973 if (req_wrap_async != nullptr) { // chmod(path, mode, req)
1974 AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
1975 uv_fs_chmod, *path, mode);
1976 } else { // chmod(path, mode, undefined, ctx)
1977 CHECK_EQ(argc, 4);
1978 FSReqWrapSync req_wrap_sync;
1979 FS_SYNC_TRACE_BEGIN(chmod);
1980 SyncCall(env, args[3], &req_wrap_sync, "chmod",
1981 uv_fs_chmod, *path, mode);
1982 FS_SYNC_TRACE_END(chmod);
1983 }
1984 }
1985
1986
1987 /* fs.fchmod(fd, mode);
1988 * Wrapper for fchmod(1) / EIO_FCHMOD
1989 */
FChmod(const FunctionCallbackInfo<Value> & args)1990 static void FChmod(const FunctionCallbackInfo<Value>& args) {
1991 Environment* env = Environment::GetCurrent(args);
1992
1993 const int argc = args.Length();
1994 CHECK_GE(argc, 2);
1995
1996 CHECK(args[0]->IsInt32());
1997 const int fd = args[0].As<Int32>()->Value();
1998
1999 CHECK(args[1]->IsInt32());
2000 const int mode = args[1].As<Int32>()->Value();
2001
2002 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2003 if (req_wrap_async != nullptr) { // fchmod(fd, mode, req)
2004 AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2005 uv_fs_fchmod, fd, mode);
2006 } else { // fchmod(fd, mode, undefined, ctx)
2007 CHECK_EQ(argc, 4);
2008 FSReqWrapSync req_wrap_sync;
2009 FS_SYNC_TRACE_BEGIN(fchmod);
2010 SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2011 uv_fs_fchmod, fd, mode);
2012 FS_SYNC_TRACE_END(fchmod);
2013 }
2014 }
2015
2016
2017 /* fs.chown(path, uid, gid);
2018 * Wrapper for chown(1) / EIO_CHOWN
2019 */
Chown(const FunctionCallbackInfo<Value> & args)2020 static void Chown(const FunctionCallbackInfo<Value>& args) {
2021 Environment* env = Environment::GetCurrent(args);
2022
2023 const int argc = args.Length();
2024 CHECK_GE(argc, 3);
2025
2026 BufferValue path(env->isolate(), args[0]);
2027 CHECK_NOT_NULL(*path);
2028
2029 CHECK(args[1]->IsUint32());
2030 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2031
2032 CHECK(args[2]->IsUint32());
2033 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2034
2035 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2036 if (req_wrap_async != nullptr) { // chown(path, uid, gid, req)
2037 AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2038 uv_fs_chown, *path, uid, gid);
2039 } else { // chown(path, uid, gid, undefined, ctx)
2040 CHECK_EQ(argc, 5);
2041 FSReqWrapSync req_wrap_sync;
2042 FS_SYNC_TRACE_BEGIN(chown);
2043 SyncCall(env, args[4], &req_wrap_sync, "chown",
2044 uv_fs_chown, *path, uid, gid);
2045 FS_SYNC_TRACE_END(chown);
2046 }
2047 }
2048
2049
2050 /* fs.fchown(fd, uid, gid);
2051 * Wrapper for fchown(1) / EIO_FCHOWN
2052 */
FChown(const FunctionCallbackInfo<Value> & args)2053 static void FChown(const FunctionCallbackInfo<Value>& args) {
2054 Environment* env = Environment::GetCurrent(args);
2055
2056 const int argc = args.Length();
2057 CHECK_GE(argc, 3);
2058
2059 CHECK(args[0]->IsInt32());
2060 const int fd = args[0].As<Int32>()->Value();
2061
2062 CHECK(args[1]->IsUint32());
2063 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2064
2065 CHECK(args[2]->IsUint32());
2066 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2067
2068 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2069 if (req_wrap_async != nullptr) { // fchown(fd, uid, gid, req)
2070 AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2071 uv_fs_fchown, fd, uid, gid);
2072 } else { // fchown(fd, uid, gid, undefined, ctx)
2073 CHECK_EQ(argc, 5);
2074 FSReqWrapSync req_wrap_sync;
2075 FS_SYNC_TRACE_BEGIN(fchown);
2076 SyncCall(env, args[4], &req_wrap_sync, "fchown",
2077 uv_fs_fchown, fd, uid, gid);
2078 FS_SYNC_TRACE_END(fchown);
2079 }
2080 }
2081
2082
LChown(const FunctionCallbackInfo<Value> & args)2083 static void LChown(const FunctionCallbackInfo<Value>& args) {
2084 Environment* env = Environment::GetCurrent(args);
2085
2086 const int argc = args.Length();
2087 CHECK_GE(argc, 3);
2088
2089 BufferValue path(env->isolate(), args[0]);
2090 CHECK_NOT_NULL(*path);
2091
2092 CHECK(args[1]->IsUint32());
2093 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Uint32>()->Value());
2094
2095 CHECK(args[2]->IsUint32());
2096 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Uint32>()->Value());
2097
2098 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2099 if (req_wrap_async != nullptr) { // lchown(path, uid, gid, req)
2100 AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2101 uv_fs_lchown, *path, uid, gid);
2102 } else { // lchown(path, uid, gid, undefined, ctx)
2103 CHECK_EQ(argc, 5);
2104 FSReqWrapSync req_wrap_sync;
2105 FS_SYNC_TRACE_BEGIN(lchown);
2106 SyncCall(env, args[4], &req_wrap_sync, "lchown",
2107 uv_fs_lchown, *path, uid, gid);
2108 FS_SYNC_TRACE_END(lchown);
2109 }
2110 }
2111
2112
UTimes(const FunctionCallbackInfo<Value> & args)2113 static void UTimes(const FunctionCallbackInfo<Value>& args) {
2114 Environment* env = Environment::GetCurrent(args);
2115
2116 const int argc = args.Length();
2117 CHECK_GE(argc, 3);
2118
2119 BufferValue path(env->isolate(), args[0]);
2120 CHECK_NOT_NULL(*path);
2121
2122 CHECK(args[1]->IsNumber());
2123 const double atime = args[1].As<Number>()->Value();
2124
2125 CHECK(args[2]->IsNumber());
2126 const double mtime = args[2].As<Number>()->Value();
2127
2128 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2129 if (req_wrap_async != nullptr) { // utimes(path, atime, mtime, req)
2130 AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2131 uv_fs_utime, *path, atime, mtime);
2132 } else { // utimes(path, atime, mtime, undefined, ctx)
2133 CHECK_EQ(argc, 5);
2134 FSReqWrapSync req_wrap_sync;
2135 FS_SYNC_TRACE_BEGIN(utimes);
2136 SyncCall(env, args[4], &req_wrap_sync, "utime",
2137 uv_fs_utime, *path, atime, mtime);
2138 FS_SYNC_TRACE_END(utimes);
2139 }
2140 }
2141
FUTimes(const FunctionCallbackInfo<Value> & args)2142 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2143 Environment* env = Environment::GetCurrent(args);
2144
2145 const int argc = args.Length();
2146 CHECK_GE(argc, 3);
2147
2148 CHECK(args[0]->IsInt32());
2149 const int fd = args[0].As<Int32>()->Value();
2150
2151 CHECK(args[1]->IsNumber());
2152 const double atime = args[1].As<Number>()->Value();
2153
2154 CHECK(args[2]->IsNumber());
2155 const double mtime = args[2].As<Number>()->Value();
2156
2157 FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2158 if (req_wrap_async != nullptr) { // futimes(fd, atime, mtime, req)
2159 AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2160 uv_fs_futime, fd, atime, mtime);
2161 } else { // futimes(fd, atime, mtime, undefined, ctx)
2162 CHECK_EQ(argc, 5);
2163 FSReqWrapSync req_wrap_sync;
2164 FS_SYNC_TRACE_BEGIN(futimes);
2165 SyncCall(env, args[4], &req_wrap_sync, "futime",
2166 uv_fs_futime, fd, atime, mtime);
2167 FS_SYNC_TRACE_END(futimes);
2168 }
2169 }
2170
Mkdtemp(const FunctionCallbackInfo<Value> & args)2171 static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2172 Environment* env = Environment::GetCurrent(args);
2173 Isolate* isolate = env->isolate();
2174
2175 const int argc = args.Length();
2176 CHECK_GE(argc, 2);
2177
2178 BufferValue tmpl(isolate, args[0]);
2179 CHECK_NOT_NULL(*tmpl);
2180
2181 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2182
2183 FSReqBase* req_wrap_async = GetReqWrap(env, args[2]);
2184 if (req_wrap_async != nullptr) { // mkdtemp(tmpl, encoding, req)
2185 AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2186 uv_fs_mkdtemp, *tmpl);
2187 } else { // mkdtemp(tmpl, encoding, undefined, ctx)
2188 CHECK_EQ(argc, 4);
2189 FSReqWrapSync req_wrap_sync;
2190 FS_SYNC_TRACE_BEGIN(mkdtemp);
2191 SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2192 uv_fs_mkdtemp, *tmpl);
2193 FS_SYNC_TRACE_END(mkdtemp);
2194 const char* path = static_cast<const char*>(req_wrap_sync.req.path);
2195
2196 Local<Value> error;
2197 MaybeLocal<Value> rc =
2198 StringBytes::Encode(isolate, path, encoding, &error);
2199 if (rc.IsEmpty()) {
2200 Local<Object> ctx = args[3].As<Object>();
2201 ctx->Set(env->context(), env->error_string(), error).FromJust();
2202 return;
2203 }
2204 args.GetReturnValue().Set(rc.ToLocalChecked());
2205 }
2206 }
2207
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)2208 void Initialize(Local<Object> target,
2209 Local<Value> unused,
2210 Local<Context> context,
2211 void* priv) {
2212 Environment* env = Environment::GetCurrent(context);
2213 Isolate* isolate = env->isolate();
2214
2215 env->SetMethod(target, "access", Access);
2216 env->SetMethod(target, "close", Close);
2217 env->SetMethod(target, "open", Open);
2218 env->SetMethod(target, "openFileHandle", OpenFileHandle);
2219 env->SetMethod(target, "read", Read);
2220 env->SetMethod(target, "fdatasync", Fdatasync);
2221 env->SetMethod(target, "fsync", Fsync);
2222 env->SetMethod(target, "rename", Rename);
2223 env->SetMethod(target, "ftruncate", FTruncate);
2224 env->SetMethod(target, "rmdir", RMDir);
2225 env->SetMethod(target, "mkdir", MKDir);
2226 env->SetMethod(target, "readdir", ReadDir);
2227 env->SetMethod(target, "internalModuleReadJSON", InternalModuleReadJSON);
2228 env->SetMethod(target, "internalModuleStat", InternalModuleStat);
2229 env->SetMethod(target, "stat", Stat);
2230 env->SetMethod(target, "lstat", LStat);
2231 env->SetMethod(target, "fstat", FStat);
2232 env->SetMethod(target, "link", Link);
2233 env->SetMethod(target, "symlink", Symlink);
2234 env->SetMethod(target, "readlink", ReadLink);
2235 env->SetMethod(target, "unlink", Unlink);
2236 env->SetMethod(target, "writeBuffer", WriteBuffer);
2237 env->SetMethod(target, "writeBuffers", WriteBuffers);
2238 env->SetMethod(target, "writeString", WriteString);
2239 env->SetMethod(target, "realpath", RealPath);
2240 env->SetMethod(target, "copyFile", CopyFile);
2241
2242 env->SetMethod(target, "chmod", Chmod);
2243 env->SetMethod(target, "fchmod", FChmod);
2244 // env->SetMethod(target, "lchmod", LChmod);
2245
2246 env->SetMethod(target, "chown", Chown);
2247 env->SetMethod(target, "fchown", FChown);
2248 env->SetMethod(target, "lchown", LChown);
2249
2250 env->SetMethod(target, "utimes", UTimes);
2251 env->SetMethod(target, "futimes", FUTimes);
2252
2253 env->SetMethod(target, "mkdtemp", Mkdtemp);
2254
2255 target->Set(context,
2256 FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsLength"),
2257 Integer::New(isolate, env->kFsStatsFieldsLength))
2258 .FromJust();
2259
2260 target->Set(context,
2261 FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2262 env->fs_stats_field_array()->GetJSArray()).FromJust();
2263
2264 target->Set(context,
2265 FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2266 env->fs_stats_field_bigint_array()->GetJSArray()).FromJust();
2267
2268 StatWatcher::Initialize(env, target);
2269
2270 // Create FunctionTemplate for FSReqCallback
2271 Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqWrap);
2272 fst->InstanceTemplate()->SetInternalFieldCount(1);
2273 fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2274 Local<String> wrapString = FIXED_ONE_BYTE_STRING(isolate, "FSReqWrap");
2275 fst->SetClassName(wrapString);
2276 target
2277 ->Set(context, wrapString,
2278 fst->GetFunction(env->context()).ToLocalChecked())
2279 .FromJust();
2280
2281 // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2282 // to do anything in the constructor, so we only store the instance template.
2283 Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2284 fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
2285 fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2286 Local<String> fhWrapString =
2287 FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2288 fh_rw->SetClassName(fhWrapString);
2289 env->set_filehandlereadwrap_template(
2290 fst->InstanceTemplate());
2291
2292 // Create Function Template for FSReqPromise
2293 Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2294 fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2295 Local<String> promiseString =
2296 FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2297 fpt->SetClassName(promiseString);
2298 Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2299 fpo->SetInternalFieldCount(1);
2300 env->set_fsreqpromise_constructor_template(fpo);
2301
2302 // Create FunctionTemplate for FileHandle
2303 Local<FunctionTemplate> fd = env->NewFunctionTemplate(FileHandle::New);
2304 fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2305 env->SetProtoMethod(fd, "close", FileHandle::Close);
2306 env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
2307 Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2308 fdt->SetInternalFieldCount(1);
2309 Local<String> handleString =
2310 FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
2311 fd->SetClassName(handleString);
2312 StreamBase::AddMethods<FileHandle>(env, fd);
2313 target
2314 ->Set(context, handleString,
2315 fd->GetFunction(env->context()).ToLocalChecked())
2316 .FromJust();
2317 env->set_fd_constructor_template(fdt);
2318
2319 // Create FunctionTemplate for FileHandle::CloseReq
2320 Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2321 fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2322 "FileHandleCloseReq"));
2323 fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2324 Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2325 fdcloset->SetInternalFieldCount(1);
2326 env->set_fdclose_constructor_template(fdcloset);
2327
2328 Local<Symbol> use_promises_symbol =
2329 Symbol::New(isolate,
2330 FIXED_ONE_BYTE_STRING(isolate, "use promises"));
2331 env->set_fs_use_promises_symbol(use_promises_symbol);
2332 target->Set(context,
2333 FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2334 use_promises_symbol).FromJust();
2335 }
2336
2337 } // namespace fs
2338
2339 } // end namespace node
2340
2341 NODE_BUILTIN_MODULE_CONTEXT_AWARE(fs, node::fs::Initialize)
2342