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-inl.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::Undefined;
74 using v8::Value;
75
76 #ifndef S_ISDIR
77 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
78 #endif
79
80 #ifdef __POSIX__
81 constexpr char kPathSeparator = '/';
82 #else
83 const char* const kPathSeparator = "\\/";
84 #endif
85
Basename(const std::string & str,const std::string & extension)86 std::string Basename(const std::string& str, const std::string& extension) {
87 // Remove everything leading up to and including the final path separator.
88 std::string::size_type pos = str.find_last_of(kPathSeparator);
89
90 // Starting index for the resulting string
91 std::size_t start_pos = 0;
92 // String size to return
93 std::size_t str_size = str.size();
94 if (pos != std::string::npos) {
95 start_pos = pos + 1;
96 str_size -= start_pos;
97 }
98
99 // Strip away the extension, if any.
100 if (str_size >= extension.size() &&
101 str.compare(str.size() - extension.size(),
102 extension.size(), extension) == 0) {
103 str_size -= extension.size();
104 }
105
106 return str.substr(start_pos, str_size);
107 }
108
GetOffset(Local<Value> value)109 inline int64_t GetOffset(Local<Value> value) {
110 return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1;
111 }
112
get_fs_func_name_by_type(uv_fs_type req_type)113 static const char* get_fs_func_name_by_type(uv_fs_type req_type) {
114 switch (req_type) {
115 #define FS_TYPE_TO_NAME(type, name) \
116 case UV_FS_##type: \
117 return name;
118 FS_TYPE_TO_NAME(OPEN, "open")
119 FS_TYPE_TO_NAME(CLOSE, "close")
120 FS_TYPE_TO_NAME(READ, "read")
121 FS_TYPE_TO_NAME(WRITE, "write")
122 FS_TYPE_TO_NAME(SENDFILE, "sendfile")
123 FS_TYPE_TO_NAME(STAT, "stat")
124 FS_TYPE_TO_NAME(LSTAT, "lstat")
125 FS_TYPE_TO_NAME(FSTAT, "fstat")
126 FS_TYPE_TO_NAME(FTRUNCATE, "ftruncate")
127 FS_TYPE_TO_NAME(UTIME, "utime")
128 FS_TYPE_TO_NAME(FUTIME, "futime")
129 FS_TYPE_TO_NAME(ACCESS, "access")
130 FS_TYPE_TO_NAME(CHMOD, "chmod")
131 FS_TYPE_TO_NAME(FCHMOD, "fchmod")
132 FS_TYPE_TO_NAME(FSYNC, "fsync")
133 FS_TYPE_TO_NAME(FDATASYNC, "fdatasync")
134 FS_TYPE_TO_NAME(UNLINK, "unlink")
135 FS_TYPE_TO_NAME(RMDIR, "rmdir")
136 FS_TYPE_TO_NAME(MKDIR, "mkdir")
137 FS_TYPE_TO_NAME(MKDTEMP, "mkdtemp")
138 FS_TYPE_TO_NAME(RENAME, "rename")
139 FS_TYPE_TO_NAME(SCANDIR, "scandir")
140 FS_TYPE_TO_NAME(LINK, "link")
141 FS_TYPE_TO_NAME(SYMLINK, "symlink")
142 FS_TYPE_TO_NAME(READLINK, "readlink")
143 FS_TYPE_TO_NAME(CHOWN, "chown")
144 FS_TYPE_TO_NAME(FCHOWN, "fchown")
145 FS_TYPE_TO_NAME(REALPATH, "realpath")
146 FS_TYPE_TO_NAME(COPYFILE, "copyfile")
147 FS_TYPE_TO_NAME(LCHOWN, "lchown")
148 FS_TYPE_TO_NAME(STATFS, "statfs")
149 FS_TYPE_TO_NAME(MKSTEMP, "mkstemp")
150 FS_TYPE_TO_NAME(LUTIME, "lutime")
151 #undef FS_TYPE_TO_NAME
152 default:
153 return "unknow";
154 }
155 }
156
157 #define TRACE_NAME(name) "fs.sync." #name
158 #define GET_TRACE_ENABLED \
159 (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \
160 TRACING_CATEGORY_NODE2(fs, sync)) != 0)
161 #define FS_SYNC_TRACE_BEGIN(syscall, ...) \
162 if (GET_TRACE_ENABLED) \
163 TRACE_EVENT_BEGIN( \
164 TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
165 #define FS_SYNC_TRACE_END(syscall, ...) \
166 if (GET_TRACE_ENABLED) \
167 TRACE_EVENT_END( \
168 TRACING_CATEGORY_NODE2(fs, sync), TRACE_NAME(syscall), ##__VA_ARGS__);
169
170 #define FS_ASYNC_TRACE_BEGIN0(fs_type, id) \
171 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(TRACING_CATEGORY_NODE2(fs, async), \
172 get_fs_func_name_by_type(fs_type), \
173 id);
174
175 #define FS_ASYNC_TRACE_END0(fs_type, id) \
176 TRACE_EVENT_NESTABLE_ASYNC_END0(TRACING_CATEGORY_NODE2(fs, async), \
177 get_fs_func_name_by_type(fs_type), \
178 id);
179
180 #define FS_ASYNC_TRACE_BEGIN1(fs_type, id, name, value) \
181 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE2(fs, async), \
182 get_fs_func_name_by_type(fs_type), \
183 id, \
184 name, \
185 value);
186
187 #define FS_ASYNC_TRACE_END1(fs_type, id, name, value) \
188 TRACE_EVENT_NESTABLE_ASYNC_END1(TRACING_CATEGORY_NODE2(fs, async), \
189 get_fs_func_name_by_type(fs_type), \
190 id, \
191 name, \
192 value);
193
194 #define FS_ASYNC_TRACE_BEGIN2(fs_type, id, name1, value1, name2, value2) \
195 TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(TRACING_CATEGORY_NODE2(fs, async), \
196 get_fs_func_name_by_type(fs_type), \
197 id, \
198 name1, \
199 value1, \
200 name2, \
201 value2);
202
203 #define FS_ASYNC_TRACE_END2(fs_type, id, name1, value1, name2, value2) \
204 TRACE_EVENT_NESTABLE_ASYNC_END2(TRACING_CATEGORY_NODE2(fs, async), \
205 get_fs_func_name_by_type(fs_type), \
206 id, \
207 name1, \
208 value1, \
209 name2, \
210 value2);
211
212 // We sometimes need to convert a C++ lambda function to a raw C-style function.
213 // This is helpful, because ReqWrap::Dispatch() does not recognize lambda
214 // functions, and thus does not wrap them properly.
215 typedef void(*uv_fs_callback_t)(uv_fs_t*);
216
217
MemoryInfo(MemoryTracker * tracker) const218 void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const {
219 tracker->TrackField("paths", paths_);
220 }
221
222 FileHandleReadWrap::~FileHandleReadWrap() = default;
223
224 FSReqBase::~FSReqBase() = default;
225
MemoryInfo(MemoryTracker * tracker) const226 void FSReqBase::MemoryInfo(MemoryTracker* tracker) const {
227 tracker->TrackField("continuation_data", continuation_data_);
228 }
229
230 // The FileHandle object wraps a file descriptor and will close it on garbage
231 // collection if necessary. If that happens, a process warning will be
232 // emitted (or a fatal exception will occur if the fd cannot be closed.)
FileHandle(BindingData * binding_data,Local<Object> obj,int fd)233 FileHandle::FileHandle(BindingData* binding_data,
234 Local<Object> obj, int fd)
235 : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE),
236 StreamBase(env()),
237 fd_(fd),
238 binding_data_(binding_data) {
239 MakeWeak();
240 StreamBase::AttachToObject(GetObject());
241 }
242
New(BindingData * binding_data,int fd,Local<Object> obj)243 FileHandle* FileHandle::New(BindingData* binding_data,
244 int fd, Local<Object> obj) {
245 Environment* env = binding_data->env();
246 if (obj.IsEmpty() && !env->fd_constructor_template()
247 ->NewInstance(env->context())
248 .ToLocal(&obj)) {
249 return nullptr;
250 }
251 return new FileHandle(binding_data, obj, fd);
252 }
253
New(const FunctionCallbackInfo<Value> & args)254 void FileHandle::New(const FunctionCallbackInfo<Value>& args) {
255 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
256 Environment* env = binding_data->env();
257 CHECK(args.IsConstructCall());
258 CHECK(args[0]->IsInt32());
259
260 FileHandle* handle =
261 FileHandle::New(binding_data, args[0].As<Int32>()->Value(), args.This());
262 if (handle == nullptr) return;
263 if (args[1]->IsNumber())
264 handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust();
265 if (args[2]->IsNumber())
266 handle->read_length_ = args[2]->IntegerValue(env->context()).FromJust();
267 }
268
~FileHandle()269 FileHandle::~FileHandle() {
270 CHECK(!closing_); // We should not be deleting while explicitly closing!
271 Close(); // Close synchronously and emit warning
272 CHECK(closed_); // We have to be closed at the point
273 }
274
DoWrite(WriteWrap * w,uv_buf_t * bufs,size_t count,uv_stream_t * send_handle)275 int FileHandle::DoWrite(WriteWrap* w,
276 uv_buf_t* bufs,
277 size_t count,
278 uv_stream_t* send_handle) {
279 return UV_ENOSYS; // Not implemented (yet).
280 }
281
MemoryInfo(MemoryTracker * tracker) const282 void FileHandle::MemoryInfo(MemoryTracker* tracker) const {
283 tracker->TrackField("current_read", current_read_);
284 }
285
GetTransferMode() const286 FileHandle::TransferMode FileHandle::GetTransferMode() const {
287 return reading_ || closing_ || closed_ ?
288 TransferMode::kUntransferable : TransferMode::kTransferable;
289 }
290
TransferForMessaging()291 std::unique_ptr<worker::TransferData> FileHandle::TransferForMessaging() {
292 CHECK_NE(GetTransferMode(), TransferMode::kUntransferable);
293 auto ret = std::make_unique<TransferData>(fd_);
294 closed_ = true;
295 return ret;
296 }
297
TransferData(int fd)298 FileHandle::TransferData::TransferData(int fd) : fd_(fd) {}
299
~TransferData()300 FileHandle::TransferData::~TransferData() {
301 if (fd_ > 0) {
302 uv_fs_t close_req;
303 CHECK_NE(fd_, -1);
304 FS_SYNC_TRACE_BEGIN(close);
305 CHECK_EQ(0, uv_fs_close(nullptr, &close_req, fd_, nullptr));
306 FS_SYNC_TRACE_END(close);
307 uv_fs_req_cleanup(&close_req);
308 }
309 }
310
Deserialize(Environment * env,v8::Local<v8::Context> context,std::unique_ptr<worker::TransferData> self)311 BaseObjectPtr<BaseObject> FileHandle::TransferData::Deserialize(
312 Environment* env,
313 v8::Local<v8::Context> context,
314 std::unique_ptr<worker::TransferData> self) {
315 BindingData* bd = Realm::GetBindingData<BindingData>(context);
316 if (bd == nullptr) return {};
317
318 int fd = fd_;
319 fd_ = -1;
320 return BaseObjectPtr<BaseObject> { FileHandle::New(bd, fd) };
321 }
322
323 // Close the file descriptor if it hasn't already been closed. A process
324 // warning will be emitted using a SetImmediate to avoid calling back to
325 // JS during GC. If closing the fd fails at this point, a fatal exception
326 // will crash the process immediately.
Close()327 inline void FileHandle::Close() {
328 if (closed_ || closing_) return;
329 uv_fs_t req;
330 CHECK_NE(fd_, -1);
331 FS_SYNC_TRACE_BEGIN(close);
332 int ret = uv_fs_close(env()->event_loop(), &req, fd_, nullptr);
333 FS_SYNC_TRACE_END(close);
334 uv_fs_req_cleanup(&req);
335
336 struct err_detail { int ret; int fd; };
337
338 err_detail detail { ret, fd_ };
339
340 AfterClose();
341
342 if (ret < 0) {
343 // Do not unref this
344 env()->SetImmediate([detail](Environment* env) {
345 char msg[70];
346 snprintf(msg, arraysize(msg),
347 "Closing file descriptor %d on garbage collection failed",
348 detail.fd);
349 // This exception will end up being fatal for the process because
350 // it is being thrown from within the SetImmediate handler and
351 // there is no JS stack to bubble it to. In other words, tearing
352 // down the process is the only reasonable thing we can do here.
353 HandleScope handle_scope(env->isolate());
354 env->ThrowUVException(detail.ret, "close", msg);
355 });
356 return;
357 }
358
359 // If the close was successful, we still want to emit a process warning
360 // to notify that the file descriptor was gc'd. We want to be noisy about
361 // this because not explicitly closing the FileHandle is a bug.
362
363 env()->SetImmediate([detail](Environment* env) {
364 ProcessEmitWarning(env,
365 "Closing file descriptor %d on garbage collection",
366 detail.fd);
367 if (env->filehandle_close_warning()) {
368 env->set_filehandle_close_warning(false);
369 USE(ProcessEmitDeprecationWarning(
370 env,
371 "Closing a FileHandle object on garbage collection is deprecated. "
372 "Please close FileHandle objects explicitly using "
373 "FileHandle.prototype.close(). In the future, an error will be "
374 "thrown if a file descriptor is closed during garbage collection.",
375 "DEP0137"));
376 }
377 }, CallbackFlags::kUnrefed);
378 }
379
Resolve()380 void FileHandle::CloseReq::Resolve() {
381 Isolate* isolate = env()->isolate();
382 HandleScope scope(isolate);
383 Context::Scope context_scope(env()->context());
384 InternalCallbackScope callback_scope(this);
385 Local<Promise> promise = promise_.Get(isolate);
386 Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
387 resolver->Resolve(env()->context(), Undefined(isolate)).Check();
388 }
389
Reject(Local<Value> reason)390 void FileHandle::CloseReq::Reject(Local<Value> reason) {
391 Isolate* isolate = env()->isolate();
392 HandleScope scope(isolate);
393 Context::Scope context_scope(env()->context());
394 InternalCallbackScope callback_scope(this);
395 Local<Promise> promise = promise_.Get(isolate);
396 Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
397 resolver->Reject(env()->context(), reason).Check();
398 }
399
file_handle()400 FileHandle* FileHandle::CloseReq::file_handle() {
401 Isolate* isolate = env()->isolate();
402 HandleScope scope(isolate);
403 Local<Value> val = ref_.Get(isolate);
404 Local<Object> obj = val.As<Object>();
405 return Unwrap<FileHandle>(obj);
406 }
407
CloseReq(Environment * env,Local<Object> obj,Local<Promise> promise,Local<Value> ref)408 FileHandle::CloseReq::CloseReq(Environment* env,
409 Local<Object> obj,
410 Local<Promise> promise,
411 Local<Value> ref)
412 : ReqWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) {
413 promise_.Reset(env->isolate(), promise);
414 ref_.Reset(env->isolate(), ref);
415 }
416
~CloseReq()417 FileHandle::CloseReq::~CloseReq() {
418 uv_fs_req_cleanup(req());
419 promise_.Reset();
420 ref_.Reset();
421 }
422
MemoryInfo(MemoryTracker * tracker) const423 void FileHandle::CloseReq::MemoryInfo(MemoryTracker* tracker) const {
424 tracker->TrackField("promise", promise_);
425 tracker->TrackField("ref", ref_);
426 }
427
428
429
430 // Closes this FileHandle asynchronously and returns a Promise that will be
431 // resolved when the callback is invoked, or rejects with a UVException if
432 // there was a problem closing the fd. This is the preferred mechanism for
433 // closing the FD object even tho the object will attempt to close
434 // automatically on gc.
ClosePromise()435 MaybeLocal<Promise> FileHandle::ClosePromise() {
436 Isolate* isolate = env()->isolate();
437 EscapableHandleScope scope(isolate);
438 Local<Context> context = env()->context();
439
440 Local<Value> close_resolver =
441 object()->GetInternalField(FileHandle::kClosingPromiseSlot).As<Value>();
442 if (!close_resolver.IsEmpty() && !close_resolver->IsUndefined()) {
443 CHECK(close_resolver->IsPromise());
444 return close_resolver.As<Promise>();
445 }
446
447 CHECK(!closed_);
448 CHECK(!closing_);
449 CHECK(!reading_);
450
451 auto maybe_resolver = Promise::Resolver::New(context);
452 CHECK(!maybe_resolver.IsEmpty());
453 Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
454 Local<Promise> promise = resolver.As<Promise>();
455
456 Local<Object> close_req_obj;
457 if (!env()->fdclose_constructor_template()
458 ->NewInstance(env()->context()).ToLocal(&close_req_obj)) {
459 return MaybeLocal<Promise>();
460 }
461 closing_ = true;
462 object()->SetInternalField(FileHandle::kClosingPromiseSlot, promise);
463
464 CloseReq* req = new CloseReq(env(), close_req_obj, promise, object());
465 auto AfterClose = uv_fs_callback_t{[](uv_fs_t* req) {
466 CloseReq* req_wrap = CloseReq::from_req(req);
467 FS_ASYNC_TRACE_END1(
468 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
469 BaseObjectPtr<CloseReq> close(req_wrap);
470 CHECK(close);
471 close->file_handle()->AfterClose();
472 if (!close->env()->can_call_into_js()) return;
473 Isolate* isolate = close->env()->isolate();
474 if (req->result < 0) {
475 HandleScope handle_scope(isolate);
476 close->Reject(
477 UVException(isolate, static_cast<int>(req->result), "close"));
478 } else {
479 close->Resolve();
480 }
481 }};
482 CHECK_NE(fd_, -1);
483 FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, req)
484 int ret = req->Dispatch(uv_fs_close, fd_, AfterClose);
485 if (ret < 0) {
486 req->Reject(UVException(isolate, ret, "close"));
487 delete req;
488 }
489
490 return scope.Escape(promise);
491 }
492
Close(const FunctionCallbackInfo<Value> & args)493 void FileHandle::Close(const FunctionCallbackInfo<Value>& args) {
494 FileHandle* fd;
495 ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
496 Local<Promise> ret;
497 if (!fd->ClosePromise().ToLocal(&ret)) return;
498 args.GetReturnValue().Set(ret);
499 }
500
501
ReleaseFD(const FunctionCallbackInfo<Value> & args)502 void FileHandle::ReleaseFD(const FunctionCallbackInfo<Value>& args) {
503 FileHandle* fd;
504 ASSIGN_OR_RETURN_UNWRAP(&fd, args.Holder());
505 // Just act as if this FileHandle has been closed.
506 fd->AfterClose();
507 }
508
509
AfterClose()510 void FileHandle::AfterClose() {
511 closing_ = false;
512 closed_ = true;
513 fd_ = -1;
514 if (reading_ && !persistent().IsEmpty())
515 EmitRead(UV_EOF);
516 }
517
MemoryInfo(MemoryTracker * tracker) const518 void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const {
519 tracker->TrackField("buffer", buffer_);
520 tracker->TrackField("file_handle", this->file_handle_);
521 }
522
FileHandleReadWrap(FileHandle * handle,Local<Object> obj)523 FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj)
524 : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK),
525 file_handle_(handle) {}
526
ReadStart()527 int FileHandle::ReadStart() {
528 if (!IsAlive() || IsClosing())
529 return UV_EOF;
530
531 reading_ = true;
532
533 if (current_read_)
534 return 0;
535
536 BaseObjectPtr<FileHandleReadWrap> read_wrap;
537
538 if (read_length_ == 0) {
539 EmitRead(UV_EOF);
540 return 0;
541 }
542
543 {
544 // Create a new FileHandleReadWrap or re-use one.
545 // Either way, we need these two scopes for AsyncReset() or otherwise
546 // for creating the new instance.
547 HandleScope handle_scope(env()->isolate());
548 AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this);
549
550 auto& freelist = binding_data_->file_handle_read_wrap_freelist;
551 if (freelist.size() > 0) {
552 read_wrap = std::move(freelist.back());
553 freelist.pop_back();
554 // Use a fresh async resource.
555 // Lifetime is ensured via AsyncWrap::resource_.
556 Local<Object> resource = Object::New(env()->isolate());
557 USE(resource->Set(
558 env()->context(), env()->handle_string(), read_wrap->object()));
559 read_wrap->AsyncReset(resource);
560 read_wrap->file_handle_ = this;
561 } else {
562 Local<Object> wrap_obj;
563 if (!env()
564 ->filehandlereadwrap_template()
565 ->NewInstance(env()->context())
566 .ToLocal(&wrap_obj)) {
567 return UV_EBUSY;
568 }
569 read_wrap = MakeDetachedBaseObject<FileHandleReadWrap>(this, wrap_obj);
570 }
571 }
572 int64_t recommended_read = 65536;
573 if (read_length_ >= 0 && read_length_ <= recommended_read)
574 recommended_read = read_length_;
575
576 read_wrap->buffer_ = EmitAlloc(recommended_read);
577
578 current_read_ = std::move(read_wrap);
579 FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, current_read_.get())
580 current_read_->Dispatch(uv_fs_read,
581 fd_,
582 ¤t_read_->buffer_,
583 1,
584 read_offset_,
585 uv_fs_callback_t{[](uv_fs_t* req) {
586 FileHandle* handle;
587 {
588 FileHandleReadWrap* req_wrap = FileHandleReadWrap::from_req(req);
589 FS_ASYNC_TRACE_END1(
590 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
591 handle = req_wrap->file_handle_;
592 CHECK_EQ(handle->current_read_.get(), req_wrap);
593 }
594
595 // ReadStart() checks whether current_read_ is set to determine whether
596 // a read is in progress. Moving it into a local variable makes sure that
597 // the ReadStart() call below doesn't think we're still actively reading.
598 BaseObjectPtr<FileHandleReadWrap> read_wrap =
599 std::move(handle->current_read_);
600
601 ssize_t result = req->result;
602 uv_buf_t buffer = read_wrap->buffer_;
603
604 uv_fs_req_cleanup(req);
605
606 // Push the read wrap back to the freelist, or let it be destroyed
607 // once we’re exiting the current scope.
608 constexpr size_t kWantedFreelistFill = 100;
609 auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist;
610 if (freelist.size() < kWantedFreelistFill) {
611 read_wrap->Reset();
612 freelist.emplace_back(std::move(read_wrap));
613 }
614
615 if (result >= 0) {
616 // Read at most as many bytes as we originally planned to.
617 if (handle->read_length_ >= 0 && handle->read_length_ < result)
618 result = handle->read_length_;
619
620 // If we read data and we have an expected length, decrease it by
621 // how much we have read.
622 if (handle->read_length_ >= 0)
623 handle->read_length_ -= result;
624
625 // If we have an offset, increase it by how much we have read.
626 if (handle->read_offset_ >= 0)
627 handle->read_offset_ += result;
628 }
629
630 // Reading 0 bytes from a file always means EOF, or that we reached
631 // the end of the requested range.
632 if (result == 0)
633 result = UV_EOF;
634
635 handle->EmitRead(result, buffer);
636
637 // Start over, if EmitRead() didn’t tell us to stop.
638 if (handle->reading_)
639 handle->ReadStart();
640 }});
641
642 return 0;
643 }
644
ReadStop()645 int FileHandle::ReadStop() {
646 reading_ = false;
647 return 0;
648 }
649
650 typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap;
651
CreateShutdownWrap(Local<Object> object)652 ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) {
653 return new FileHandleCloseWrap(this, object);
654 }
655
DoShutdown(ShutdownWrap * req_wrap)656 int FileHandle::DoShutdown(ShutdownWrap* req_wrap) {
657 if (closing_ || closed_) {
658 req_wrap->Done(0);
659 return 1;
660 }
661 FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(req_wrap);
662 closing_ = true;
663 CHECK_NE(fd_, -1);
664 FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, wrap)
665 wrap->Dispatch(uv_fs_close, fd_, uv_fs_callback_t{[](uv_fs_t* req) {
666 FileHandleCloseWrap* wrap = static_cast<FileHandleCloseWrap*>(
667 FileHandleCloseWrap::from_req(req));
668 FS_ASYNC_TRACE_END1(
669 req->fs_type, wrap, "result", static_cast<int>(req->result))
670 FileHandle* handle = static_cast<FileHandle*>(wrap->stream());
671 handle->AfterClose();
672
673 int result = static_cast<int>(req->result);
674 uv_fs_req_cleanup(req);
675 wrap->Done(result);
676 }});
677
678 return 0;
679 }
680
681
Reject(Local<Value> reject)682 void FSReqCallback::Reject(Local<Value> reject) {
683 MakeCallback(env()->oncomplete_string(), 1, &reject);
684 }
685
ResolveStat(const uv_stat_t * stat)686 void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
687 Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat));
688 }
689
ResolveStatFs(const uv_statfs_t * stat)690 void FSReqCallback::ResolveStatFs(const uv_statfs_t* stat) {
691 Resolve(FillGlobalStatFsArray(binding_data(), use_bigint(), stat));
692 }
693
Resolve(Local<Value> value)694 void FSReqCallback::Resolve(Local<Value> value) {
695 Local<Value> argv[2] {
696 Null(env()->isolate()),
697 value
698 };
699 MakeCallback(env()->oncomplete_string(),
700 value->IsUndefined() ? 1 : arraysize(argv),
701 argv);
702 }
703
SetReturnValue(const FunctionCallbackInfo<Value> & args)704 void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
705 args.GetReturnValue().SetUndefined();
706 }
707
NewFSReqCallback(const FunctionCallbackInfo<Value> & args)708 void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
709 CHECK(args.IsConstructCall());
710 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
711 new FSReqCallback(binding_data, args.This(), args[0]->IsTrue());
712 }
713
FSReqAfterScope(FSReqBase * wrap,uv_fs_t * req)714 FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req)
715 : wrap_(wrap),
716 req_(req),
717 handle_scope_(wrap->env()->isolate()),
718 context_scope_(wrap->env()->context()) {
719 CHECK_EQ(wrap_->req(), req);
720 }
721
~FSReqAfterScope()722 FSReqAfterScope::~FSReqAfterScope() {
723 Clear();
724 }
725
Clear()726 void FSReqAfterScope::Clear() {
727 if (!wrap_) return;
728
729 uv_fs_req_cleanup(wrap_->req());
730 wrap_->Detach();
731 wrap_.reset();
732 }
733
734 // TODO(joyeecheung): create a normal context object, and
735 // construct the actual errors in the JS land using the context.
736 // The context should include fds for some fs APIs, currently they are
737 // missing in the error messages. The path, dest, syscall, fd, .etc
738 // can be put into the context before the binding is even invoked,
739 // the only information that has to come from the C++ layer is the
740 // error number (and possibly the syscall for abstraction),
741 // which is also why the errors should have been constructed
742 // in JS for more flexibility.
Reject(uv_fs_t * req)743 void FSReqAfterScope::Reject(uv_fs_t* req) {
744 BaseObjectPtr<FSReqBase> wrap { wrap_ };
745 Local<Value> exception = UVException(wrap_->env()->isolate(),
746 static_cast<int>(req->result),
747 wrap_->syscall(),
748 nullptr,
749 req->path,
750 wrap_->data());
751 Clear();
752 wrap->Reject(exception);
753 }
754
Proceed()755 bool FSReqAfterScope::Proceed() {
756 if (!wrap_->env()->can_call_into_js()) {
757 return false;
758 }
759
760 if (req_->result < 0) {
761 Reject(req_);
762 return false;
763 }
764 return true;
765 }
766
AfterNoArgs(uv_fs_t * req)767 void AfterNoArgs(uv_fs_t* req) {
768 FSReqBase* req_wrap = FSReqBase::from_req(req);
769 FSReqAfterScope after(req_wrap, req);
770 FS_ASYNC_TRACE_END1(
771 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
772 if (after.Proceed())
773 req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
774 }
775
AfterStat(uv_fs_t * req)776 void AfterStat(uv_fs_t* req) {
777 FSReqBase* req_wrap = FSReqBase::from_req(req);
778 FSReqAfterScope after(req_wrap, req);
779 FS_ASYNC_TRACE_END1(
780 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
781 if (after.Proceed()) {
782 req_wrap->ResolveStat(&req->statbuf);
783 }
784 }
785
AfterStatFs(uv_fs_t * req)786 void AfterStatFs(uv_fs_t* req) {
787 FSReqBase* req_wrap = FSReqBase::from_req(req);
788 FSReqAfterScope after(req_wrap, req);
789 FS_ASYNC_TRACE_END1(
790 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
791 if (after.Proceed()) {
792 req_wrap->ResolveStatFs(static_cast<uv_statfs_t*>(req->ptr));
793 }
794 }
795
AfterInteger(uv_fs_t * req)796 void AfterInteger(uv_fs_t* req) {
797 FSReqBase* req_wrap = FSReqBase::from_req(req);
798 FSReqAfterScope after(req_wrap, req);
799 FS_ASYNC_TRACE_END1(
800 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
801 int result = static_cast<int>(req->result);
802 if (result >= 0 && req_wrap->is_plain_open())
803 req_wrap->env()->AddUnmanagedFd(result);
804
805 if (after.Proceed())
806 req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), result));
807 }
808
AfterOpenFileHandle(uv_fs_t * req)809 void AfterOpenFileHandle(uv_fs_t* req) {
810 FSReqBase* req_wrap = FSReqBase::from_req(req);
811 FSReqAfterScope after(req_wrap, req);
812 FS_ASYNC_TRACE_END1(
813 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
814 if (after.Proceed()) {
815 FileHandle* fd = FileHandle::New(req_wrap->binding_data(),
816 static_cast<int>(req->result));
817 if (fd == nullptr) return;
818 req_wrap->Resolve(fd->object());
819 }
820 }
821
822 // Reverse the logic applied by path.toNamespacedPath() to create a
823 // namespace-prefixed path.
FromNamespacedPath(std::string * path)824 void FromNamespacedPath(std::string* path) {
825 #ifdef _WIN32
826 if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
827 *path = path->substr(8);
828 path->insert(0, "\\\\");
829 } else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
830 *path = path->substr(4);
831 }
832 #endif
833 }
834
AfterMkdirp(uv_fs_t * req)835 void AfterMkdirp(uv_fs_t* req) {
836 FSReqBase* req_wrap = FSReqBase::from_req(req);
837 FSReqAfterScope after(req_wrap, req);
838 FS_ASYNC_TRACE_END1(
839 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
840 if (after.Proceed()) {
841 std::string first_path(req_wrap->continuation_data()->first_path());
842 if (first_path.empty())
843 return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
844 FromNamespacedPath(&first_path);
845 Local<Value> path;
846 Local<Value> error;
847 if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
848 req_wrap->encoding(),
849 &error).ToLocal(&path)) {
850 return req_wrap->Reject(error);
851 }
852 return req_wrap->Resolve(path);
853 }
854 }
855
AfterStringPath(uv_fs_t * req)856 void AfterStringPath(uv_fs_t* req) {
857 FSReqBase* req_wrap = FSReqBase::from_req(req);
858 FSReqAfterScope after(req_wrap, req);
859 FS_ASYNC_TRACE_END1(
860 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
861 MaybeLocal<Value> link;
862 Local<Value> error;
863
864 if (after.Proceed()) {
865 link = StringBytes::Encode(req_wrap->env()->isolate(),
866 req->path,
867 req_wrap->encoding(),
868 &error);
869 if (link.IsEmpty())
870 req_wrap->Reject(error);
871 else
872 req_wrap->Resolve(link.ToLocalChecked());
873 }
874 }
875
AfterStringPtr(uv_fs_t * req)876 void AfterStringPtr(uv_fs_t* req) {
877 FSReqBase* req_wrap = FSReqBase::from_req(req);
878 FSReqAfterScope after(req_wrap, req);
879 FS_ASYNC_TRACE_END1(
880 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
881 MaybeLocal<Value> link;
882 Local<Value> error;
883
884 if (after.Proceed()) {
885 link = StringBytes::Encode(req_wrap->env()->isolate(),
886 static_cast<const char*>(req->ptr),
887 req_wrap->encoding(),
888 &error);
889 if (link.IsEmpty())
890 req_wrap->Reject(error);
891 else
892 req_wrap->Resolve(link.ToLocalChecked());
893 }
894 }
895
AfterScanDir(uv_fs_t * req)896 void AfterScanDir(uv_fs_t* req) {
897 FSReqBase* req_wrap = FSReqBase::from_req(req);
898 FSReqAfterScope after(req_wrap, req);
899 FS_ASYNC_TRACE_END1(
900 req->fs_type, req_wrap, "result", static_cast<int>(req->result))
901 if (!after.Proceed()) {
902 return;
903 }
904
905 Environment* env = req_wrap->env();
906 Isolate* isolate = env->isolate();
907 Local<Value> error;
908 int r;
909
910 std::vector<Local<Value>> name_v;
911 std::vector<Local<Value>> type_v;
912
913 const bool with_file_types = req_wrap->with_file_types();
914
915 for (;;) {
916 uv_dirent_t ent;
917
918 r = uv_fs_scandir_next(req, &ent);
919 if (r == UV_EOF)
920 break;
921 if (r != 0) {
922 return req_wrap->Reject(
923 UVException(isolate, r, nullptr, req_wrap->syscall(), req->path));
924 }
925
926 Local<Value> filename;
927 if (!StringBytes::Encode(isolate, ent.name, req_wrap->encoding(), &error)
928 .ToLocal(&filename)) {
929 return req_wrap->Reject(error);
930 }
931 name_v.push_back(filename);
932
933 if (with_file_types) type_v.emplace_back(Integer::New(isolate, ent.type));
934 }
935
936 if (with_file_types) {
937 Local<Value> result[] = {Array::New(isolate, name_v.data(), name_v.size()),
938 Array::New(isolate, type_v.data(), type_v.size())};
939 req_wrap->Resolve(Array::New(isolate, result, arraysize(result)));
940 } else {
941 req_wrap->Resolve(Array::New(isolate, name_v.data(), name_v.size()));
942 }
943 }
944
Access(const FunctionCallbackInfo<Value> & args)945 void Access(const FunctionCallbackInfo<Value>& args) {
946 Environment* env = Environment::GetCurrent(args);
947 Isolate* isolate = env->isolate();
948 HandleScope scope(isolate);
949
950 const int argc = args.Length();
951 CHECK_GE(argc, 2);
952
953 CHECK(args[1]->IsInt32());
954 int mode = args[1].As<Int32>()->Value();
955
956 BufferValue path(isolate, args[0]);
957 CHECK_NOT_NULL(*path);
958
959 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
960 if (req_wrap_async != nullptr) { // access(path, mode, req)
961 FS_ASYNC_TRACE_BEGIN1(
962 UV_FS_ACCESS, req_wrap_async, "path", TRACE_STR_COPY(*path))
963 AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs,
964 uv_fs_access, *path, mode);
965 } else { // access(path, mode, undefined, ctx)
966 CHECK_EQ(argc, 4);
967 FSReqWrapSync req_wrap_sync;
968 FS_SYNC_TRACE_BEGIN(access);
969 SyncCall(env, args[3], &req_wrap_sync, "access", uv_fs_access, *path, mode);
970 FS_SYNC_TRACE_END(access);
971 }
972 }
973
974
Close(const FunctionCallbackInfo<Value> & args)975 void Close(const FunctionCallbackInfo<Value>& args) {
976 Environment* env = Environment::GetCurrent(args);
977
978 const int argc = args.Length();
979 CHECK_GE(argc, 2);
980
981 CHECK(args[0]->IsInt32());
982 int fd = args[0].As<Int32>()->Value();
983 env->RemoveUnmanagedFd(fd);
984
985 FSReqBase* req_wrap_async = GetReqWrap(args, 1);
986 if (req_wrap_async != nullptr) { // close(fd, req)
987 FS_ASYNC_TRACE_BEGIN0(UV_FS_CLOSE, req_wrap_async)
988 AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs,
989 uv_fs_close, fd);
990 } else { // close(fd, undefined, ctx)
991 CHECK_EQ(argc, 3);
992 FSReqWrapSync req_wrap_sync;
993 FS_SYNC_TRACE_BEGIN(close);
994 SyncCall(env, args[2], &req_wrap_sync, "close", uv_fs_close, fd);
995 FS_SYNC_TRACE_END(close);
996 }
997 }
998
999
1000 // Used to speed up module loading. Returns an array [string, boolean]
InternalModuleReadJSON(const FunctionCallbackInfo<Value> & args)1001 static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
1002 Environment* env = Environment::GetCurrent(args);
1003 Isolate* isolate = env->isolate();
1004 uv_loop_t* loop = env->event_loop();
1005
1006 CHECK(args[0]->IsString());
1007 node::Utf8Value path(isolate, args[0]);
1008
1009 if (strlen(*path) != path.length()) {
1010 args.GetReturnValue().Set(Array::New(isolate));
1011 return; // Contains a nul byte.
1012 }
1013 uv_fs_t open_req;
1014 const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
1015 uv_fs_req_cleanup(&open_req);
1016
1017 if (fd < 0) {
1018 args.GetReturnValue().Set(Array::New(isolate));
1019 return;
1020 }
1021
1022 auto defer_close = OnScopeLeave([fd, loop]() {
1023 uv_fs_t close_req;
1024 CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
1025 uv_fs_req_cleanup(&close_req);
1026 });
1027
1028 const size_t kBlockSize = 32 << 10;
1029 std::vector<char> chars;
1030 int64_t offset = 0;
1031 ssize_t numchars;
1032 do {
1033 const size_t start = chars.size();
1034 chars.resize(start + kBlockSize);
1035
1036 uv_buf_t buf;
1037 buf.base = &chars[start];
1038 buf.len = kBlockSize;
1039
1040 uv_fs_t read_req;
1041 numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
1042 uv_fs_req_cleanup(&read_req);
1043
1044 if (numchars < 0) {
1045 args.GetReturnValue().Set(Array::New(isolate));
1046 return;
1047 }
1048 offset += numchars;
1049 } while (static_cast<size_t>(numchars) == kBlockSize);
1050
1051 size_t start = 0;
1052 if (offset >= 3 && 0 == memcmp(chars.data(), "\xEF\xBB\xBF", 3)) {
1053 start = 3; // Skip UTF-8 BOM.
1054 }
1055 const size_t size = offset - start;
1056
1057 // TODO(anonrig): Follow-up on removing the following changes for AIX.
1058 char* p = &chars[start];
1059 char* pe = &chars[size];
1060 char* pos[2];
1061 char** ppos = &pos[0];
1062
1063 while (p < pe) {
1064 char c = *p++;
1065 if (c == '\\' && p < pe && *p == '"') p++;
1066 if (c != '"') continue;
1067 *ppos++ = p;
1068 if (ppos < &pos[2]) continue;
1069 ppos = &pos[0];
1070
1071 char* s = &pos[0][0];
1072 char* se = &pos[1][-1]; // Exclude quote.
1073 size_t n = se - s;
1074
1075 if (n == 4) {
1076 if (0 == memcmp(s, "main", 4)) break;
1077 if (0 == memcmp(s, "name", 4)) break;
1078 if (0 == memcmp(s, "type", 4)) break;
1079 } else if (n == 7) {
1080 if (0 == memcmp(s, "exports", 7)) break;
1081 if (0 == memcmp(s, "imports", 7)) break;
1082 }
1083 }
1084
1085 Local<Value> return_value[] = {
1086 String::NewFromUtf8(
1087 isolate, &chars[start], v8::NewStringType::kNormal, size)
1088 .ToLocalChecked(),
1089 Boolean::New(isolate, p < pe ? true : false)};
1090
1091 args.GetReturnValue().Set(
1092 Array::New(isolate, return_value, arraysize(return_value)));
1093 }
1094
1095 // Used to speed up module loading. Returns 0 if the path refers to
1096 // a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
1097 // The speedup comes from not creating thousands of Stat and Error objects.
InternalModuleStat(const FunctionCallbackInfo<Value> & args)1098 static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
1099 Environment* env = Environment::GetCurrent(args);
1100
1101 CHECK(args[0]->IsString());
1102 node::Utf8Value path(env->isolate(), args[0]);
1103
1104 uv_fs_t req;
1105 int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
1106 if (rc == 0) {
1107 const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
1108 rc = !!(s->st_mode & S_IFDIR);
1109 }
1110 uv_fs_req_cleanup(&req);
1111
1112 args.GetReturnValue().Set(rc);
1113 }
1114
Stat(const FunctionCallbackInfo<Value> & args)1115 static void Stat(const FunctionCallbackInfo<Value>& args) {
1116 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
1117 Environment* env = binding_data->env();
1118
1119 const int argc = args.Length();
1120 CHECK_GE(argc, 2);
1121
1122 BufferValue path(env->isolate(), args[0]);
1123 CHECK_NOT_NULL(*path);
1124
1125 bool use_bigint = args[1]->IsTrue();
1126 FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1127 if (req_wrap_async != nullptr) { // stat(path, use_bigint, req)
1128 FS_ASYNC_TRACE_BEGIN1(
1129 UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1130 AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1131 uv_fs_stat, *path);
1132 } else { // stat(path, use_bigint, undefined, ctx)
1133 CHECK_EQ(argc, 4);
1134 FSReqWrapSync req_wrap_sync;
1135 FS_SYNC_TRACE_BEGIN(stat);
1136 int err = SyncCall(env, args[3], &req_wrap_sync, "stat", uv_fs_stat, *path);
1137 FS_SYNC_TRACE_END(stat);
1138 if (err != 0) {
1139 return; // error info is in ctx
1140 }
1141
1142 Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1143 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1144 args.GetReturnValue().Set(arr);
1145 }
1146 }
1147
LStat(const FunctionCallbackInfo<Value> & args)1148 static void LStat(const FunctionCallbackInfo<Value>& args) {
1149 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
1150 Environment* env = binding_data->env();
1151
1152 const int argc = args.Length();
1153 CHECK_GE(argc, 3);
1154
1155 BufferValue path(env->isolate(), args[0]);
1156 CHECK_NOT_NULL(*path);
1157
1158 bool use_bigint = args[1]->IsTrue();
1159 FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1160 if (req_wrap_async != nullptr) { // lstat(path, use_bigint, req)
1161 FS_ASYNC_TRACE_BEGIN1(
1162 UV_FS_LSTAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1163 AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat,
1164 uv_fs_lstat, *path);
1165 } else { // lstat(path, use_bigint, undefined, ctx)
1166 CHECK_EQ(argc, 4);
1167 FSReqWrapSync req_wrap_sync;
1168 FS_SYNC_TRACE_BEGIN(lstat);
1169 int err = SyncCall(env, args[3], &req_wrap_sync, "lstat", uv_fs_lstat,
1170 *path);
1171 FS_SYNC_TRACE_END(lstat);
1172 if (err != 0) {
1173 return; // error info is in ctx
1174 }
1175
1176 Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1177 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1178 args.GetReturnValue().Set(arr);
1179 }
1180 }
1181
FStat(const FunctionCallbackInfo<Value> & args)1182 static void FStat(const FunctionCallbackInfo<Value>& args) {
1183 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
1184 Environment* env = binding_data->env();
1185
1186 const int argc = args.Length();
1187 CHECK_GE(argc, 2);
1188
1189 CHECK(args[0]->IsInt32());
1190 int fd = args[0].As<Int32>()->Value();
1191
1192 bool use_bigint = args[1]->IsTrue();
1193 FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1194 if (req_wrap_async != nullptr) { // fstat(fd, use_bigint, req)
1195 FS_ASYNC_TRACE_BEGIN0(UV_FS_FSTAT, req_wrap_async)
1196 AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat,
1197 uv_fs_fstat, fd);
1198 } else { // fstat(fd, use_bigint, undefined, ctx)
1199 CHECK_EQ(argc, 4);
1200 FSReqWrapSync req_wrap_sync;
1201 FS_SYNC_TRACE_BEGIN(fstat);
1202 int err = SyncCall(env, args[3], &req_wrap_sync, "fstat", uv_fs_fstat, fd);
1203 FS_SYNC_TRACE_END(fstat);
1204 if (err != 0) {
1205 return; // error info is in ctx
1206 }
1207
1208 Local<Value> arr = FillGlobalStatsArray(binding_data, use_bigint,
1209 static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
1210 args.GetReturnValue().Set(arr);
1211 }
1212 }
1213
StatFs(const FunctionCallbackInfo<Value> & args)1214 static void StatFs(const FunctionCallbackInfo<Value>& args) {
1215 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
1216 Environment* env = binding_data->env();
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 bool use_bigint = args[1]->IsTrue();
1225 FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
1226 if (req_wrap_async != nullptr) { // statfs(path, use_bigint, req)
1227 FS_ASYNC_TRACE_BEGIN1(
1228 UV_FS_STATFS, req_wrap_async, "path", TRACE_STR_COPY(*path))
1229 AsyncCall(env,
1230 req_wrap_async,
1231 args,
1232 "statfs",
1233 UTF8,
1234 AfterStatFs,
1235 uv_fs_statfs,
1236 *path);
1237 } else { // statfs(path, use_bigint, undefined, ctx)
1238 CHECK_EQ(argc, 4);
1239 FSReqWrapSync req_wrap_sync;
1240 FS_SYNC_TRACE_BEGIN(statfs);
1241 int err =
1242 SyncCall(env, args[3], &req_wrap_sync, "statfs", uv_fs_statfs, *path);
1243 FS_SYNC_TRACE_END(statfs);
1244 if (err != 0) {
1245 return; // error info is in ctx
1246 }
1247
1248 Local<Value> arr = FillGlobalStatFsArray(
1249 binding_data,
1250 use_bigint,
1251 static_cast<const uv_statfs_t*>(req_wrap_sync.req.ptr));
1252 args.GetReturnValue().Set(arr);
1253 }
1254 }
1255
Symlink(const FunctionCallbackInfo<Value> & args)1256 static void Symlink(const FunctionCallbackInfo<Value>& args) {
1257 Environment* env = Environment::GetCurrent(args);
1258 Isolate* isolate = env->isolate();
1259
1260 const int argc = args.Length();
1261 CHECK_GE(argc, 4);
1262
1263 BufferValue target(isolate, args[0]);
1264 CHECK_NOT_NULL(*target);
1265 BufferValue path(isolate, args[1]);
1266 CHECK_NOT_NULL(*path);
1267
1268 CHECK(args[2]->IsInt32());
1269 int flags = args[2].As<Int32>()->Value();
1270
1271 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1272 if (req_wrap_async != nullptr) { // symlink(target, path, flags, req)
1273 FS_ASYNC_TRACE_BEGIN2(UV_FS_SYMLINK,
1274 req_wrap_async,
1275 "target",
1276 TRACE_STR_COPY(*target),
1277 "path",
1278 TRACE_STR_COPY(*path))
1279 AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(),
1280 UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags);
1281 } else { // symlink(target, path, flags, undefined, ctx)
1282 CHECK_EQ(argc, 5);
1283 FSReqWrapSync req_wrap_sync;
1284 FS_SYNC_TRACE_BEGIN(symlink);
1285 SyncCall(env, args[4], &req_wrap_sync, "symlink",
1286 uv_fs_symlink, *target, *path, flags);
1287 FS_SYNC_TRACE_END(symlink);
1288 }
1289 }
1290
Link(const FunctionCallbackInfo<Value> & args)1291 static void Link(const FunctionCallbackInfo<Value>& args) {
1292 Environment* env = Environment::GetCurrent(args);
1293 Isolate* isolate = env->isolate();
1294
1295 const int argc = args.Length();
1296 CHECK_GE(argc, 3);
1297
1298 BufferValue src(isolate, args[0]);
1299 CHECK_NOT_NULL(*src);
1300
1301 BufferValue dest(isolate, args[1]);
1302 CHECK_NOT_NULL(*dest);
1303
1304 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1305 if (req_wrap_async != nullptr) { // link(src, dest, req)
1306 FS_ASYNC_TRACE_BEGIN2(UV_FS_LINK,
1307 req_wrap_async,
1308 "src",
1309 TRACE_STR_COPY(*src),
1310 "dest",
1311 TRACE_STR_COPY(*dest))
1312 AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8,
1313 AfterNoArgs, uv_fs_link, *src, *dest);
1314 } else { // link(src, dest)
1315 CHECK_EQ(argc, 4);
1316 FSReqWrapSync req_wrap_sync;
1317 FS_SYNC_TRACE_BEGIN(link);
1318 SyncCall(env, args[3], &req_wrap_sync, "link",
1319 uv_fs_link, *src, *dest);
1320 FS_SYNC_TRACE_END(link);
1321 }
1322 }
1323
ReadLink(const FunctionCallbackInfo<Value> & args)1324 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
1325 Environment* env = Environment::GetCurrent(args);
1326 Isolate* isolate = env->isolate();
1327
1328 const int argc = args.Length();
1329 CHECK_GE(argc, 3);
1330
1331 BufferValue path(isolate, args[0]);
1332 CHECK_NOT_NULL(*path);
1333
1334 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1335
1336 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1337 if (req_wrap_async != nullptr) { // readlink(path, encoding, req)
1338 FS_ASYNC_TRACE_BEGIN1(
1339 UV_FS_READLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1340 AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr,
1341 uv_fs_readlink, *path);
1342 } else {
1343 CHECK_EQ(argc, 4);
1344 FSReqWrapSync req_wrap_sync;
1345 FS_SYNC_TRACE_BEGIN(readlink);
1346 int err = SyncCall(env, args[3], &req_wrap_sync, "readlink",
1347 uv_fs_readlink, *path);
1348 FS_SYNC_TRACE_END(readlink);
1349 if (err < 0) {
1350 return; // syscall failed, no need to continue, error info is in ctx
1351 }
1352 const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1353
1354 Local<Value> error;
1355 MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1356 link_path,
1357 encoding,
1358 &error);
1359 if (rc.IsEmpty()) {
1360 Local<Object> ctx = args[3].As<Object>();
1361 ctx->Set(env->context(), env->error_string(), error).Check();
1362 return;
1363 }
1364
1365 args.GetReturnValue().Set(rc.ToLocalChecked());
1366 }
1367 }
1368
Rename(const FunctionCallbackInfo<Value> & args)1369 static void Rename(const FunctionCallbackInfo<Value>& args) {
1370 Environment* env = Environment::GetCurrent(args);
1371 Isolate* isolate = env->isolate();
1372
1373 const int argc = args.Length();
1374 CHECK_GE(argc, 3);
1375
1376 BufferValue old_path(isolate, args[0]);
1377 CHECK_NOT_NULL(*old_path);
1378 BufferValue new_path(isolate, args[1]);
1379 CHECK_NOT_NULL(*new_path);
1380
1381 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1382 if (req_wrap_async != nullptr) {
1383 FS_ASYNC_TRACE_BEGIN2(UV_FS_RENAME,
1384 req_wrap_async,
1385 "old_path",
1386 TRACE_STR_COPY(*old_path),
1387 "new_path",
1388 TRACE_STR_COPY(*new_path))
1389 AsyncDestCall(env, req_wrap_async, args, "rename", *new_path,
1390 new_path.length(), UTF8, AfterNoArgs, uv_fs_rename,
1391 *old_path, *new_path);
1392 } else {
1393 CHECK_EQ(argc, 4);
1394 FSReqWrapSync req_wrap_sync;
1395 FS_SYNC_TRACE_BEGIN(rename);
1396 SyncCall(env, args[3], &req_wrap_sync, "rename", uv_fs_rename,
1397 *old_path, *new_path);
1398 FS_SYNC_TRACE_END(rename);
1399 }
1400 }
1401
FTruncate(const FunctionCallbackInfo<Value> & args)1402 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
1403 Environment* env = Environment::GetCurrent(args);
1404
1405 const int argc = args.Length();
1406 CHECK_GE(argc, 3);
1407
1408 CHECK(args[0]->IsInt32());
1409 const int fd = args[0].As<Int32>()->Value();
1410
1411 CHECK(IsSafeJsInt(args[1]));
1412 const int64_t len = args[1].As<Integer>()->Value();
1413
1414 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1415 if (req_wrap_async != nullptr) {
1416 FS_ASYNC_TRACE_BEGIN0(UV_FS_FTRUNCATE, req_wrap_async)
1417 AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs,
1418 uv_fs_ftruncate, fd, len);
1419 } else {
1420 CHECK_EQ(argc, 4);
1421 FSReqWrapSync req_wrap_sync;
1422 FS_SYNC_TRACE_BEGIN(ftruncate);
1423 SyncCall(env, args[3], &req_wrap_sync, "ftruncate", uv_fs_ftruncate, fd,
1424 len);
1425 FS_SYNC_TRACE_END(ftruncate);
1426 }
1427 }
1428
Fdatasync(const FunctionCallbackInfo<Value> & args)1429 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
1430 Environment* env = Environment::GetCurrent(args);
1431
1432 const int argc = args.Length();
1433 CHECK_GE(argc, 2);
1434
1435 CHECK(args[0]->IsInt32());
1436 const int fd = args[0].As<Int32>()->Value();
1437
1438 FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1439 if (req_wrap_async != nullptr) {
1440 FS_ASYNC_TRACE_BEGIN0(UV_FS_FDATASYNC, req_wrap_async)
1441 AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs,
1442 uv_fs_fdatasync, fd);
1443 } else {
1444 CHECK_EQ(argc, 3);
1445 FSReqWrapSync req_wrap_sync;
1446 FS_SYNC_TRACE_BEGIN(fdatasync);
1447 SyncCall(env, args[2], &req_wrap_sync, "fdatasync", uv_fs_fdatasync, fd);
1448 FS_SYNC_TRACE_END(fdatasync);
1449 }
1450 }
1451
Fsync(const FunctionCallbackInfo<Value> & args)1452 static void Fsync(const FunctionCallbackInfo<Value>& args) {
1453 Environment* env = Environment::GetCurrent(args);
1454
1455 const int argc = args.Length();
1456 CHECK_GE(argc, 2);
1457
1458 CHECK(args[0]->IsInt32());
1459 const int fd = args[0].As<Int32>()->Value();
1460
1461 FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1462 if (req_wrap_async != nullptr) {
1463 FS_ASYNC_TRACE_BEGIN0(UV_FS_FSYNC, req_wrap_async)
1464 AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs,
1465 uv_fs_fsync, fd);
1466 } else {
1467 CHECK_EQ(argc, 3);
1468 FSReqWrapSync req_wrap_sync;
1469 FS_SYNC_TRACE_BEGIN(fsync);
1470 SyncCall(env, args[2], &req_wrap_sync, "fsync", uv_fs_fsync, fd);
1471 FS_SYNC_TRACE_END(fsync);
1472 }
1473 }
1474
Unlink(const FunctionCallbackInfo<Value> & args)1475 static void Unlink(const FunctionCallbackInfo<Value>& args) {
1476 Environment* env = Environment::GetCurrent(args);
1477
1478 const int argc = args.Length();
1479 CHECK_GE(argc, 2);
1480
1481 BufferValue path(env->isolate(), args[0]);
1482 CHECK_NOT_NULL(*path);
1483
1484 FSReqBase* req_wrap_async = GetReqWrap(args, 1);
1485 if (req_wrap_async != nullptr) {
1486 FS_ASYNC_TRACE_BEGIN1(
1487 UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1488 AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs,
1489 uv_fs_unlink, *path);
1490 } else {
1491 CHECK_EQ(argc, 3);
1492 FSReqWrapSync req_wrap_sync;
1493 FS_SYNC_TRACE_BEGIN(unlink);
1494 SyncCall(env, args[2], &req_wrap_sync, "unlink", uv_fs_unlink, *path);
1495 FS_SYNC_TRACE_END(unlink);
1496 }
1497 }
1498
RMDir(const FunctionCallbackInfo<Value> & args)1499 static void RMDir(const FunctionCallbackInfo<Value>& args) {
1500 Environment* env = Environment::GetCurrent(args);
1501
1502 const int argc = args.Length();
1503 CHECK_GE(argc, 2);
1504
1505 BufferValue path(env->isolate(), args[0]);
1506 CHECK_NOT_NULL(*path);
1507
1508 FSReqBase* req_wrap_async = GetReqWrap(args, 1); // rmdir(path, req)
1509 if (req_wrap_async != nullptr) {
1510 FS_ASYNC_TRACE_BEGIN1(
1511 UV_FS_RMDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1512 AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs,
1513 uv_fs_rmdir, *path);
1514 } else { // rmdir(path, undefined, ctx)
1515 CHECK_EQ(argc, 3);
1516 FSReqWrapSync req_wrap_sync;
1517 FS_SYNC_TRACE_BEGIN(rmdir);
1518 SyncCall(env, args[2], &req_wrap_sync, "rmdir",
1519 uv_fs_rmdir, *path);
1520 FS_SYNC_TRACE_END(rmdir);
1521 }
1522 }
1523
MKDirpSync(uv_loop_t * loop,uv_fs_t * req,const std::string & path,int mode,uv_fs_cb cb)1524 int MKDirpSync(uv_loop_t* loop,
1525 uv_fs_t* req,
1526 const std::string& path,
1527 int mode,
1528 uv_fs_cb cb) {
1529 FSReqWrapSync* req_wrap = ContainerOf(&FSReqWrapSync::req, req);
1530
1531 // on the first iteration of algorithm, stash state information.
1532 if (req_wrap->continuation_data() == nullptr) {
1533 req_wrap->set_continuation_data(
1534 std::make_unique<FSContinuationData>(req, mode, cb));
1535 req_wrap->continuation_data()->PushPath(std::move(path));
1536 }
1537
1538 while (req_wrap->continuation_data()->paths().size() > 0) {
1539 std::string next_path = req_wrap->continuation_data()->PopPath();
1540 int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode, nullptr);
1541 while (true) {
1542 switch (err) {
1543 // Note: uv_fs_req_cleanup in terminal paths will be called by
1544 // ~FSReqWrapSync():
1545 case 0:
1546 req_wrap->continuation_data()->MaybeSetFirstPath(next_path);
1547 if (req_wrap->continuation_data()->paths().size() == 0) {
1548 return 0;
1549 }
1550 break;
1551 case UV_EACCES:
1552 case UV_ENOSPC:
1553 case UV_ENOTDIR:
1554 case UV_EPERM: {
1555 return err;
1556 }
1557 case UV_ENOENT: {
1558 std::string dirname = next_path.substr(0,
1559 next_path.find_last_of(kPathSeparator));
1560 if (dirname != next_path) {
1561 req_wrap->continuation_data()->PushPath(std::move(next_path));
1562 req_wrap->continuation_data()->PushPath(std::move(dirname));
1563 } else if (req_wrap->continuation_data()->paths().size() == 0) {
1564 err = UV_EEXIST;
1565 continue;
1566 }
1567 break;
1568 }
1569 default:
1570 uv_fs_req_cleanup(req);
1571 int orig_err = err;
1572 err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
1573 if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
1574 uv_fs_req_cleanup(req);
1575 if (orig_err == UV_EEXIST &&
1576 req_wrap->continuation_data()->paths().size() > 0) {
1577 return UV_ENOTDIR;
1578 }
1579 return UV_EEXIST;
1580 }
1581 if (err < 0) return err;
1582 break;
1583 }
1584 break;
1585 }
1586 uv_fs_req_cleanup(req);
1587 }
1588
1589 return 0;
1590 }
1591
MKDirpAsync(uv_loop_t * loop,uv_fs_t * req,const char * path,int mode,uv_fs_cb cb)1592 int MKDirpAsync(uv_loop_t* loop,
1593 uv_fs_t* req,
1594 const char* path,
1595 int mode,
1596 uv_fs_cb cb) {
1597 FSReqBase* req_wrap = FSReqBase::from_req(req);
1598 // on the first iteration of algorithm, stash state information.
1599 if (req_wrap->continuation_data() == nullptr) {
1600 req_wrap->set_continuation_data(
1601 std::make_unique<FSContinuationData>(req, mode, cb));
1602 req_wrap->continuation_data()->PushPath(std::move(path));
1603 }
1604
1605 // on each iteration of algorithm, mkdir directory on top of stack.
1606 std::string next_path = req_wrap->continuation_data()->PopPath();
1607 int err = uv_fs_mkdir(loop, req, next_path.c_str(), mode,
1608 uv_fs_callback_t{[](uv_fs_t* req) {
1609 FSReqBase* req_wrap = FSReqBase::from_req(req);
1610 Environment* env = req_wrap->env();
1611 uv_loop_t* loop = env->event_loop();
1612 std::string path = req->path;
1613 int err = static_cast<int>(req->result);
1614
1615 while (true) {
1616 switch (err) {
1617 // Note: uv_fs_req_cleanup in terminal paths will be called by
1618 // FSReqAfterScope::~FSReqAfterScope()
1619 case 0: {
1620 if (req_wrap->continuation_data()->paths().size() == 0) {
1621 req_wrap->continuation_data()->MaybeSetFirstPath(path);
1622 req_wrap->continuation_data()->Done(0);
1623 } else {
1624 req_wrap->continuation_data()->MaybeSetFirstPath(path);
1625 uv_fs_req_cleanup(req);
1626 MKDirpAsync(loop, req, path.c_str(),
1627 req_wrap->continuation_data()->mode(), nullptr);
1628 }
1629 break;
1630 }
1631 case UV_EACCES:
1632 case UV_ENOTDIR:
1633 case UV_EPERM: {
1634 req_wrap->continuation_data()->Done(err);
1635 break;
1636 }
1637 case UV_ENOENT: {
1638 std::string dirname = path.substr(0,
1639 path.find_last_of(kPathSeparator));
1640 if (dirname != path) {
1641 req_wrap->continuation_data()->PushPath(path);
1642 req_wrap->continuation_data()->PushPath(std::move(dirname));
1643 } else if (req_wrap->continuation_data()->paths().size() == 0) {
1644 err = UV_EEXIST;
1645 continue;
1646 }
1647 uv_fs_req_cleanup(req);
1648 MKDirpAsync(loop, req, path.c_str(),
1649 req_wrap->continuation_data()->mode(), nullptr);
1650 break;
1651 }
1652 default:
1653 uv_fs_req_cleanup(req);
1654 // Stash err for use in the callback.
1655 req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
1656 int err = uv_fs_stat(loop, req, path.c_str(),
1657 uv_fs_callback_t{[](uv_fs_t* req) {
1658 FSReqBase* req_wrap = FSReqBase::from_req(req);
1659 int err = static_cast<int>(req->result);
1660 if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
1661 req_wrap->continuation_data()->paths().size() > 0) {
1662 if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
1663 Environment* env = req_wrap->env();
1664 uv_loop_t* loop = env->event_loop();
1665 std::string path = req->path;
1666 uv_fs_req_cleanup(req);
1667 MKDirpAsync(loop, req, path.c_str(),
1668 req_wrap->continuation_data()->mode(), nullptr);
1669 return;
1670 }
1671 err = UV_ENOTDIR;
1672 }
1673 // verify that the path pointed to is actually a directory.
1674 if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
1675 req_wrap->continuation_data()->Done(err);
1676 }});
1677 if (err < 0) req_wrap->continuation_data()->Done(err);
1678 break;
1679 }
1680 break;
1681 }
1682 }});
1683
1684 return err;
1685 }
1686
CallMKDirpSync(Environment * env,const FunctionCallbackInfo<Value> & args,FSReqWrapSync * req_wrap,const char * path,int mode)1687 int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1688 FSReqWrapSync* req_wrap, const char* path, int mode) {
1689 env->PrintSyncTrace();
1690 int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1691 nullptr);
1692 if (err < 0) {
1693 v8::Local<v8::Context> context = env->context();
1694 v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1695 v8::Isolate* isolate = env->isolate();
1696 ctx_obj->Set(context,
1697 env->errno_string(),
1698 v8::Integer::New(isolate, err)).Check();
1699 ctx_obj->Set(context,
1700 env->syscall_string(),
1701 OneByteString(isolate, "mkdir")).Check();
1702 }
1703 return err;
1704 }
1705
MKDir(const FunctionCallbackInfo<Value> & args)1706 static void MKDir(const FunctionCallbackInfo<Value>& args) {
1707 Environment* env = Environment::GetCurrent(args);
1708
1709 const int argc = args.Length();
1710 CHECK_GE(argc, 4);
1711
1712 BufferValue path(env->isolate(), args[0]);
1713 CHECK_NOT_NULL(*path);
1714
1715 CHECK(args[1]->IsInt32());
1716 const int mode = args[1].As<Int32>()->Value();
1717
1718 CHECK(args[2]->IsBoolean());
1719 bool mkdirp = args[2]->IsTrue();
1720
1721 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1722 if (req_wrap_async != nullptr) { // mkdir(path, mode, req)
1723 FS_ASYNC_TRACE_BEGIN1(
1724 UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
1725 AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
1726 mkdirp ? AfterMkdirp : AfterNoArgs,
1727 mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1728 } else { // mkdir(path, mode, undefined, ctx)
1729 CHECK_EQ(argc, 5);
1730 FSReqWrapSync req_wrap_sync;
1731 FS_SYNC_TRACE_BEGIN(mkdir);
1732 if (mkdirp) {
1733 int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1734 if (err == 0 &&
1735 !req_wrap_sync.continuation_data()->first_path().empty()) {
1736 Local<Value> error;
1737 std::string first_path(req_wrap_sync.continuation_data()->first_path());
1738 FromNamespacedPath(&first_path);
1739 MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
1740 first_path.c_str(),
1741 UTF8, &error);
1742 if (path.IsEmpty()) {
1743 Local<Object> ctx = args[4].As<Object>();
1744 ctx->Set(env->context(), env->error_string(), error).Check();
1745 return;
1746 }
1747 args.GetReturnValue().Set(path.ToLocalChecked());
1748 }
1749 } else {
1750 SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1751 uv_fs_mkdir, *path, mode);
1752 }
1753 FS_SYNC_TRACE_END(mkdir);
1754 }
1755 }
1756
RealPath(const FunctionCallbackInfo<Value> & args)1757 static void RealPath(const FunctionCallbackInfo<Value>& args) {
1758 Environment* env = Environment::GetCurrent(args);
1759 Isolate* isolate = env->isolate();
1760
1761 const int argc = args.Length();
1762 CHECK_GE(argc, 3);
1763
1764 BufferValue path(isolate, args[0]);
1765 CHECK_NOT_NULL(*path);
1766
1767 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1768
1769 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
1770 if (req_wrap_async != nullptr) { // realpath(path, encoding, req)
1771 FS_ASYNC_TRACE_BEGIN1(
1772 UV_FS_REALPATH, req_wrap_async, "path", TRACE_STR_COPY(*path))
1773 AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr,
1774 uv_fs_realpath, *path);
1775 } else { // realpath(path, encoding, undefined, ctx)
1776 CHECK_EQ(argc, 4);
1777 FSReqWrapSync req_wrap_sync;
1778 FS_SYNC_TRACE_BEGIN(realpath);
1779 int err = SyncCall(env, args[3], &req_wrap_sync, "realpath",
1780 uv_fs_realpath, *path);
1781 FS_SYNC_TRACE_END(realpath);
1782 if (err < 0) {
1783 return; // syscall failed, no need to continue, error info is in ctx
1784 }
1785
1786 const char* link_path = static_cast<const char*>(req_wrap_sync.req.ptr);
1787
1788 Local<Value> error;
1789 MaybeLocal<Value> rc = StringBytes::Encode(isolate,
1790 link_path,
1791 encoding,
1792 &error);
1793 if (rc.IsEmpty()) {
1794 Local<Object> ctx = args[3].As<Object>();
1795 ctx->Set(env->context(), env->error_string(), error).Check();
1796 return;
1797 }
1798
1799 args.GetReturnValue().Set(rc.ToLocalChecked());
1800 }
1801 }
1802
ReadDir(const FunctionCallbackInfo<Value> & args)1803 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
1804 Environment* env = Environment::GetCurrent(args);
1805 Isolate* isolate = env->isolate();
1806
1807 const int argc = args.Length();
1808 CHECK_GE(argc, 3);
1809
1810 BufferValue path(isolate, args[0]);
1811 CHECK_NOT_NULL(*path);
1812
1813 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
1814
1815 bool with_types = args[2]->IsTrue();
1816
1817 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1818 if (req_wrap_async != nullptr) { // readdir(path, encoding, withTypes, req)
1819 req_wrap_async->set_with_file_types(with_types);
1820 FS_ASYNC_TRACE_BEGIN1(
1821 UV_FS_SCANDIR, req_wrap_async, "path", TRACE_STR_COPY(*path))
1822 AsyncCall(env,
1823 req_wrap_async,
1824 args,
1825 "scandir",
1826 encoding,
1827 AfterScanDir,
1828 uv_fs_scandir,
1829 *path,
1830 0 /*flags*/);
1831 } else { // readdir(path, encoding, withTypes, undefined, ctx)
1832 CHECK_EQ(argc, 5);
1833 FSReqWrapSync req_wrap_sync;
1834 FS_SYNC_TRACE_BEGIN(readdir);
1835 int err = SyncCall(env, args[4], &req_wrap_sync, "scandir",
1836 uv_fs_scandir, *path, 0 /*flags*/);
1837 FS_SYNC_TRACE_END(readdir);
1838 if (err < 0) {
1839 return; // syscall failed, no need to continue, error info is in ctx
1840 }
1841
1842 CHECK_GE(req_wrap_sync.req.result, 0);
1843 int r;
1844 std::vector<Local<Value>> name_v;
1845 std::vector<Local<Value>> type_v;
1846
1847 for (;;) {
1848 uv_dirent_t ent;
1849
1850 r = uv_fs_scandir_next(&(req_wrap_sync.req), &ent);
1851 if (r == UV_EOF)
1852 break;
1853 if (r != 0) {
1854 Local<Object> ctx = args[4].As<Object>();
1855 ctx->Set(env->context(), env->errno_string(),
1856 Integer::New(isolate, r)).Check();
1857 ctx->Set(env->context(), env->syscall_string(),
1858 OneByteString(isolate, "readdir")).Check();
1859 return;
1860 }
1861
1862 Local<Value> error;
1863 MaybeLocal<Value> filename = StringBytes::Encode(isolate,
1864 ent.name,
1865 encoding,
1866 &error);
1867
1868 if (filename.IsEmpty()) {
1869 Local<Object> ctx = args[4].As<Object>();
1870 ctx->Set(env->context(), env->error_string(), error).Check();
1871 return;
1872 }
1873
1874 name_v.push_back(filename.ToLocalChecked());
1875
1876 if (with_types) {
1877 type_v.emplace_back(Integer::New(isolate, ent.type));
1878 }
1879 }
1880
1881
1882 Local<Array> names = Array::New(isolate, name_v.data(), name_v.size());
1883 if (with_types) {
1884 Local<Value> result[] = {
1885 names,
1886 Array::New(isolate, type_v.data(), type_v.size())
1887 };
1888 args.GetReturnValue().Set(Array::New(isolate, result, arraysize(result)));
1889 } else {
1890 args.GetReturnValue().Set(names);
1891 }
1892 }
1893 }
1894
Open(const FunctionCallbackInfo<Value> & args)1895 static void Open(const FunctionCallbackInfo<Value>& args) {
1896 Environment* env = Environment::GetCurrent(args);
1897
1898 const int argc = args.Length();
1899 CHECK_GE(argc, 3);
1900
1901 BufferValue path(env->isolate(), args[0]);
1902 CHECK_NOT_NULL(*path);
1903
1904 CHECK(args[1]->IsInt32());
1905 const int flags = args[1].As<Int32>()->Value();
1906
1907 CHECK(args[2]->IsInt32());
1908 const int mode = args[2].As<Int32>()->Value();
1909
1910 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1911 if (req_wrap_async != nullptr) { // open(path, flags, mode, req)
1912 req_wrap_async->set_is_plain_open(true);
1913 FS_ASYNC_TRACE_BEGIN1(
1914 UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1915 AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger,
1916 uv_fs_open, *path, flags, mode);
1917 } else { // open(path, flags, mode, undefined, ctx)
1918 CHECK_EQ(argc, 5);
1919 FSReqWrapSync req_wrap_sync;
1920 FS_SYNC_TRACE_BEGIN(open);
1921 int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1922 uv_fs_open, *path, flags, mode);
1923 FS_SYNC_TRACE_END(open);
1924 if (result >= 0) env->AddUnmanagedFd(result);
1925 args.GetReturnValue().Set(result);
1926 }
1927 }
1928
OpenFileHandle(const FunctionCallbackInfo<Value> & args)1929 static void OpenFileHandle(const FunctionCallbackInfo<Value>& args) {
1930 BindingData* binding_data = Realm::GetBindingData<BindingData>(args);
1931 Environment* env = binding_data->env();
1932 Isolate* isolate = env->isolate();
1933
1934 const int argc = args.Length();
1935 CHECK_GE(argc, 3);
1936
1937 BufferValue path(isolate, args[0]);
1938 CHECK_NOT_NULL(*path);
1939
1940 CHECK(args[1]->IsInt32());
1941 const int flags = args[1].As<Int32>()->Value();
1942
1943 CHECK(args[2]->IsInt32());
1944 const int mode = args[2].As<Int32>()->Value();
1945
1946 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1947 if (req_wrap_async != nullptr) { // openFileHandle(path, flags, mode, req)
1948 FS_ASYNC_TRACE_BEGIN1(
1949 UV_FS_OPEN, req_wrap_async, "path", TRACE_STR_COPY(*path))
1950 AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle,
1951 uv_fs_open, *path, flags, mode);
1952 } else { // openFileHandle(path, flags, mode, undefined, ctx)
1953 CHECK_EQ(argc, 5);
1954 FSReqWrapSync req_wrap_sync;
1955 FS_SYNC_TRACE_BEGIN(open);
1956 int result = SyncCall(env, args[4], &req_wrap_sync, "open",
1957 uv_fs_open, *path, flags, mode);
1958 FS_SYNC_TRACE_END(open);
1959 if (result < 0) {
1960 return; // syscall failed, no need to continue, error info is in ctx
1961 }
1962 FileHandle* fd = FileHandle::New(binding_data, result);
1963 if (fd == nullptr) return;
1964 args.GetReturnValue().Set(fd->object());
1965 }
1966 }
1967
CopyFile(const FunctionCallbackInfo<Value> & args)1968 static void CopyFile(const FunctionCallbackInfo<Value>& args) {
1969 Environment* env = Environment::GetCurrent(args);
1970 Isolate* isolate = env->isolate();
1971
1972 const int argc = args.Length();
1973 CHECK_GE(argc, 3);
1974
1975 BufferValue src(isolate, args[0]);
1976 CHECK_NOT_NULL(*src);
1977
1978 BufferValue dest(isolate, args[1]);
1979 CHECK_NOT_NULL(*dest);
1980
1981 CHECK(args[2]->IsInt32());
1982 const int flags = args[2].As<Int32>()->Value();
1983
1984 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1985 if (req_wrap_async != nullptr) { // copyFile(src, dest, flags, req)
1986 FS_ASYNC_TRACE_BEGIN2(UV_FS_COPYFILE,
1987 req_wrap_async,
1988 "src",
1989 TRACE_STR_COPY(*src),
1990 "dest",
1991 TRACE_STR_COPY(*dest))
1992 AsyncDestCall(env, req_wrap_async, args, "copyfile",
1993 *dest, dest.length(), UTF8, AfterNoArgs,
1994 uv_fs_copyfile, *src, *dest, flags);
1995 } else { // copyFile(src, dest, flags, undefined, ctx)
1996 CHECK_EQ(argc, 5);
1997 FSReqWrapSync req_wrap_sync;
1998 FS_SYNC_TRACE_BEGIN(copyfile);
1999 SyncCall(env, args[4], &req_wrap_sync, "copyfile",
2000 uv_fs_copyfile, *src, *dest, flags);
2001 FS_SYNC_TRACE_END(copyfile);
2002 }
2003 }
2004
2005
2006 // Wrapper for write(2).
2007 //
2008 // bytesWritten = write(fd, buffer, offset, length, position, callback)
2009 // 0 fd integer. file descriptor
2010 // 1 buffer the data to write
2011 // 2 offset where in the buffer to start from
2012 // 3 length how much to write
2013 // 4 position if integer, position to write at in the file.
2014 // if null, write from the current position
WriteBuffer(const FunctionCallbackInfo<Value> & args)2015 static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
2016 Environment* env = Environment::GetCurrent(args);
2017
2018 const int argc = args.Length();
2019 CHECK_GE(argc, 4);
2020
2021 CHECK(args[0]->IsInt32());
2022 const int fd = args[0].As<Int32>()->Value();
2023
2024 CHECK(Buffer::HasInstance(args[1]));
2025 Local<Object> buffer_obj = args[1].As<Object>();
2026 char* buffer_data = Buffer::Data(buffer_obj);
2027 size_t buffer_length = Buffer::Length(buffer_obj);
2028
2029 CHECK(IsSafeJsInt(args[2]));
2030 const int64_t off_64 = args[2].As<Integer>()->Value();
2031 CHECK_GE(off_64, 0);
2032 CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
2033 const size_t off = static_cast<size_t>(off_64);
2034
2035 CHECK(args[3]->IsInt32());
2036 const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2037 CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2038 CHECK_LE(len, buffer_length);
2039 CHECK_GE(off + len, off);
2040
2041 const int64_t pos = GetOffset(args[4]);
2042
2043 char* buf = buffer_data + off;
2044 uv_buf_t uvbuf = uv_buf_init(buf, len);
2045
2046 FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2047 if (req_wrap_async != nullptr) { // write(fd, buffer, off, len, pos, req)
2048 FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2049 AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
2050 uv_fs_write, fd, &uvbuf, 1, pos);
2051 } else { // write(fd, buffer, off, len, pos, undefined, ctx)
2052 CHECK_EQ(argc, 7);
2053 FSReqWrapSync req_wrap_sync;
2054 FS_SYNC_TRACE_BEGIN(write);
2055 int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
2056 uv_fs_write, fd, &uvbuf, 1, pos);
2057 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2058 args.GetReturnValue().Set(bytesWritten);
2059 }
2060 }
2061
2062
2063 // Wrapper for writev(2).
2064 //
2065 // bytesWritten = writev(fd, chunks, position, callback)
2066 // 0 fd integer. file descriptor
2067 // 1 chunks array of buffers to write
2068 // 2 position if integer, position to write at in the file.
2069 // if null, write from the current position
WriteBuffers(const FunctionCallbackInfo<Value> & args)2070 static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
2071 Environment* env = Environment::GetCurrent(args);
2072
2073 const int argc = args.Length();
2074 CHECK_GE(argc, 3);
2075
2076 CHECK(args[0]->IsInt32());
2077 const int fd = args[0].As<Int32>()->Value();
2078
2079 CHECK(args[1]->IsArray());
2080 Local<Array> chunks = args[1].As<Array>();
2081
2082 int64_t pos = GetOffset(args[2]);
2083
2084 MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
2085
2086 for (uint32_t i = 0; i < iovs.length(); i++) {
2087 Local<Value> chunk = chunks->Get(env->context(), i).ToLocalChecked();
2088 CHECK(Buffer::HasInstance(chunk));
2089 iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
2090 }
2091
2092 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2093 if (req_wrap_async != nullptr) { // writeBuffers(fd, chunks, pos, req)
2094 FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2095 AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
2096 uv_fs_write, fd, *iovs, iovs.length(), pos);
2097 } else { // writeBuffers(fd, chunks, pos, undefined, ctx)
2098 CHECK_EQ(argc, 5);
2099 FSReqWrapSync req_wrap_sync;
2100 FS_SYNC_TRACE_BEGIN(write);
2101 int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write",
2102 uv_fs_write, fd, *iovs, iovs.length(), pos);
2103 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2104 args.GetReturnValue().Set(bytesWritten);
2105 }
2106 }
2107
2108
2109 // Wrapper for write(2).
2110 //
2111 // bytesWritten = write(fd, string, position, enc, callback)
2112 // 0 fd integer. file descriptor
2113 // 1 string non-buffer values are converted to strings
2114 // 2 position if integer, position to write at in the file.
2115 // if null, write from the current position
2116 // 3 enc encoding of string
WriteString(const FunctionCallbackInfo<Value> & args)2117 static void WriteString(const FunctionCallbackInfo<Value>& args) {
2118 Environment* env = Environment::GetCurrent(args);
2119 Isolate* isolate = env->isolate();
2120
2121 const int argc = args.Length();
2122 CHECK_GE(argc, 4);
2123
2124 CHECK(args[0]->IsInt32());
2125 const int fd = args[0].As<Int32>()->Value();
2126
2127 const int64_t pos = GetOffset(args[2]);
2128
2129 const auto enc = ParseEncoding(isolate, args[3], UTF8);
2130
2131 Local<Value> value = args[1];
2132 char* buf = nullptr;
2133 size_t len;
2134
2135 FSReqBase* req_wrap_async = GetReqWrap(args, 4);
2136 const bool is_async = req_wrap_async != nullptr;
2137
2138 // Avoid copying the string when it is externalized but only when:
2139 // 1. The target encoding is compatible with the string's encoding, and
2140 // 2. The write is synchronous, otherwise the string might get neutered
2141 // while the request is in flight, and
2142 // 3. For UCS2, when the host system is little-endian. Big-endian systems
2143 // need to call StringBytes::Write() to ensure proper byte swapping.
2144 // The const_casts are conceptually sound: memory is read but not written.
2145 if (!is_async && value->IsString()) {
2146 auto string = value.As<String>();
2147 if ((enc == ASCII || enc == LATIN1) && string->IsExternalOneByte()) {
2148 auto ext = string->GetExternalOneByteStringResource();
2149 buf = const_cast<char*>(ext->data());
2150 len = ext->length();
2151 } else if (enc == UCS2 && IsLittleEndian() && string->IsExternalTwoByte()) {
2152 auto ext = string->GetExternalStringResource();
2153 buf = reinterpret_cast<char*>(const_cast<uint16_t*>(ext->data()));
2154 len = ext->length() * sizeof(*ext->data());
2155 }
2156 }
2157
2158 if (is_async) { // write(fd, string, pos, enc, req)
2159 CHECK_NOT_NULL(req_wrap_async);
2160 if (!StringBytes::StorageSize(isolate, value, enc).To(&len)) return;
2161 FSReqBase::FSReqBuffer& stack_buffer =
2162 req_wrap_async->Init("write", len, enc);
2163 // StorageSize may return too large a char, so correct the actual length
2164 // by the write size
2165 len = StringBytes::Write(isolate, *stack_buffer, len, args[1], enc);
2166 stack_buffer.SetLengthAndZeroTerminate(len);
2167 uv_buf_t uvbuf = uv_buf_init(*stack_buffer, len);
2168 FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
2169 int err = req_wrap_async->Dispatch(uv_fs_write,
2170 fd,
2171 &uvbuf,
2172 1,
2173 pos,
2174 AfterInteger);
2175 if (err < 0) {
2176 uv_fs_t* uv_req = req_wrap_async->req();
2177 uv_req->result = err;
2178 uv_req->path = nullptr;
2179 AfterInteger(uv_req); // after may delete req_wrap_async if there is
2180 // an error
2181 } else {
2182 req_wrap_async->SetReturnValue(args);
2183 }
2184 } else { // write(fd, string, pos, enc, undefined, ctx)
2185 CHECK_EQ(argc, 6);
2186 FSReqWrapSync req_wrap_sync;
2187 FSReqBase::FSReqBuffer stack_buffer;
2188 if (buf == nullptr) {
2189 if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
2190 return;
2191 stack_buffer.AllocateSufficientStorage(len + 1);
2192 // StorageSize may return too large a char, so correct the actual length
2193 // by the write size
2194 len = StringBytes::Write(isolate, *stack_buffer,
2195 len, args[1], enc);
2196 stack_buffer.SetLengthAndZeroTerminate(len);
2197 buf = *stack_buffer;
2198 }
2199 uv_buf_t uvbuf = uv_buf_init(buf, len);
2200 FS_SYNC_TRACE_BEGIN(write);
2201 int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
2202 uv_fs_write, fd, &uvbuf, 1, pos);
2203 FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
2204 args.GetReturnValue().Set(bytesWritten);
2205 }
2206 }
2207
2208
2209 /*
2210 * Wrapper for read(2).
2211 *
2212 * bytesRead = fs.read(fd, buffer, offset, length, position)
2213 *
2214 * 0 fd int32. file descriptor
2215 * 1 buffer instance of Buffer
2216 * 2 offset int64. offset to start reading into inside buffer
2217 * 3 length int32. length to read
2218 * 4 position int64. file position - -1 for current position
2219 */
Read(const FunctionCallbackInfo<Value> & args)2220 static void Read(const FunctionCallbackInfo<Value>& args) {
2221 Environment* env = Environment::GetCurrent(args);
2222
2223 const int argc = args.Length();
2224 CHECK_GE(argc, 5);
2225
2226 CHECK(args[0]->IsInt32());
2227 const int fd = args[0].As<Int32>()->Value();
2228
2229 CHECK(Buffer::HasInstance(args[1]));
2230 Local<Object> buffer_obj = args[1].As<Object>();
2231 char* buffer_data = Buffer::Data(buffer_obj);
2232 size_t buffer_length = Buffer::Length(buffer_obj);
2233
2234 CHECK(IsSafeJsInt(args[2]));
2235 const int64_t off_64 = args[2].As<Integer>()->Value();
2236 CHECK_GE(off_64, 0);
2237 CHECK_LT(static_cast<uint64_t>(off_64), buffer_length);
2238 const size_t off = static_cast<size_t>(off_64);
2239
2240 CHECK(args[3]->IsInt32());
2241 const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());
2242 CHECK(Buffer::IsWithinBounds(off, len, buffer_length));
2243
2244 CHECK(IsSafeJsInt(args[4]) || args[4]->IsBigInt());
2245 const int64_t pos = args[4]->IsNumber() ?
2246 args[4].As<Integer>()->Value() :
2247 args[4].As<BigInt>()->Int64Value();
2248
2249 char* buf = buffer_data + off;
2250 uv_buf_t uvbuf = uv_buf_init(buf, len);
2251
2252 FSReqBase* req_wrap_async = GetReqWrap(args, 5);
2253 if (req_wrap_async != nullptr) { // read(fd, buffer, offset, len, pos, req)
2254 FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2255 AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2256 uv_fs_read, fd, &uvbuf, 1, pos);
2257 } else { // read(fd, buffer, offset, len, pos, undefined, ctx)
2258 CHECK_EQ(argc, 7);
2259 FSReqWrapSync req_wrap_sync;
2260 FS_SYNC_TRACE_BEGIN(read);
2261 const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read",
2262 uv_fs_read, fd, &uvbuf, 1, pos);
2263 FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2264 args.GetReturnValue().Set(bytesRead);
2265 }
2266 }
2267
2268
2269 // Wrapper for readv(2).
2270 //
2271 // bytesRead = fs.readv(fd, buffers[, position], callback)
2272 // 0 fd integer. file descriptor
2273 // 1 buffers array of buffers to read
2274 // 2 position if integer, position to read at in the file.
2275 // if null, read from the current position
ReadBuffers(const FunctionCallbackInfo<Value> & args)2276 static void ReadBuffers(const FunctionCallbackInfo<Value>& args) {
2277 Environment* env = Environment::GetCurrent(args);
2278
2279 const int argc = args.Length();
2280 CHECK_GE(argc, 3);
2281
2282 CHECK(args[0]->IsInt32());
2283 const int fd = args[0].As<Int32>()->Value();
2284
2285 CHECK(args[1]->IsArray());
2286 Local<Array> buffers = args[1].As<Array>();
2287
2288 int64_t pos = GetOffset(args[2]); // -1 if not a valid JS int
2289
2290 MaybeStackBuffer<uv_buf_t> iovs(buffers->Length());
2291
2292 // Init uv buffers from ArrayBufferViews
2293 for (uint32_t i = 0; i < iovs.length(); i++) {
2294 Local<Value> buffer = buffers->Get(env->context(), i).ToLocalChecked();
2295 CHECK(Buffer::HasInstance(buffer));
2296 iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer));
2297 }
2298
2299 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2300 if (req_wrap_async != nullptr) { // readBuffers(fd, buffers, pos, req)
2301 FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async)
2302 AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger,
2303 uv_fs_read, fd, *iovs, iovs.length(), pos);
2304 } else { // readBuffers(fd, buffers, undefined, ctx)
2305 CHECK_EQ(argc, 5);
2306 FSReqWrapSync req_wrap_sync;
2307 FS_SYNC_TRACE_BEGIN(read);
2308 int bytesRead = SyncCall(env, /* ctx */ args[4], &req_wrap_sync, "read",
2309 uv_fs_read, fd, *iovs, iovs.length(), pos);
2310 FS_SYNC_TRACE_END(read, "bytesRead", bytesRead);
2311 args.GetReturnValue().Set(bytesRead);
2312 }
2313 }
2314
2315
2316 /* fs.chmod(path, mode);
2317 * Wrapper for chmod(1) / EIO_CHMOD
2318 */
Chmod(const FunctionCallbackInfo<Value> & args)2319 static void Chmod(const FunctionCallbackInfo<Value>& args) {
2320 Environment* env = Environment::GetCurrent(args);
2321
2322 const int argc = args.Length();
2323 CHECK_GE(argc, 2);
2324
2325 BufferValue path(env->isolate(), args[0]);
2326 CHECK_NOT_NULL(*path);
2327
2328 CHECK(args[1]->IsInt32());
2329 int mode = args[1].As<Int32>()->Value();
2330
2331 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2332 if (req_wrap_async != nullptr) { // chmod(path, mode, req)
2333 FS_ASYNC_TRACE_BEGIN1(
2334 UV_FS_CHMOD, req_wrap_async, "path", TRACE_STR_COPY(*path))
2335 AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
2336 uv_fs_chmod, *path, mode);
2337 } else { // chmod(path, mode, undefined, ctx)
2338 CHECK_EQ(argc, 4);
2339 FSReqWrapSync req_wrap_sync;
2340 FS_SYNC_TRACE_BEGIN(chmod);
2341 SyncCall(env, args[3], &req_wrap_sync, "chmod",
2342 uv_fs_chmod, *path, mode);
2343 FS_SYNC_TRACE_END(chmod);
2344 }
2345 }
2346
2347
2348 /* fs.fchmod(fd, mode);
2349 * Wrapper for fchmod(1) / EIO_FCHMOD
2350 */
FChmod(const FunctionCallbackInfo<Value> & args)2351 static void FChmod(const FunctionCallbackInfo<Value>& args) {
2352 Environment* env = Environment::GetCurrent(args);
2353
2354 const int argc = args.Length();
2355 CHECK_GE(argc, 2);
2356
2357 CHECK(args[0]->IsInt32());
2358 const int fd = args[0].As<Int32>()->Value();
2359
2360 CHECK(args[1]->IsInt32());
2361 const int mode = args[1].As<Int32>()->Value();
2362
2363 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2364 if (req_wrap_async != nullptr) { // fchmod(fd, mode, req)
2365 FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
2366 AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
2367 uv_fs_fchmod, fd, mode);
2368 } else { // fchmod(fd, mode, undefined, ctx)
2369 CHECK_EQ(argc, 4);
2370 FSReqWrapSync req_wrap_sync;
2371 FS_SYNC_TRACE_BEGIN(fchmod);
2372 SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2373 uv_fs_fchmod, fd, mode);
2374 FS_SYNC_TRACE_END(fchmod);
2375 }
2376 }
2377
2378
2379 /* fs.chown(path, uid, gid);
2380 * Wrapper for chown(1) / EIO_CHOWN
2381 */
Chown(const FunctionCallbackInfo<Value> & args)2382 static void Chown(const FunctionCallbackInfo<Value>& args) {
2383 Environment* env = Environment::GetCurrent(args);
2384
2385 const int argc = args.Length();
2386 CHECK_GE(argc, 3);
2387
2388 BufferValue path(env->isolate(), args[0]);
2389 CHECK_NOT_NULL(*path);
2390
2391 CHECK(IsSafeJsInt(args[1]));
2392 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2393
2394 CHECK(IsSafeJsInt(args[2]));
2395 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2396
2397 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2398 if (req_wrap_async != nullptr) { // chown(path, uid, gid, req)
2399 FS_ASYNC_TRACE_BEGIN1(
2400 UV_FS_CHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2401 AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs,
2402 uv_fs_chown, *path, uid, gid);
2403 } else { // chown(path, uid, gid, undefined, ctx)
2404 CHECK_EQ(argc, 5);
2405 FSReqWrapSync req_wrap_sync;
2406 FS_SYNC_TRACE_BEGIN(chown);
2407 SyncCall(env, args[4], &req_wrap_sync, "chown",
2408 uv_fs_chown, *path, uid, gid);
2409 FS_SYNC_TRACE_END(chown);
2410 }
2411 }
2412
2413
2414 /* fs.fchown(fd, uid, gid);
2415 * Wrapper for fchown(1) / EIO_FCHOWN
2416 */
FChown(const FunctionCallbackInfo<Value> & args)2417 static void FChown(const FunctionCallbackInfo<Value>& args) {
2418 Environment* env = Environment::GetCurrent(args);
2419
2420 const int argc = args.Length();
2421 CHECK_GE(argc, 3);
2422
2423 CHECK(args[0]->IsInt32());
2424 const int fd = args[0].As<Int32>()->Value();
2425
2426 CHECK(IsSafeJsInt(args[1]));
2427 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2428
2429 CHECK(IsSafeJsInt(args[2]));
2430 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2431
2432 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2433 if (req_wrap_async != nullptr) { // fchown(fd, uid, gid, req)
2434 FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHOWN, req_wrap_async)
2435 AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs,
2436 uv_fs_fchown, fd, uid, gid);
2437 } else { // fchown(fd, uid, gid, undefined, ctx)
2438 CHECK_EQ(argc, 5);
2439 FSReqWrapSync req_wrap_sync;
2440 FS_SYNC_TRACE_BEGIN(fchown);
2441 SyncCall(env, args[4], &req_wrap_sync, "fchown",
2442 uv_fs_fchown, fd, uid, gid);
2443 FS_SYNC_TRACE_END(fchown);
2444 }
2445 }
2446
2447
LChown(const FunctionCallbackInfo<Value> & args)2448 static void LChown(const FunctionCallbackInfo<Value>& args) {
2449 Environment* env = Environment::GetCurrent(args);
2450
2451 const int argc = args.Length();
2452 CHECK_GE(argc, 3);
2453
2454 BufferValue path(env->isolate(), args[0]);
2455 CHECK_NOT_NULL(*path);
2456
2457 CHECK(IsSafeJsInt(args[1]));
2458 const uv_uid_t uid = static_cast<uv_uid_t>(args[1].As<Integer>()->Value());
2459
2460 CHECK(IsSafeJsInt(args[2]));
2461 const uv_gid_t gid = static_cast<uv_gid_t>(args[2].As<Integer>()->Value());
2462
2463 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2464 if (req_wrap_async != nullptr) { // lchown(path, uid, gid, req)
2465 FS_ASYNC_TRACE_BEGIN1(
2466 UV_FS_LCHOWN, req_wrap_async, "path", TRACE_STR_COPY(*path))
2467 AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs,
2468 uv_fs_lchown, *path, uid, gid);
2469 } else { // lchown(path, uid, gid, undefined, ctx)
2470 CHECK_EQ(argc, 5);
2471 FSReqWrapSync req_wrap_sync;
2472 FS_SYNC_TRACE_BEGIN(lchown);
2473 SyncCall(env, args[4], &req_wrap_sync, "lchown",
2474 uv_fs_lchown, *path, uid, gid);
2475 FS_SYNC_TRACE_END(lchown);
2476 }
2477 }
2478
2479
UTimes(const FunctionCallbackInfo<Value> & args)2480 static void UTimes(const FunctionCallbackInfo<Value>& args) {
2481 Environment* env = Environment::GetCurrent(args);
2482
2483 const int argc = args.Length();
2484 CHECK_GE(argc, 3);
2485
2486 BufferValue path(env->isolate(), args[0]);
2487 CHECK_NOT_NULL(*path);
2488
2489 CHECK(args[1]->IsNumber());
2490 const double atime = args[1].As<Number>()->Value();
2491
2492 CHECK(args[2]->IsNumber());
2493 const double mtime = args[2].As<Number>()->Value();
2494
2495 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2496 if (req_wrap_async != nullptr) { // utimes(path, atime, mtime, req)
2497 FS_ASYNC_TRACE_BEGIN1(
2498 UV_FS_UTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2499 AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs,
2500 uv_fs_utime, *path, atime, mtime);
2501 } else { // utimes(path, atime, mtime, undefined, ctx)
2502 CHECK_EQ(argc, 5);
2503 FSReqWrapSync req_wrap_sync;
2504 FS_SYNC_TRACE_BEGIN(utimes);
2505 SyncCall(env, args[4], &req_wrap_sync, "utime",
2506 uv_fs_utime, *path, atime, mtime);
2507 FS_SYNC_TRACE_END(utimes);
2508 }
2509 }
2510
FUTimes(const FunctionCallbackInfo<Value> & args)2511 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
2512 Environment* env = Environment::GetCurrent(args);
2513
2514 const int argc = args.Length();
2515 CHECK_GE(argc, 3);
2516
2517 CHECK(args[0]->IsInt32());
2518 const int fd = args[0].As<Int32>()->Value();
2519
2520 CHECK(args[1]->IsNumber());
2521 const double atime = args[1].As<Number>()->Value();
2522
2523 CHECK(args[2]->IsNumber());
2524 const double mtime = args[2].As<Number>()->Value();
2525
2526 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2527 if (req_wrap_async != nullptr) { // futimes(fd, atime, mtime, req)
2528 FS_ASYNC_TRACE_BEGIN0(UV_FS_FUTIME, req_wrap_async)
2529 AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs,
2530 uv_fs_futime, fd, atime, mtime);
2531 } else { // futimes(fd, atime, mtime, undefined, ctx)
2532 CHECK_EQ(argc, 5);
2533 FSReqWrapSync req_wrap_sync;
2534 FS_SYNC_TRACE_BEGIN(futimes);
2535 SyncCall(env, args[4], &req_wrap_sync, "futime",
2536 uv_fs_futime, fd, atime, mtime);
2537 FS_SYNC_TRACE_END(futimes);
2538 }
2539 }
2540
LUTimes(const FunctionCallbackInfo<Value> & args)2541 static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2542 Environment* env = Environment::GetCurrent(args);
2543
2544 const int argc = args.Length();
2545 CHECK_GE(argc, 3);
2546
2547 BufferValue path(env->isolate(), args[0]);
2548 CHECK_NOT_NULL(*path);
2549
2550 CHECK(args[1]->IsNumber());
2551 const double atime = args[1].As<Number>()->Value();
2552
2553 CHECK(args[2]->IsNumber());
2554 const double mtime = args[2].As<Number>()->Value();
2555
2556 FSReqBase* req_wrap_async = GetReqWrap(args, 3);
2557 if (req_wrap_async != nullptr) { // lutimes(path, atime, mtime, req)
2558 FS_ASYNC_TRACE_BEGIN1(
2559 UV_FS_LUTIME, req_wrap_async, "path", TRACE_STR_COPY(*path))
2560 AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2561 uv_fs_lutime, *path, atime, mtime);
2562 } else { // lutimes(path, atime, mtime, undefined, ctx)
2563 CHECK_EQ(argc, 5);
2564 FSReqWrapSync req_wrap_sync;
2565 FS_SYNC_TRACE_BEGIN(lutimes);
2566 SyncCall(env, args[4], &req_wrap_sync, "lutime",
2567 uv_fs_lutime, *path, atime, mtime);
2568 FS_SYNC_TRACE_END(lutimes);
2569 }
2570 }
2571
Mkdtemp(const FunctionCallbackInfo<Value> & args)2572 static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
2573 Environment* env = Environment::GetCurrent(args);
2574 Isolate* isolate = env->isolate();
2575
2576 const int argc = args.Length();
2577 CHECK_GE(argc, 2);
2578
2579 BufferValue tmpl(isolate, args[0]);
2580 CHECK_NOT_NULL(*tmpl);
2581
2582 const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8);
2583
2584 FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2585 if (req_wrap_async != nullptr) { // mkdtemp(tmpl, encoding, req)
2586 FS_ASYNC_TRACE_BEGIN1(
2587 UV_FS_MKDTEMP, req_wrap_async, "path", TRACE_STR_COPY(*tmpl))
2588 AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath,
2589 uv_fs_mkdtemp, *tmpl);
2590 } else { // mkdtemp(tmpl, encoding, undefined, ctx)
2591 CHECK_EQ(argc, 4);
2592 FSReqWrapSync req_wrap_sync;
2593 FS_SYNC_TRACE_BEGIN(mkdtemp);
2594 SyncCall(env, args[3], &req_wrap_sync, "mkdtemp",
2595 uv_fs_mkdtemp, *tmpl);
2596 FS_SYNC_TRACE_END(mkdtemp);
2597 const char* path = req_wrap_sync.req.path;
2598
2599 Local<Value> error;
2600 MaybeLocal<Value> rc =
2601 StringBytes::Encode(isolate, path, encoding, &error);
2602 if (rc.IsEmpty()) {
2603 Local<Object> ctx = args[3].As<Object>();
2604 ctx->Set(env->context(), env->error_string(), error).Check();
2605 return;
2606 }
2607 args.GetReturnValue().Set(rc.ToLocalChecked());
2608 }
2609 }
2610
MemoryInfo(MemoryTracker * tracker) const2611 void BindingData::MemoryInfo(MemoryTracker* tracker) const {
2612 tracker->TrackField("stats_field_array", stats_field_array);
2613 tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
2614 tracker->TrackField("statfs_field_array", statfs_field_array);
2615 tracker->TrackField("statfs_field_bigint_array", statfs_field_bigint_array);
2616 tracker->TrackField("file_handle_read_wrap_freelist",
2617 file_handle_read_wrap_freelist);
2618 }
2619
BindingData(Realm * realm,v8::Local<v8::Object> wrap)2620 BindingData::BindingData(Realm* realm, v8::Local<v8::Object> wrap)
2621 : SnapshotableObject(realm, wrap, type_int),
2622 stats_field_array(realm->isolate(), kFsStatsBufferLength),
2623 stats_field_bigint_array(realm->isolate(), kFsStatsBufferLength),
2624 statfs_field_array(realm->isolate(), kFsStatFsBufferLength),
2625 statfs_field_bigint_array(realm->isolate(), kFsStatFsBufferLength) {
2626 Isolate* isolate = realm->isolate();
2627 Local<Context> context = realm->context();
2628 wrap->Set(context,
2629 FIXED_ONE_BYTE_STRING(isolate, "statValues"),
2630 stats_field_array.GetJSArray())
2631 .Check();
2632
2633 wrap->Set(context,
2634 FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
2635 stats_field_bigint_array.GetJSArray())
2636 .Check();
2637
2638 wrap->Set(context,
2639 FIXED_ONE_BYTE_STRING(isolate, "statFsValues"),
2640 statfs_field_array.GetJSArray())
2641 .Check();
2642
2643 wrap->Set(context,
2644 FIXED_ONE_BYTE_STRING(isolate, "bigintStatFsValues"),
2645 statfs_field_bigint_array.GetJSArray())
2646 .Check();
2647 }
2648
Deserialize(Local<Context> context,Local<Object> holder,int index,InternalFieldInfoBase * info)2649 void BindingData::Deserialize(Local<Context> context,
2650 Local<Object> holder,
2651 int index,
2652 InternalFieldInfoBase* info) {
2653 DCHECK_EQ(index, BaseObject::kEmbedderType);
2654 HandleScope scope(context->GetIsolate());
2655 Realm* realm = Realm::GetCurrent(context);
2656 BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
2657 CHECK_NOT_NULL(binding);
2658 }
2659
PrepareForSerialization(Local<Context> context,v8::SnapshotCreator * creator)2660 bool BindingData::PrepareForSerialization(Local<Context> context,
2661 v8::SnapshotCreator* creator) {
2662 CHECK(file_handle_read_wrap_freelist.empty());
2663 // We'll just re-initialize the buffers in the constructor since their
2664 // contents can be thrown away once consumed in the previous call.
2665 stats_field_array.Release();
2666 stats_field_bigint_array.Release();
2667 statfs_field_array.Release();
2668 statfs_field_bigint_array.Release();
2669 // Return true because we need to maintain the reference to the binding from
2670 // JS land.
2671 return true;
2672 }
2673
Serialize(int index)2674 InternalFieldInfoBase* BindingData::Serialize(int index) {
2675 DCHECK_EQ(index, BaseObject::kEmbedderType);
2676 InternalFieldInfo* info =
2677 InternalFieldInfoBase::New<InternalFieldInfo>(type());
2678 return info;
2679 }
2680
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)2681 void Initialize(Local<Object> target,
2682 Local<Value> unused,
2683 Local<Context> context,
2684 void* priv) {
2685 Realm* realm = Realm::GetCurrent(context);
2686 Environment* env = realm->env();
2687 Isolate* isolate = env->isolate();
2688 BindingData* const binding_data =
2689 realm->AddBindingData<BindingData>(context, target);
2690 if (binding_data == nullptr) return;
2691
2692 SetMethod(context, target, "access", Access);
2693 SetMethod(context, target, "close", Close);
2694 SetMethod(context, target, "open", Open);
2695 SetMethod(context, target, "openFileHandle", OpenFileHandle);
2696 SetMethod(context, target, "read", Read);
2697 SetMethod(context, target, "readBuffers", ReadBuffers);
2698 SetMethod(context, target, "fdatasync", Fdatasync);
2699 SetMethod(context, target, "fsync", Fsync);
2700 SetMethod(context, target, "rename", Rename);
2701 SetMethod(context, target, "ftruncate", FTruncate);
2702 SetMethod(context, target, "rmdir", RMDir);
2703 SetMethod(context, target, "mkdir", MKDir);
2704 SetMethod(context, target, "readdir", ReadDir);
2705 SetMethod(context, target, "internalModuleReadJSON", InternalModuleReadJSON);
2706 SetMethod(context, target, "internalModuleStat", InternalModuleStat);
2707 SetMethod(context, target, "stat", Stat);
2708 SetMethod(context, target, "lstat", LStat);
2709 SetMethod(context, target, "fstat", FStat);
2710 SetMethod(context, target, "statfs", StatFs);
2711 SetMethod(context, target, "link", Link);
2712 SetMethod(context, target, "symlink", Symlink);
2713 SetMethod(context, target, "readlink", ReadLink);
2714 SetMethod(context, target, "unlink", Unlink);
2715 SetMethod(context, target, "writeBuffer", WriteBuffer);
2716 SetMethod(context, target, "writeBuffers", WriteBuffers);
2717 SetMethod(context, target, "writeString", WriteString);
2718 SetMethod(context, target, "realpath", RealPath);
2719 SetMethod(context, target, "copyFile", CopyFile);
2720
2721 SetMethod(context, target, "chmod", Chmod);
2722 SetMethod(context, target, "fchmod", FChmod);
2723
2724 SetMethod(context, target, "chown", Chown);
2725 SetMethod(context, target, "fchown", FChown);
2726 SetMethod(context, target, "lchown", LChown);
2727
2728 SetMethod(context, target, "utimes", UTimes);
2729 SetMethod(context, target, "futimes", FUTimes);
2730 SetMethod(context, target, "lutimes", LUTimes);
2731
2732 SetMethod(context, target, "mkdtemp", Mkdtemp);
2733
2734 target
2735 ->Set(context,
2736 FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
2737 Integer::New(
2738 isolate,
2739 static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
2740 .Check();
2741
2742 StatWatcher::Initialize(env, target);
2743
2744 // Create FunctionTemplate for FSReqCallback
2745 Local<FunctionTemplate> fst = NewFunctionTemplate(isolate, NewFSReqCallback);
2746 fst->InstanceTemplate()->SetInternalFieldCount(
2747 FSReqBase::kInternalFieldCount);
2748 fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
2749 SetConstructorFunction(context, target, "FSReqCallback", fst);
2750
2751 // Create FunctionTemplate for FileHandleReadWrap. There’s no need
2752 // to do anything in the constructor, so we only store the instance template.
2753 Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
2754 fh_rw->InstanceTemplate()->SetInternalFieldCount(
2755 FSReqBase::kInternalFieldCount);
2756 fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
2757 Local<String> fhWrapString =
2758 FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
2759 fh_rw->SetClassName(fhWrapString);
2760 env->set_filehandlereadwrap_template(
2761 fst->InstanceTemplate());
2762
2763 // Create Function Template for FSReqPromise
2764 Local<FunctionTemplate> fpt = FunctionTemplate::New(isolate);
2765 fpt->Inherit(AsyncWrap::GetConstructorTemplate(env));
2766 Local<String> promiseString =
2767 FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
2768 fpt->SetClassName(promiseString);
2769 Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
2770 fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2771 env->set_fsreqpromise_constructor_template(fpo);
2772
2773 // Create FunctionTemplate for FileHandle
2774 Local<FunctionTemplate> fd = NewFunctionTemplate(isolate, FileHandle::New);
2775 fd->Inherit(AsyncWrap::GetConstructorTemplate(env));
2776 SetProtoMethod(isolate, fd, "close", FileHandle::Close);
2777 SetProtoMethod(isolate, fd, "releaseFD", FileHandle::ReleaseFD);
2778 Local<ObjectTemplate> fdt = fd->InstanceTemplate();
2779 fdt->SetInternalFieldCount(FileHandle::kInternalFieldCount);
2780 StreamBase::AddMethods(env, fd);
2781 SetConstructorFunction(context, target, "FileHandle", fd);
2782 env->set_fd_constructor_template(fdt);
2783
2784 // Create FunctionTemplate for FileHandle::CloseReq
2785 Local<FunctionTemplate> fdclose = FunctionTemplate::New(isolate);
2786 fdclose->SetClassName(FIXED_ONE_BYTE_STRING(isolate,
2787 "FileHandleCloseReq"));
2788 fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
2789 Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
2790 fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
2791 env->set_fdclose_constructor_template(fdcloset);
2792
2793 target->Set(context,
2794 FIXED_ONE_BYTE_STRING(isolate, "kUsePromises"),
2795 env->fs_use_promises_symbol()).Check();
2796 }
2797
binding_data()2798 BindingData* FSReqBase::binding_data() {
2799 return binding_data_.get();
2800 }
2801
RegisterExternalReferences(ExternalReferenceRegistry * registry)2802 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2803 registry->Register(Access);
2804 StatWatcher::RegisterExternalReferences(registry);
2805
2806 registry->Register(Close);
2807 registry->Register(Open);
2808 registry->Register(OpenFileHandle);
2809 registry->Register(Read);
2810 registry->Register(ReadBuffers);
2811 registry->Register(Fdatasync);
2812 registry->Register(Fsync);
2813 registry->Register(Rename);
2814 registry->Register(FTruncate);
2815 registry->Register(RMDir);
2816 registry->Register(MKDir);
2817 registry->Register(ReadDir);
2818 registry->Register(InternalModuleReadJSON);
2819 registry->Register(InternalModuleStat);
2820 registry->Register(Stat);
2821 registry->Register(LStat);
2822 registry->Register(FStat);
2823 registry->Register(StatFs);
2824 registry->Register(Link);
2825 registry->Register(Symlink);
2826 registry->Register(ReadLink);
2827 registry->Register(Unlink);
2828 registry->Register(WriteBuffer);
2829 registry->Register(WriteBuffers);
2830 registry->Register(WriteString);
2831 registry->Register(RealPath);
2832 registry->Register(CopyFile);
2833
2834 registry->Register(Chmod);
2835 registry->Register(FChmod);
2836
2837 registry->Register(Chown);
2838 registry->Register(FChown);
2839 registry->Register(LChown);
2840
2841 registry->Register(UTimes);
2842 registry->Register(FUTimes);
2843 registry->Register(LUTimes);
2844
2845 registry->Register(Mkdtemp);
2846 registry->Register(NewFSReqCallback);
2847
2848 registry->Register(FileHandle::New);
2849 registry->Register(FileHandle::Close);
2850 registry->Register(FileHandle::ReleaseFD);
2851 StreamBase::RegisterExternalReferences(registry);
2852 }
2853
2854 } // namespace fs
2855
2856 } // end namespace node
2857
2858 NODE_BINDING_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
2859 NODE_BINDING_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)
2860