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