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 50namespace node { 51 52namespace fs { 53 54using v8::Array; 55using v8::BigInt; 56using v8::Boolean; 57using v8::Context; 58using v8::EscapableHandleScope; 59using v8::Function; 60using v8::FunctionCallbackInfo; 61using v8::FunctionTemplate; 62using v8::HandleScope; 63using v8::Int32; 64using v8::Integer; 65using v8::Isolate; 66using v8::Local; 67using v8::MaybeLocal; 68using v8::Number; 69using v8::Object; 70using v8::ObjectTemplate; 71using v8::Promise; 72using v8::String; 73using v8::Undefined; 74using v8::Value; 75 76#ifndef S_ISDIR 77# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 78#endif 79 80#ifdef __POSIX__ 81constexpr char kPathSeparator = '/'; 82#else 83const char* const kPathSeparator = "\\/"; 84#endif 85 86std::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 109inline int64_t GetOffset(Local<Value> value) { 110 return IsSafeJsInt(value) ? value.As<Integer>()->Value() : -1; 111} 112 113static 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. 215typedef void(*uv_fs_callback_t)(uv_fs_t*); 216 217 218void FSContinuationData::MemoryInfo(MemoryTracker* tracker) const { 219 tracker->TrackField("paths", paths_); 220} 221 222FileHandleReadWrap::~FileHandleReadWrap() = default; 223 224FSReqBase::~FSReqBase() = default; 225 226void 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.) 233FileHandle::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 243FileHandle* 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 254void 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 269FileHandle::~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 275int 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 282void FileHandle::MemoryInfo(MemoryTracker* tracker) const { 283 tracker->TrackField("current_read", current_read_); 284} 285 286FileHandle::TransferMode FileHandle::GetTransferMode() const { 287 return reading_ || closing_ || closed_ ? 288 TransferMode::kUntransferable : TransferMode::kTransferable; 289} 290 291std::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 298FileHandle::TransferData::TransferData(int fd) : fd_(fd) {} 299 300FileHandle::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 311BaseObjectPtr<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. 327inline 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 380void 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 390void 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 400FileHandle* 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 408FileHandle::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 417FileHandle::CloseReq::~CloseReq() { 418 uv_fs_req_cleanup(req()); 419 promise_.Reset(); 420 ref_.Reset(); 421} 422 423void 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. 435MaybeLocal<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 493void 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 502void 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 510void FileHandle::AfterClose() { 511 closing_ = false; 512 closed_ = true; 513 fd_ = -1; 514 if (reading_ && !persistent().IsEmpty()) 515 EmitRead(UV_EOF); 516} 517 518void FileHandleReadWrap::MemoryInfo(MemoryTracker* tracker) const { 519 tracker->TrackField("buffer", buffer_); 520 tracker->TrackField("file_handle", this->file_handle_); 521} 522 523FileHandleReadWrap::FileHandleReadWrap(FileHandle* handle, Local<Object> obj) 524 : ReqWrap(handle->env(), obj, AsyncWrap::PROVIDER_FSREQCALLBACK), 525 file_handle_(handle) {} 526 527int 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 645int FileHandle::ReadStop() { 646 reading_ = false; 647 return 0; 648} 649 650typedef SimpleShutdownWrap<ReqWrap<uv_fs_t>> FileHandleCloseWrap; 651 652ShutdownWrap* FileHandle::CreateShutdownWrap(Local<Object> object) { 653 return new FileHandleCloseWrap(this, object); 654} 655 656int 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 682void FSReqCallback::Reject(Local<Value> reject) { 683 MakeCallback(env()->oncomplete_string(), 1, &reject); 684} 685 686void FSReqCallback::ResolveStat(const uv_stat_t* stat) { 687 Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat)); 688} 689 690void FSReqCallback::ResolveStatFs(const uv_statfs_t* stat) { 691 Resolve(FillGlobalStatFsArray(binding_data(), use_bigint(), stat)); 692} 693 694void 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 704void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) { 705 args.GetReturnValue().SetUndefined(); 706} 707 708void 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 714FSReqAfterScope::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 722FSReqAfterScope::~FSReqAfterScope() { 723 Clear(); 724} 725 726void 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. 743void 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 755bool 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 767void 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 776void 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 786void 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 796void 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 809void 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. 824void 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 835void 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 856void 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 876void 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 896void 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 945void 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 975void 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] 1001static 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. 1098static 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 1115static 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 1148static 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 1182static 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 1214static 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 1256static 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 1291static 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 1324static 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 1369static 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 1402static 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 1429static 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 1452static 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 1475static 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 1499static 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 1524int 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 1592int 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 1687int 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 1706static 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 1757static 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 1803static 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 1895static 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 1929static 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 1968static 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 2015static 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 2070static 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 2117static 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 */ 2220static 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 2276static 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 */ 2319static 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 */ 2351static 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 */ 2382static 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 */ 2417static 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 2448static 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 2480static 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 2511static 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 2541static 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 2572static 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 2611void 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 2620BindingData::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 2649void 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 2660bool 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 2674InternalFieldInfoBase* BindingData::Serialize(int index) { 2675 DCHECK_EQ(index, BaseObject::kEmbedderType); 2676 InternalFieldInfo* info = 2677 InternalFieldInfoBase::New<InternalFieldInfo>(type()); 2678 return info; 2679} 2680 2681void 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 2798BindingData* FSReqBase::binding_data() { 2799 return binding_data_.get(); 2800} 2801 2802void 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 2858NODE_BINDING_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize) 2859NODE_BINDING_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences) 2860