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