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