Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_file.cc
Go to the documentation of this file.
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "node.h"
23 #include "node_buffer.h"
24 #include "node_internals.h"
25 #include "node_stat_watcher.h"
26 
27 #include "env.h"
28 #include "env-inl.h"
29 #include "req-wrap.h"
30 #include "req-wrap-inl.h"
31 #include "string_bytes.h"
32 #include "util.h"
33 
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <limits.h>
40 
41 #if defined(__MINGW32__) || defined(_MSC_VER)
42 # include <io.h>
43 #endif
44 
45 #include <vector>
46 
47 namespace node {
48 namespace {
49 
50 using v8::Array;
51 using v8::ArrayBuffer;
52 using v8::Context;
53 using v8::Float64Array;
54 using v8::Function;
55 using v8::FunctionCallbackInfo;
56 using v8::FunctionTemplate;
57 using v8::HandleScope;
58 using v8::Integer;
59 using v8::Local;
60 using v8::MaybeLocal;
61 using v8::Number;
62 using v8::Object;
63 using v8::String;
64 using v8::Value;
65 
66 #ifndef MIN
67 # define MIN(a, b) ((a) < (b) ? (a) : (b))
68 #endif
69 
70 #define TYPE_ERROR(msg) env->ThrowTypeError(msg)
71 
72 #define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
73 
74 class FSReqWrap: public ReqWrap<uv_fs_t> {
75  public:
76  enum Ownership { COPY, MOVE };
77 
78  inline static FSReqWrap* New(Environment* env,
79  Local<Object> req,
80  const char* syscall,
81  const char* data = nullptr,
82  enum encoding encoding = UTF8,
83  Ownership ownership = COPY);
84 
85  inline void Dispose();
86 
87  void ReleaseEarly() {
88  if (data_ != inline_data()) {
89  delete[] data_;
90  data_ = nullptr;
91  }
92  }
93 
94  const char* syscall() const { return syscall_; }
95  const char* data() const { return data_; }
96  const enum encoding encoding_;
97 
98  size_t self_size() const override { return sizeof(*this); }
99 
100  private:
101  FSReqWrap(Environment* env,
102  Local<Object> req,
103  const char* syscall,
104  const char* data,
105  enum encoding encoding)
106  : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
107  encoding_(encoding),
108  syscall_(syscall),
109  data_(data) {
110  Wrap(object(), this);
111  }
112 
113  ~FSReqWrap() {
114  ReleaseEarly();
115  ClearWrap(object());
116  }
117 
118  void* operator new(size_t size) = delete;
119  void* operator new(size_t size, char* storage) { return storage; }
120  char* inline_data() { return reinterpret_cast<char*>(this + 1); }
121 
122  const char* syscall_;
123  const char* data_;
124 
125  DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
126 };
127 
128 #define ASSERT_PATH(path) \
129  if (*path == nullptr) \
130  return TYPE_ERROR( #path " must be a string or Buffer");
131 
132 FSReqWrap* FSReqWrap::New(Environment* env,
133  Local<Object> req,
134  const char* syscall,
135  const char* data,
136  enum encoding encoding,
137  Ownership ownership) {
138  const bool copy = (data != nullptr && ownership == COPY);
139  const size_t size = copy ? 1 + strlen(data) : 0;
140  FSReqWrap* that;
141  char* const storage = new char[sizeof(*that) + size];
142  that = new(storage) FSReqWrap(env, req, syscall, data, encoding);
143  if (copy)
144  that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
145  return that;
146 }
147 
148 
149 void FSReqWrap::Dispose() {
150  this->~FSReqWrap();
151  delete[] reinterpret_cast<char*>(this);
152 }
153 
154 
155 void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
156  CHECK(args.IsConstructCall());
157  ClearWrap(args.This());
158 }
159 
160 
161 inline bool IsInt64(double x) {
162  return x == static_cast<double>(static_cast<int64_t>(x));
163 }
164 
165 void After(uv_fs_t *req) {
166  FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
167  CHECK_EQ(req_wrap->req(), req);
168  req_wrap->ReleaseEarly(); // Free memory that's no longer used now.
169 
170  Environment* env = req_wrap->env();
171  HandleScope handle_scope(env->isolate());
172  Context::Scope context_scope(env->context());
173 
174  // there is always at least one argument. "error"
175  int argc = 1;
176 
177  // Allocate space for two args. We may only use one depending on the case.
178  // (Feel free to increase this if you need more)
179  Local<Value> argv[2];
180  MaybeLocal<Value> link;
181  Local<Value> error;
182 
183  if (req->result < 0) {
184  // An error happened.
185  argv[0] = UVException(env->isolate(),
186  req->result,
187  req_wrap->syscall(),
188  nullptr,
189  req->path,
190  req_wrap->data());
191  } else {
192  // error value is empty or null for non-error.
193  argv[0] = Null(env->isolate());
194 
195  // All have at least two args now.
196  argc = 2;
197 
198  switch (req->fs_type) {
199  // These all have no data to pass.
200  case UV_FS_ACCESS:
201  case UV_FS_CLOSE:
202  case UV_FS_RENAME:
203  case UV_FS_UNLINK:
204  case UV_FS_RMDIR:
205  case UV_FS_MKDIR:
206  case UV_FS_FTRUNCATE:
207  case UV_FS_FSYNC:
208  case UV_FS_FDATASYNC:
209  case UV_FS_LINK:
210  case UV_FS_SYMLINK:
211  case UV_FS_CHMOD:
212  case UV_FS_FCHMOD:
213  case UV_FS_CHOWN:
214  case UV_FS_FCHOWN:
215  case UV_FS_COPYFILE:
216  // These, however, don't.
217  argc = 1;
218  break;
219 
220  case UV_FS_STAT:
221  case UV_FS_LSTAT:
222  case UV_FS_FSTAT:
223  argc = 1;
224  FillStatsArray(env->fs_stats_field_array(),
225  static_cast<const uv_stat_t*>(req->ptr));
226  break;
227 
228  case UV_FS_UTIME:
229  case UV_FS_FUTIME:
230  argc = 0;
231  break;
232 
233  case UV_FS_OPEN:
234  argv[1] = Integer::New(env->isolate(), req->result);
235  break;
236 
237  case UV_FS_WRITE:
238  argv[1] = Integer::New(env->isolate(), req->result);
239  break;
240 
241  case UV_FS_MKDTEMP:
242  {
243  link = StringBytes::Encode(env->isolate(),
244  static_cast<const char*>(req->path),
245  req_wrap->encoding_,
246  &error);
247  if (link.IsEmpty()) {
248  // TODO(addaleax): Use `error` itself here.
249  argv[0] = UVException(env->isolate(),
250  UV_EINVAL,
251  req_wrap->syscall(),
252  "Invalid character encoding for filename",
253  req->path,
254  req_wrap->data());
255  } else {
256  argv[1] = link.ToLocalChecked();
257  }
258  break;
259  }
260 
261  case UV_FS_READLINK:
262  link = StringBytes::Encode(env->isolate(),
263  static_cast<const char*>(req->ptr),
264  req_wrap->encoding_,
265  &error);
266  if (link.IsEmpty()) {
267  // TODO(addaleax): Use `error` itself here.
268  argv[0] = UVException(env->isolate(),
269  UV_EINVAL,
270  req_wrap->syscall(),
271  "Invalid character encoding for link",
272  req->path,
273  req_wrap->data());
274  } else {
275  argv[1] = link.ToLocalChecked();
276  }
277  break;
278 
279  case UV_FS_REALPATH:
280  link = StringBytes::Encode(env->isolate(),
281  static_cast<const char*>(req->ptr),
282  req_wrap->encoding_,
283  &error);
284  if (link.IsEmpty()) {
285  // TODO(addaleax): Use `error` itself here.
286  argv[0] = UVException(env->isolate(),
287  UV_EINVAL,
288  req_wrap->syscall(),
289  "Invalid character encoding for link",
290  req->path,
291  req_wrap->data());
292  } else {
293  argv[1] = link.ToLocalChecked();
294  }
295  break;
296 
297  case UV_FS_READ:
298  // Buffer interface
299  argv[1] = Integer::New(env->isolate(), req->result);
300  break;
301 
302  case UV_FS_SCANDIR:
303  {
304  int r;
305  Local<Array> names = Array::New(env->isolate(), 0);
306  Local<Function> fn = env->push_values_to_array_function();
307  Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
308  size_t name_idx = 0;
309 
310  for (int i = 0; ; i++) {
311  uv_dirent_t ent;
312 
313  r = uv_fs_scandir_next(req, &ent);
314  if (r == UV_EOF)
315  break;
316  if (r != 0) {
317  argv[0] = UVException(r,
318  nullptr,
319  req_wrap->syscall(),
320  static_cast<const char*>(req->path));
321  break;
322  }
323 
324  MaybeLocal<Value> filename =
325  StringBytes::Encode(env->isolate(),
326  ent.name,
327  req_wrap->encoding_,
328  &error);
329  if (filename.IsEmpty()) {
330  // TODO(addaleax): Use `error` itself here.
331  argv[0] = UVException(env->isolate(),
332  UV_EINVAL,
333  req_wrap->syscall(),
334  "Invalid character encoding for filename",
335  req->path,
336  req_wrap->data());
337  break;
338  }
339  name_argv[name_idx++] = filename.ToLocalChecked();
340 
341  if (name_idx >= arraysize(name_argv)) {
342  fn->Call(env->context(), names, name_idx, name_argv)
343  .ToLocalChecked();
344  name_idx = 0;
345  }
346  }
347 
348  if (name_idx > 0) {
349  fn->Call(env->context(), names, name_idx, name_argv)
350  .ToLocalChecked();
351  }
352 
353  argv[1] = names;
354  }
355  break;
356 
357  default:
358  CHECK(0 && "Unhandled eio response");
359  }
360  }
361 
362  req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
363 
364  uv_fs_req_cleanup(req_wrap->req());
365  req_wrap->Dispose();
366 }
367 
368 // This struct is only used on sync fs calls.
369 // For async calls FSReqWrap is used.
370 class fs_req_wrap {
371  public:
372  fs_req_wrap() {}
373  ~fs_req_wrap() { uv_fs_req_cleanup(&req); }
374  uv_fs_t req;
375 
376  private:
377  DISALLOW_COPY_AND_ASSIGN(fs_req_wrap);
378 };
379 
380 
381 #define ASYNC_DEST_CALL(func, request, dest, encoding, ...) \
382  Environment* env = Environment::GetCurrent(args); \
383  CHECK(request->IsObject()); \
384  FSReqWrap* req_wrap = FSReqWrap::New(env, request.As<Object>(), \
385  #func, dest, encoding); \
386  int err = uv_fs_ ## func(env->event_loop(), \
387  req_wrap->req(), \
388  __VA_ARGS__, \
389  After); \
390  req_wrap->Dispatched(); \
391  if (err < 0) { \
392  uv_fs_t* uv_req = req_wrap->req(); \
393  uv_req->result = err; \
394  uv_req->path = nullptr; \
395  After(uv_req); \
396  req_wrap = nullptr; \
397  } else { \
398  args.GetReturnValue().Set(req_wrap->persistent()); \
399  }
400 
401 #define ASYNC_CALL(func, req, encoding, ...) \
402  ASYNC_DEST_CALL(func, req, nullptr, encoding, __VA_ARGS__) \
403 
404 #define SYNC_DEST_CALL(func, path, dest, ...) \
405  fs_req_wrap req_wrap; \
406  env->PrintSyncTrace(); \
407  int err = uv_fs_ ## func(env->event_loop(), \
408  &req_wrap.req, \
409  __VA_ARGS__, \
410  nullptr); \
411  if (err < 0) { \
412  return env->ThrowUVException(err, #func, nullptr, path, dest); \
413  } \
414 
415 #define SYNC_CALL(func, path, ...) \
416  SYNC_DEST_CALL(func, path, nullptr, __VA_ARGS__) \
417 
418 #define SYNC_REQ req_wrap.req
419 
420 #define SYNC_RESULT err
421 
422 void Access(const FunctionCallbackInfo<Value>& args) {
423  Environment* env = Environment::GetCurrent(args.GetIsolate());
424  HandleScope scope(env->isolate());
425 
426  if (args.Length() < 2)
427  return TYPE_ERROR("path and mode are required");
428  if (!args[1]->IsInt32())
429  return TYPE_ERROR("mode must be an integer");
430 
431  BufferValue path(env->isolate(), args[0]);
432  ASSERT_PATH(path)
433 
434  int mode = static_cast<int>(args[1]->Int32Value());
435 
436  if (args[2]->IsObject()) {
437  ASYNC_CALL(access, args[2], UTF8, *path, mode);
438  } else {
439  SYNC_CALL(access, *path, *path, mode);
440  }
441 }
442 
443 
444 void Close(const FunctionCallbackInfo<Value>& args) {
445  Environment* env = Environment::GetCurrent(args);
446 
447  if (args.Length() < 1)
448  return TYPE_ERROR("fd is required");
449  if (!args[0]->IsInt32())
450  return TYPE_ERROR("fd must be a file descriptor");
451 
452  int fd = args[0]->Int32Value();
453 
454  if (args[1]->IsObject()) {
455  ASYNC_CALL(close, args[1], UTF8, fd)
456  } else {
457  SYNC_CALL(close, 0, fd)
458  }
459 }
460 
461 } // anonymous namespace
462 
463 void FillStatsArray(double* fields, const uv_stat_t* s) {
464  fields[0] = s->st_dev;
465  fields[1] = s->st_mode;
466  fields[2] = s->st_nlink;
467  fields[3] = s->st_uid;
468  fields[4] = s->st_gid;
469  fields[5] = s->st_rdev;
470 #if defined(__POSIX__)
471  fields[6] = s->st_blksize;
472 #else
473  fields[6] = -1;
474 #endif
475  fields[7] = s->st_ino;
476  fields[8] = s->st_size;
477 #if defined(__POSIX__)
478  fields[9] = s->st_blocks;
479 #else
480  fields[9] = -1;
481 #endif
482 // Dates.
483 // NO-LINT because the fields are 'long' and we just want to cast to `unsigned`
484 #define X(idx, name) \
485  /* NOLINTNEXTLINE(runtime/int) */ \
486  fields[idx] = ((unsigned long)(s->st_##name.tv_sec) * 1e3) + \
487  /* NOLINTNEXTLINE(runtime/int) */ \
488  ((unsigned long)(s->st_##name.tv_nsec) / 1e6); \
489 
490  X(10, atim)
491  X(11, mtim)
492  X(12, ctim)
493  X(13, birthtim)
494 #undef X
495 }
496 
497 // Used to speed up module loading. Returns the contents of the file as
498 // a string or undefined when the file cannot be opened. The speedup
499 // comes from not creating Error objects on failure.
500 static void InternalModuleReadFile(const FunctionCallbackInfo<Value>& args) {
501  Environment* env = Environment::GetCurrent(args);
502  uv_loop_t* loop = env->event_loop();
503 
504  CHECK(args[0]->IsString());
505  node::Utf8Value path(env->isolate(), args[0]);
506 
507  if (strlen(*path) != path.length())
508  return; // Contains a nul byte.
509 
510  uv_fs_t open_req;
511  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
512  uv_fs_req_cleanup(&open_req);
513 
514  if (fd < 0) {
515  return;
516  }
517 
518  const size_t kBlockSize = 32 << 10;
519  std::vector<char> chars;
520  int64_t offset = 0;
521  ssize_t numchars;
522  do {
523  const size_t start = chars.size();
524  chars.resize(start + kBlockSize);
525 
526  uv_buf_t buf;
527  buf.base = &chars[start];
528  buf.len = kBlockSize;
529 
530  uv_fs_t read_req;
531  numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
532  uv_fs_req_cleanup(&read_req);
533 
534  CHECK_GE(numchars, 0);
535  offset += numchars;
536  } while (static_cast<size_t>(numchars) == kBlockSize);
537 
538  uv_fs_t close_req;
539  CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
540  uv_fs_req_cleanup(&close_req);
541 
542  size_t start = 0;
543  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
544  start = 3; // Skip UTF-8 BOM.
545  }
546 
547  Local<String> chars_string =
548  String::NewFromUtf8(env->isolate(),
549  &chars[start],
550  String::kNormalString,
551  offset - start);
552  args.GetReturnValue().Set(chars_string);
553 }
554 
555 // Used to speed up module loading. Returns 0 if the path refers to
556 // a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
557 // The speedup comes from not creating thousands of Stat and Error objects.
558 static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
559  Environment* env = Environment::GetCurrent(args);
560 
561  CHECK(args[0]->IsString());
562  node::Utf8Value path(env->isolate(), args[0]);
563 
564  uv_fs_t req;
565  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
566  if (rc == 0) {
567  const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
568  rc = !!(s->st_mode & S_IFDIR);
569  }
570  uv_fs_req_cleanup(&req);
571 
572  args.GetReturnValue().Set(rc);
573 }
574 
575 static void Stat(const FunctionCallbackInfo<Value>& args) {
576  Environment* env = Environment::GetCurrent(args);
577 
578  if (args.Length() < 1)
579  return TYPE_ERROR("path required");
580 
581  BufferValue path(env->isolate(), args[0]);
582  ASSERT_PATH(path)
583 
584  if (args[1]->IsObject()) {
585  ASYNC_CALL(stat, args[1], UTF8, *path)
586  } else {
587  SYNC_CALL(stat, *path, *path)
588  FillStatsArray(env->fs_stats_field_array(),
589  static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
590  }
591 }
592 
593 static void LStat(const FunctionCallbackInfo<Value>& args) {
594  Environment* env = Environment::GetCurrent(args);
595 
596  if (args.Length() < 1)
597  return TYPE_ERROR("path required");
598 
599  BufferValue path(env->isolate(), args[0]);
600  ASSERT_PATH(path)
601 
602  if (args[1]->IsObject()) {
603  ASYNC_CALL(lstat, args[1], UTF8, *path)
604  } else {
605  SYNC_CALL(lstat, *path, *path)
606  FillStatsArray(env->fs_stats_field_array(),
607  static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
608  }
609 }
610 
611 static void FStat(const FunctionCallbackInfo<Value>& args) {
612  Environment* env = Environment::GetCurrent(args);
613 
614  if (args.Length() < 1)
615  return TYPE_ERROR("fd is required");
616  if (!args[0]->IsInt32())
617  return TYPE_ERROR("fd must be a file descriptor");
618 
619  int fd = args[0]->Int32Value();
620 
621  if (args[1]->IsObject()) {
622  ASYNC_CALL(fstat, args[1], UTF8, fd)
623  } else {
624  SYNC_CALL(fstat, nullptr, fd)
625  FillStatsArray(env->fs_stats_field_array(),
626  static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
627  }
628 }
629 
630 static void Symlink(const FunctionCallbackInfo<Value>& args) {
631  Environment* env = Environment::GetCurrent(args);
632 
633  int len = args.Length();
634  if (len < 1)
635  return TYPE_ERROR("target path required");
636  if (len < 2)
637  return TYPE_ERROR("src path required");
638 
639  BufferValue target(env->isolate(), args[0]);
640  ASSERT_PATH(target)
641  BufferValue path(env->isolate(), args[1]);
642  ASSERT_PATH(path)
643 
644  int flags = 0;
645 
646  if (args[2]->IsString()) {
647  node::Utf8Value mode(env->isolate(), args[2]);
648  if (strcmp(*mode, "dir") == 0) {
649  flags |= UV_FS_SYMLINK_DIR;
650  } else if (strcmp(*mode, "junction") == 0) {
651  flags |= UV_FS_SYMLINK_JUNCTION;
652  } else if (strcmp(*mode, "file") != 0) {
653  return env->ThrowError("Unknown symlink type");
654  }
655  }
656 
657  if (args[3]->IsObject()) {
658  ASYNC_DEST_CALL(symlink, args[3], *path, UTF8, *target, *path, flags)
659  } else {
660  SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
661  }
662 }
663 
664 static void Link(const FunctionCallbackInfo<Value>& args) {
665  Environment* env = Environment::GetCurrent(args);
666 
667  int len = args.Length();
668  if (len < 1)
669  return TYPE_ERROR("src path required");
670  if (len < 2)
671  return TYPE_ERROR("dest path required");
672 
673  BufferValue src(env->isolate(), args[0]);
674  ASSERT_PATH(src)
675 
676  BufferValue dest(env->isolate(), args[1]);
677  ASSERT_PATH(dest)
678 
679  if (args[2]->IsObject()) {
680  ASYNC_DEST_CALL(link, args[2], *dest, UTF8, *src, *dest)
681  } else {
682  SYNC_DEST_CALL(link, *src, *dest, *src, *dest)
683  }
684 }
685 
686 static void ReadLink(const FunctionCallbackInfo<Value>& args) {
687  Environment* env = Environment::GetCurrent(args);
688 
689  const int argc = args.Length();
690 
691  if (argc < 1)
692  return TYPE_ERROR("path required");
693 
694  BufferValue path(env->isolate(), args[0]);
695  ASSERT_PATH(path)
696 
697  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
698 
699  Local<Value> callback = Null(env->isolate());
700  if (argc == 3)
701  callback = args[2];
702 
703  if (callback->IsObject()) {
704  ASYNC_CALL(readlink, callback, encoding, *path)
705  } else {
706  SYNC_CALL(readlink, *path, *path)
707  const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
708 
709  Local<Value> error;
710  MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
711  link_path,
712  encoding,
713  &error);
714  if (rc.IsEmpty()) {
715  // TODO(addaleax): Use `error` itself here.
716  return env->ThrowUVException(UV_EINVAL,
717  "readlink",
718  "Invalid character encoding for link",
719  *path);
720  }
721  args.GetReturnValue().Set(rc.ToLocalChecked());
722  }
723 }
724 
725 static void Rename(const FunctionCallbackInfo<Value>& args) {
726  Environment* env = Environment::GetCurrent(args);
727 
728  int len = args.Length();
729  if (len < 1)
730  return TYPE_ERROR("old path required");
731  if (len < 2)
732  return TYPE_ERROR("new path required");
733 
734  BufferValue old_path(env->isolate(), args[0]);
735  ASSERT_PATH(old_path)
736  BufferValue new_path(env->isolate(), args[1]);
737  ASSERT_PATH(new_path)
738 
739  if (args[2]->IsObject()) {
740  ASYNC_DEST_CALL(rename, args[2], *new_path, UTF8, *old_path, *new_path)
741  } else {
742  SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
743  }
744 }
745 
746 static void FTruncate(const FunctionCallbackInfo<Value>& args) {
747  Environment* env = Environment::GetCurrent(args);
748 
749  if (args.Length() < 2)
750  return TYPE_ERROR("fd and length are required");
751  if (!args[0]->IsInt32())
752  return TYPE_ERROR("fd must be a file descriptor");
753 
754  int fd = args[0]->Int32Value();
755 
756  // FIXME(bnoordhuis) It's questionable to reject non-ints here but still
757  // allow implicit coercion from null or undefined to zero. Probably best
758  // handled in lib/fs.js.
759  Local<Value> len_v(args[1]);
760  if (!len_v->IsUndefined() &&
761  !len_v->IsNull() &&
762  !IsInt64(len_v->NumberValue())) {
763  return env->ThrowTypeError("Not an integer");
764  }
765 
766  const int64_t len = len_v->IntegerValue();
767 
768  if (args[2]->IsObject()) {
769  ASYNC_CALL(ftruncate, args[2], UTF8, fd, len)
770  } else {
771  SYNC_CALL(ftruncate, 0, fd, len)
772  }
773 }
774 
775 static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
776  Environment* env = Environment::GetCurrent(args);
777 
778  if (args.Length() < 1)
779  return TYPE_ERROR("fd is required");
780  if (!args[0]->IsInt32())
781  return TYPE_ERROR("fd must be a file descriptor");
782 
783  int fd = args[0]->Int32Value();
784 
785  if (args[1]->IsObject()) {
786  ASYNC_CALL(fdatasync, args[1], UTF8, fd)
787  } else {
788  SYNC_CALL(fdatasync, 0, fd)
789  }
790 }
791 
792 static void Fsync(const FunctionCallbackInfo<Value>& args) {
793  Environment* env = Environment::GetCurrent(args);
794 
795  if (args.Length() < 1)
796  return TYPE_ERROR("fd is required");
797  if (!args[0]->IsInt32())
798  return TYPE_ERROR("fd must be a file descriptor");
799 
800  int fd = args[0]->Int32Value();
801 
802  if (args[1]->IsObject()) {
803  ASYNC_CALL(fsync, args[1], UTF8, fd)
804  } else {
805  SYNC_CALL(fsync, 0, fd)
806  }
807 }
808 
809 static void Unlink(const FunctionCallbackInfo<Value>& args) {
810  Environment* env = Environment::GetCurrent(args);
811 
812  if (args.Length() < 1)
813  return TYPE_ERROR("path required");
814 
815  BufferValue path(env->isolate(), args[0]);
816  ASSERT_PATH(path)
817 
818  if (args[1]->IsObject()) {
819  ASYNC_CALL(unlink, args[1], UTF8, *path)
820  } else {
821  SYNC_CALL(unlink, *path, *path)
822  }
823 }
824 
825 static void RMDir(const FunctionCallbackInfo<Value>& args) {
826  Environment* env = Environment::GetCurrent(args);
827 
828  if (args.Length() < 1)
829  return TYPE_ERROR("path required");
830 
831  BufferValue path(env->isolate(), args[0]);
832  ASSERT_PATH(path)
833 
834  if (args[1]->IsObject()) {
835  ASYNC_CALL(rmdir, args[1], UTF8, *path)
836  } else {
837  SYNC_CALL(rmdir, *path, *path)
838  }
839 }
840 
841 static void MKDir(const FunctionCallbackInfo<Value>& args) {
842  Environment* env = Environment::GetCurrent(args);
843 
844  if (args.Length() < 2)
845  return TYPE_ERROR("path and mode are required");
846  if (!args[1]->IsInt32())
847  return TYPE_ERROR("mode must be an integer");
848 
849  BufferValue path(env->isolate(), args[0]);
850  ASSERT_PATH(path)
851 
852  int mode = static_cast<int>(args[1]->Int32Value());
853 
854  if (args[2]->IsObject()) {
855  ASYNC_CALL(mkdir, args[2], UTF8, *path, mode)
856  } else {
857  SYNC_CALL(mkdir, *path, *path, mode)
858  }
859 }
860 
861 static void RealPath(const FunctionCallbackInfo<Value>& args) {
862  Environment* env = Environment::GetCurrent(args);
863 
864  const int argc = args.Length();
865 
866  if (argc < 1)
867  return TYPE_ERROR("path required");
868 
869  BufferValue path(env->isolate(), args[0]);
870  ASSERT_PATH(path)
871 
872  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
873 
874  Local<Value> callback = Null(env->isolate());
875  if (argc == 3)
876  callback = args[2];
877 
878  if (callback->IsObject()) {
879  ASYNC_CALL(realpath, callback, encoding, *path);
880  } else {
881  SYNC_CALL(realpath, *path, *path);
882  const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
883 
884  Local<Value> error;
885  MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
886  link_path,
887  encoding,
888  &error);
889  if (rc.IsEmpty()) {
890  // TODO(addaleax): Use `error` itself here.
891  return env->ThrowUVException(UV_EINVAL,
892  "realpath",
893  "Invalid character encoding for path",
894  *path);
895  }
896  args.GetReturnValue().Set(rc.ToLocalChecked());
897  }
898 }
899 
900 static void ReadDir(const FunctionCallbackInfo<Value>& args) {
901  Environment* env = Environment::GetCurrent(args);
902 
903  const int argc = args.Length();
904 
905  if (argc < 1)
906  return TYPE_ERROR("path required");
907 
908  BufferValue path(env->isolate(), args[0]);
909  ASSERT_PATH(path)
910 
911  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
912 
913  Local<Value> callback = Null(env->isolate());
914  if (argc == 3)
915  callback = args[2];
916 
917  if (callback->IsObject()) {
918  ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/)
919  } else {
920  SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
921 
922  CHECK_GE(SYNC_REQ.result, 0);
923  int r;
924  Local<Array> names = Array::New(env->isolate(), 0);
925  Local<Function> fn = env->push_values_to_array_function();
926  Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
927  size_t name_idx = 0;
928 
929  for (int i = 0; ; i++) {
930  uv_dirent_t ent;
931 
932  r = uv_fs_scandir_next(&SYNC_REQ, &ent);
933  if (r == UV_EOF)
934  break;
935  if (r != 0)
936  return env->ThrowUVException(r, "readdir", "", *path);
937 
938  Local<Value> error;
939  MaybeLocal<Value> filename = StringBytes::Encode(env->isolate(),
940  ent.name,
941  encoding,
942  &error);
943  if (filename.IsEmpty()) {
944  // TODO(addaleax): Use `error` itself here.
945  return env->ThrowUVException(UV_EINVAL,
946  "readdir",
947  "Invalid character encoding for filename",
948  *path);
949  }
950 
951  name_v[name_idx++] = filename.ToLocalChecked();
952 
953  if (name_idx >= arraysize(name_v)) {
954  fn->Call(env->context(), names, name_idx, name_v)
955  .ToLocalChecked();
956  name_idx = 0;
957  }
958  }
959 
960  if (name_idx > 0) {
961  fn->Call(env->context(), names, name_idx, name_v).ToLocalChecked();
962  }
963 
964  args.GetReturnValue().Set(names);
965  }
966 }
967 
968 static void Open(const FunctionCallbackInfo<Value>& args) {
969  Environment* env = Environment::GetCurrent(args);
970 
971  int len = args.Length();
972  if (len < 1)
973  return TYPE_ERROR("path required");
974  if (len < 2)
975  return TYPE_ERROR("flags required");
976  if (len < 3)
977  return TYPE_ERROR("mode required");
978  if (!args[1]->IsInt32())
979  return TYPE_ERROR("flags must be an int");
980  if (!args[2]->IsInt32())
981  return TYPE_ERROR("mode must be an int");
982 
983  BufferValue path(env->isolate(), args[0]);
984  ASSERT_PATH(path)
985 
986  int flags = args[1]->Int32Value();
987  int mode = static_cast<int>(args[2]->Int32Value());
988 
989  if (args[3]->IsObject()) {
990  ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
991  } else {
992  SYNC_CALL(open, *path, *path, flags, mode)
993  args.GetReturnValue().Set(SYNC_RESULT);
994  }
995 }
996 
997 
998 static void CopyFile(const FunctionCallbackInfo<Value>& args) {
999  Environment* env = Environment::GetCurrent(args);
1000 
1001  if (!args[0]->IsString())
1002  return TYPE_ERROR("src must be a string");
1003  if (!args[1]->IsString())
1004  return TYPE_ERROR("dest must be a string");
1005  if (!args[2]->IsInt32())
1006  return TYPE_ERROR("flags must be an int");
1007 
1008  BufferValue src(env->isolate(), args[0]);
1009  ASSERT_PATH(src)
1010  BufferValue dest(env->isolate(), args[1]);
1011  ASSERT_PATH(dest)
1012  int flags = args[2]->Int32Value();
1013 
1014  if (args[3]->IsObject()) {
1015  ASYNC_DEST_CALL(copyfile, args[3], *dest, UTF8, *src, *dest, flags)
1016  } else {
1017  SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
1018  }
1019 }
1020 
1021 
1022 // Wrapper for write(2).
1023 //
1024 // bytesWritten = write(fd, buffer, offset, length, position, callback)
1025 // 0 fd integer. file descriptor
1026 // 1 buffer the data to write
1027 // 2 offset where in the buffer to start from
1028 // 3 length how much to write
1029 // 4 position if integer, position to write at in the file.
1030 // if null, write from the current position
1031 static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1032  Environment* env = Environment::GetCurrent(args);
1033 
1034  if (!args[0]->IsInt32())
1035  return env->ThrowTypeError("First argument must be file descriptor");
1036 
1037  CHECK(Buffer::HasInstance(args[1]));
1038 
1039  int fd = args[0]->Int32Value();
1040  Local<Object> obj = args[1].As<Object>();
1041  const char* buf = Buffer::Data(obj);
1042  size_t buffer_length = Buffer::Length(obj);
1043  size_t off = args[2]->Uint32Value();
1044  size_t len = args[3]->Uint32Value();
1045  int64_t pos = GET_OFFSET(args[4]);
1046  Local<Value> req = args[5];
1047 
1048  if (off > buffer_length)
1049  return env->ThrowRangeError("offset out of bounds");
1050  if (len > buffer_length)
1051  return env->ThrowRangeError("length out of bounds");
1052  if (off + len < off)
1053  return env->ThrowRangeError("off + len overflow");
1054  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1055  return env->ThrowRangeError("off + len > buffer.length");
1056 
1057  buf += off;
1058 
1059  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1060 
1061  if (req->IsObject()) {
1062  ASYNC_CALL(write, req, UTF8, fd, &uvbuf, 1, pos)
1063  return;
1064  }
1065 
1066  SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1067  args.GetReturnValue().Set(SYNC_RESULT);
1068 }
1069 
1070 
1071 // Wrapper for writev(2).
1072 //
1073 // bytesWritten = writev(fd, chunks, position, callback)
1074 // 0 fd integer. file descriptor
1075 // 1 chunks array of buffers to write
1076 // 2 position if integer, position to write at in the file.
1077 // if null, write from the current position
1078 static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1079  Environment* env = Environment::GetCurrent(args);
1080 
1081  CHECK(args[0]->IsInt32());
1082  CHECK(args[1]->IsArray());
1083 
1084  int fd = args[0]->Int32Value();
1085  Local<Array> chunks = args[1].As<Array>();
1086  int64_t pos = GET_OFFSET(args[2]);
1087  Local<Value> req = args[3];
1088 
1089  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1090 
1091  for (uint32_t i = 0; i < iovs.length(); i++) {
1092  Local<Value> chunk = chunks->Get(i);
1093 
1094  if (!Buffer::HasInstance(chunk))
1095  return env->ThrowTypeError("Array elements all need to be buffers");
1096 
1097  iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1098  }
1099 
1100  if (req->IsObject()) {
1101  ASYNC_CALL(write, req, UTF8, fd, *iovs, iovs.length(), pos)
1102  return;
1103  }
1104 
1105  SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
1106  args.GetReturnValue().Set(SYNC_RESULT);
1107 }
1108 
1109 
1110 // Wrapper for write(2).
1111 //
1112 // bytesWritten = write(fd, string, position, enc, callback)
1113 // 0 fd integer. file descriptor
1114 // 1 string non-buffer values are converted to strings
1115 // 2 position if integer, position to write at in the file.
1116 // if null, write from the current position
1117 // 3 enc encoding of string
1118 static void WriteString(const FunctionCallbackInfo<Value>& args) {
1119  Environment* env = Environment::GetCurrent(args);
1120 
1121  if (!args[0]->IsInt32())
1122  return env->ThrowTypeError("First argument must be file descriptor");
1123 
1124  Local<Value> req;
1125  Local<Value> string = args[1];
1126  int fd = args[0]->Int32Value();
1127  char* buf = nullptr;
1128  int64_t pos;
1129  size_t len;
1130  FSReqWrap::Ownership ownership = FSReqWrap::COPY;
1131 
1132  // will assign buf and len if string was external
1133  if (!StringBytes::GetExternalParts(string,
1134  const_cast<const char**>(&buf),
1135  &len)) {
1136  enum encoding enc = ParseEncoding(env->isolate(), args[3], UTF8);
1137  len = StringBytes::StorageSize(env->isolate(), string, enc);
1138  buf = new char[len];
1139  // StorageSize may return too large a char, so correct the actual length
1140  // by the write size
1141  len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
1142  ownership = FSReqWrap::MOVE;
1143  }
1144  pos = GET_OFFSET(args[2]);
1145  req = args[4];
1146 
1147  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1148 
1149  if (!req->IsObject()) {
1150  // SYNC_CALL returns on error. Make sure to always free the memory.
1151  struct Delete {
1152  inline explicit Delete(char* pointer) : pointer_(pointer) {}
1153  inline ~Delete() { delete[] pointer_; }
1154  char* const pointer_;
1155  };
1156  Delete delete_on_return(ownership == FSReqWrap::MOVE ? buf : nullptr);
1157  SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1158  return args.GetReturnValue().Set(SYNC_RESULT);
1159  }
1160 
1161  FSReqWrap* req_wrap =
1162  FSReqWrap::New(env, req.As<Object>(), "write", buf, UTF8, ownership);
1163  int err = uv_fs_write(env->event_loop(),
1164  req_wrap->req(),
1165  fd,
1166  &uvbuf,
1167  1,
1168  pos,
1169  After);
1170  req_wrap->Dispatched();
1171  if (err < 0) {
1172  uv_fs_t* uv_req = req_wrap->req();
1173  uv_req->result = err;
1174  uv_req->path = nullptr;
1175  After(uv_req);
1176  return;
1177  }
1178 
1179  return args.GetReturnValue().Set(req_wrap->persistent());
1180 }
1181 
1182 
1183 /*
1184  * Wrapper for read(2).
1185  *
1186  * bytesRead = fs.read(fd, buffer, offset, length, position)
1187  *
1188  * 0 fd integer. file descriptor
1189  * 1 buffer instance of Buffer
1190  * 2 offset integer. offset to start reading into inside buffer
1191  * 3 length integer. length to read
1192  * 4 position file position - null for current position
1193  *
1194  */
1195 static void Read(const FunctionCallbackInfo<Value>& args) {
1196  Environment* env = Environment::GetCurrent(args);
1197 
1198  if (args.Length() < 2)
1199  return TYPE_ERROR("fd and buffer are required");
1200  if (!args[0]->IsInt32())
1201  return TYPE_ERROR("fd must be a file descriptor");
1202  if (!Buffer::HasInstance(args[1]))
1203  return TYPE_ERROR("Second argument needs to be a buffer");
1204 
1205  int fd = args[0]->Int32Value();
1206 
1207  Local<Value> req;
1208 
1209  size_t len;
1210  int64_t pos;
1211 
1212  char * buf = nullptr;
1213 
1214  Local<Object> buffer_obj = args[1]->ToObject(env->isolate());
1215  char *buffer_data = Buffer::Data(buffer_obj);
1216  size_t buffer_length = Buffer::Length(buffer_obj);
1217 
1218  size_t off = args[2]->Int32Value();
1219  if (off >= buffer_length) {
1220  return env->ThrowError("Offset is out of bounds");
1221  }
1222 
1223  len = args[3]->Int32Value();
1224  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1225  return env->ThrowRangeError("Length extends beyond buffer");
1226 
1227  pos = GET_OFFSET(args[4]);
1228 
1229  buf = buffer_data + off;
1230 
1231  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1232 
1233  req = args[5];
1234 
1235  if (req->IsObject()) {
1236  ASYNC_CALL(read, req, UTF8, fd, &uvbuf, 1, pos);
1237  } else {
1238  SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
1239  args.GetReturnValue().Set(SYNC_RESULT);
1240  }
1241 }
1242 
1243 
1244 /* fs.chmod(path, mode);
1245  * Wrapper for chmod(1) / EIO_CHMOD
1246  */
1247 static void Chmod(const FunctionCallbackInfo<Value>& args) {
1248  Environment* env = Environment::GetCurrent(args);
1249 
1250  if (args.Length() < 2)
1251  return TYPE_ERROR("path and mode are required");
1252  if (!args[1]->IsInt32())
1253  return TYPE_ERROR("mode must be an integer");
1254 
1255  BufferValue path(env->isolate(), args[0]);
1256  ASSERT_PATH(path)
1257 
1258  int mode = static_cast<int>(args[1]->Int32Value());
1259 
1260  if (args[2]->IsObject()) {
1261  ASYNC_CALL(chmod, args[2], UTF8, *path, mode);
1262  } else {
1263  SYNC_CALL(chmod, *path, *path, mode);
1264  }
1265 }
1266 
1267 
1268 /* fs.fchmod(fd, mode);
1269  * Wrapper for fchmod(1) / EIO_FCHMOD
1270  */
1271 static void FChmod(const FunctionCallbackInfo<Value>& args) {
1272  Environment* env = Environment::GetCurrent(args);
1273 
1274  if (args.Length() < 2)
1275  return TYPE_ERROR("fd and mode are required");
1276  if (!args[0]->IsInt32())
1277  return TYPE_ERROR("fd must be a file descriptor");
1278  if (!args[1]->IsInt32())
1279  return TYPE_ERROR("mode must be an integer");
1280 
1281  int fd = args[0]->Int32Value();
1282  int mode = static_cast<int>(args[1]->Int32Value());
1283 
1284  if (args[2]->IsObject()) {
1285  ASYNC_CALL(fchmod, args[2], UTF8, fd, mode);
1286  } else {
1287  SYNC_CALL(fchmod, 0, fd, mode);
1288  }
1289 }
1290 
1291 
1292 /* fs.chown(path, uid, gid);
1293  * Wrapper for chown(1) / EIO_CHOWN
1294  */
1295 static void Chown(const FunctionCallbackInfo<Value>& args) {
1296  Environment* env = Environment::GetCurrent(args);
1297 
1298  int len = args.Length();
1299  if (len < 1)
1300  return TYPE_ERROR("path required");
1301  if (len < 2)
1302  return TYPE_ERROR("uid required");
1303  if (len < 3)
1304  return TYPE_ERROR("gid required");
1305  if (!args[1]->IsUint32())
1306  return TYPE_ERROR("uid must be an unsigned int");
1307  if (!args[2]->IsUint32())
1308  return TYPE_ERROR("gid must be an unsigned int");
1309 
1310  BufferValue path(env->isolate(), args[0]);
1311  ASSERT_PATH(path)
1312 
1313  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1314  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1315 
1316  if (args[3]->IsObject()) {
1317  ASYNC_CALL(chown, args[3], UTF8, *path, uid, gid);
1318  } else {
1319  SYNC_CALL(chown, *path, *path, uid, gid);
1320  }
1321 }
1322 
1323 
1324 /* fs.fchown(fd, uid, gid);
1325  * Wrapper for fchown(1) / EIO_FCHOWN
1326  */
1327 static void FChown(const FunctionCallbackInfo<Value>& args) {
1328  Environment* env = Environment::GetCurrent(args);
1329 
1330  int len = args.Length();
1331  if (len < 1)
1332  return TYPE_ERROR("fd required");
1333  if (len < 2)
1334  return TYPE_ERROR("uid required");
1335  if (len < 3)
1336  return TYPE_ERROR("gid required");
1337  if (!args[0]->IsInt32())
1338  return TYPE_ERROR("fd must be an int");
1339  if (!args[1]->IsUint32())
1340  return TYPE_ERROR("uid must be an unsigned int");
1341  if (!args[2]->IsUint32())
1342  return TYPE_ERROR("gid must be an unsigned int");
1343 
1344  int fd = args[0]->Int32Value();
1345  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1346  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1347 
1348  if (args[3]->IsObject()) {
1349  ASYNC_CALL(fchown, args[3], UTF8, fd, uid, gid);
1350  } else {
1351  SYNC_CALL(fchown, 0, fd, uid, gid);
1352  }
1353 }
1354 
1355 
1356 static void UTimes(const FunctionCallbackInfo<Value>& args) {
1357  Environment* env = Environment::GetCurrent(args);
1358 
1359  int len = args.Length();
1360  if (len < 1)
1361  return TYPE_ERROR("path required");
1362  if (len < 2)
1363  return TYPE_ERROR("atime required");
1364  if (len < 3)
1365  return TYPE_ERROR("mtime required");
1366  if (!args[1]->IsNumber())
1367  return TYPE_ERROR("atime must be a number");
1368  if (!args[2]->IsNumber())
1369  return TYPE_ERROR("mtime must be a number");
1370 
1371  BufferValue path(env->isolate(), args[0]);
1372  ASSERT_PATH(path)
1373 
1374  const double atime = static_cast<double>(args[1]->NumberValue());
1375  const double mtime = static_cast<double>(args[2]->NumberValue());
1376 
1377  if (args[3]->IsObject()) {
1378  ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime);
1379  } else {
1380  SYNC_CALL(utime, *path, *path, atime, mtime);
1381  }
1382 }
1383 
1384 static void FUTimes(const FunctionCallbackInfo<Value>& args) {
1385  Environment* env = Environment::GetCurrent(args);
1386 
1387  int len = args.Length();
1388  if (len < 1)
1389  return TYPE_ERROR("fd required");
1390  if (len < 2)
1391  return TYPE_ERROR("atime required");
1392  if (len < 3)
1393  return TYPE_ERROR("mtime required");
1394  if (!args[0]->IsInt32())
1395  return TYPE_ERROR("fd must be an int");
1396  if (!args[1]->IsNumber())
1397  return TYPE_ERROR("atime must be a number");
1398  if (!args[2]->IsNumber())
1399  return TYPE_ERROR("mtime must be a number");
1400 
1401  const int fd = args[0]->Int32Value();
1402  const double atime = static_cast<double>(args[1]->NumberValue());
1403  const double mtime = static_cast<double>(args[2]->NumberValue());
1404 
1405  if (args[3]->IsObject()) {
1406  ASYNC_CALL(futime, args[3], UTF8, fd, atime, mtime);
1407  } else {
1408  SYNC_CALL(futime, 0, fd, atime, mtime);
1409  }
1410 }
1411 
1412 static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
1413  Environment* env = Environment::GetCurrent(args);
1414 
1415  CHECK_GE(args.Length(), 2);
1416 
1417  BufferValue tmpl(env->isolate(), args[0]);
1418  if (*tmpl == nullptr)
1419  return TYPE_ERROR("template must be a string or Buffer");
1420 
1421  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
1422 
1423  if (args[2]->IsObject()) {
1424  ASYNC_CALL(mkdtemp, args[2], encoding, *tmpl);
1425  } else {
1426  SYNC_CALL(mkdtemp, *tmpl, *tmpl);
1427  const char* path = static_cast<const char*>(SYNC_REQ.path);
1428 
1429  Local<Value> error;
1430  MaybeLocal<Value> rc =
1431  StringBytes::Encode(env->isolate(), path, encoding, &error);
1432  if (rc.IsEmpty()) {
1433  // TODO(addaleax): Use `error` itself here.
1434  return env->ThrowUVException(UV_EINVAL,
1435  "mkdtemp",
1436  "Invalid character encoding for filename",
1437  *tmpl);
1438  }
1439  args.GetReturnValue().Set(rc.ToLocalChecked());
1440  }
1441 }
1442 
1443 void GetStatValues(const FunctionCallbackInfo<Value>& args) {
1444  Environment* env = Environment::GetCurrent(args);
1445  double* fields = env->fs_stats_field_array();
1446  if (fields == nullptr) {
1447  // stat fields contains twice the number of entries because `fs.StatWatcher`
1448  // needs room to store data for *two* `fs.Stats` instances.
1449  fields = new double[2 * 14];
1450  env->set_fs_stats_field_array(fields);
1451  }
1452  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(),
1453  fields,
1454  sizeof(double) * 2 * 14);
1455  Local<Float64Array> fields_array = Float64Array::New(ab, 0, 2 * 14);
1456  args.GetReturnValue().Set(fields_array);
1457 }
1458 
1459 void InitFs(Local<Object> target,
1460  Local<Value> unused,
1461  Local<Context> context,
1462  void* priv) {
1463  Environment* env = Environment::GetCurrent(context);
1464 
1465  env->SetMethod(target, "access", Access);
1466  env->SetMethod(target, "close", Close);
1467  env->SetMethod(target, "open", Open);
1468  env->SetMethod(target, "read", Read);
1469  env->SetMethod(target, "fdatasync", Fdatasync);
1470  env->SetMethod(target, "fsync", Fsync);
1471  env->SetMethod(target, "rename", Rename);
1472  env->SetMethod(target, "ftruncate", FTruncate);
1473  env->SetMethod(target, "rmdir", RMDir);
1474  env->SetMethod(target, "mkdir", MKDir);
1475  env->SetMethod(target, "readdir", ReadDir);
1476  env->SetMethod(target, "internalModuleReadFile", InternalModuleReadFile);
1477  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
1478  env->SetMethod(target, "stat", Stat);
1479  env->SetMethod(target, "lstat", LStat);
1480  env->SetMethod(target, "fstat", FStat);
1481  env->SetMethod(target, "link", Link);
1482  env->SetMethod(target, "symlink", Symlink);
1483  env->SetMethod(target, "readlink", ReadLink);
1484  env->SetMethod(target, "unlink", Unlink);
1485  env->SetMethod(target, "writeBuffer", WriteBuffer);
1486  env->SetMethod(target, "writeBuffers", WriteBuffers);
1487  env->SetMethod(target, "writeString", WriteString);
1488  env->SetMethod(target, "realpath", RealPath);
1489  env->SetMethod(target, "copyFile", CopyFile);
1490 
1491  env->SetMethod(target, "chmod", Chmod);
1492  env->SetMethod(target, "fchmod", FChmod);
1493  // env->SetMethod(target, "lchmod", LChmod);
1494 
1495  env->SetMethod(target, "chown", Chown);
1496  env->SetMethod(target, "fchown", FChown);
1497  // env->SetMethod(target, "lchown", LChown);
1498 
1499  env->SetMethod(target, "utimes", UTimes);
1500  env->SetMethod(target, "futimes", FUTimes);
1501 
1502  env->SetMethod(target, "mkdtemp", Mkdtemp);
1503 
1504  env->SetMethod(target, "getStatValues", GetStatValues);
1505 
1506  StatWatcher::Initialize(env, target);
1507 
1508  // Create FunctionTemplate for FSReqWrap
1509  Local<FunctionTemplate> fst =
1510  FunctionTemplate::New(env->isolate(), NewFSReqWrap);
1511  fst->InstanceTemplate()->SetInternalFieldCount(1);
1512  AsyncWrap::AddWrapMethods(env, fst);
1513  Local<String> wrapString =
1514  FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap");
1515  fst->SetClassName(wrapString);
1516  target->Set(wrapString, fst->GetFunction());
1517 }
1518 
1519 } // end namespace node
1520 
#define SYNC_CALL(func, path,...)
Definition: node_file.cc:415
#define SYNC_DEST_CALL(func, path, dest,...)
Definition: node_file.cc:404
#define GET_OFFSET(a)
Definition: node_file.cc:72
#define ASYNC_CALL(func, req, encoding,...)
Definition: node_file.cc:401
bool HasInstance(Local< Value > val)
Definition: node_buffer.cc:201
unsigned char * buf
Definition: cares_wrap.cc:483
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
#define SYNC_RESULT
Definition: node_file.cc:420
#define ASSERT_PATH(path)
Definition: node_file.cc:128
int len
Definition: cares_wrap.cc:485
void GetStatValues(const FunctionCallbackInfo< Value > &args)
Definition: node_file.cc:1443
union node::cares_wrap::@8::CaresAsyncData::@0 data
X(SetTTL, uv_udp_set_ttl) X(SetBroadcast
size_t Length(Local< Value > val)
Definition: node_buffer.cc:227
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
Definition: node_http2.cc:1172
encoding
Definition: node.h:322
char * Data(Local< Value > val)
Definition: node_buffer.cc:211
void FillStatsArray(double *fields, const uv_stat_t *s)
Definition: node_file.cc:463
dtrace s
Definition: v8ustack.d:615
#define SYNC_REQ
Definition: node_file.cc:418
enum encoding ParseEncoding(const char *encoding, enum encoding default_encoding)
Definition: node.cc:1485
#define ASYNC_DEST_CALL(func, request, dest, encoding,...)
Definition: node_file.cc:381
uv_fs_t req
Definition: node_file.cc:374
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
void InitFs(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
Definition: node_file.cc:1459
enum encoding encoding_
Definition: node_file.cc:96
NODE_DEPRECATED("Use ParseEncoding(isolate, ...)", inline enum encoding ParseEncoding(v8::Local< v8::Value > encoding_v, enum encoding default_encoding=LATIN1) { return ParseEncoding(v8::Isolate::GetCurrent(), encoding_v, default_encoding);}) NODE_EXTERN void FatalException(v8 NODE_DEPRECATED("Use FatalException(isolate, ...)", inline void FatalException(const v8::TryCatch &try_catch) { return FatalException(v8::Isolate::GetCurrent(), try_catch);}) NODE_EXTERN v8 NODE_EXTERN v8::Local< v8::Value > Encode(v8::Isolate *isolate, const uint16_t *buf, size_t len)
Definition: node.h:350
#define TYPE_ERROR(msg)
Definition: node_file.cc:70
Local< Value > UVException(Isolate *isolate, int errorno, const char *syscall, const char *msg, const char *path)
Definition: node.cc:940
this off
Definition: v8ustack.d:365