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