GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/node_file.cc Lines: 582 646 90.1 %
Date: 2016-11-30 Branches: 344 583 59.0 %

Line Branch Exec Source
1
#include "node.h"
2
#include "node_file.h"
3
#include "node_buffer.h"
4
#include "node_internals.h"
5
#include "node_stat_watcher.h"
6
7
#include "env.h"
8
#include "env-inl.h"
9
#include "req-wrap.h"
10
#include "req-wrap-inl.h"
11
#include "string_bytes.h"
12
#include "util.h"
13
14
#include <fcntl.h>
15
#include <sys/types.h>
16
#include <sys/stat.h>
17
#include <string.h>
18
#include <errno.h>
19
#include <limits.h>
20
21
#if defined(__MINGW32__) || defined(_MSC_VER)
22
# include <io.h>
23
#endif
24
25
#include <vector>
26
27
namespace node {
28
29
using v8::Array;
30
using v8::Context;
31
using v8::EscapableHandleScope;
32
using v8::Function;
33
using v8::FunctionCallbackInfo;
34
using v8::FunctionTemplate;
35
using v8::HandleScope;
36
using v8::Integer;
37
using v8::Local;
38
using v8::Number;
39
using v8::Object;
40
using v8::String;
41
using v8::Value;
42
43
#ifndef MIN
44
# define MIN(a, b) ((a) < (b) ? (a) : (b))
45
#endif
46
47
#define TYPE_ERROR(msg) env->ThrowTypeError(msg)
48
49
#define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
50
51
class FSReqWrap: public ReqWrap<uv_fs_t> {
52
 public:
53
  enum Ownership { COPY, MOVE };
54
55
  inline static FSReqWrap* New(Environment* env,
56
                               Local<Object> req,
57
                               const char* syscall,
58
                               const char* data = nullptr,
59
                               enum encoding encoding = UTF8,
60
                               Ownership ownership = COPY);
61
62
  inline void Dispose();
63
64
  void ReleaseEarly() {
65

55332
    if (data_ != inline_data()) {
66

27638
      delete[] data_;
67
27638
      data_ = nullptr;
68
    }
69
  }
70
71
  const char* syscall() const { return syscall_; }
72
  const char* data() const { return data_; }
73
  const enum encoding encoding_;
74
75
  size_t self_size() const override { return sizeof(*this); }
76
77
 private:
78
13834
  FSReqWrap(Environment* env,
79
            Local<Object> req,
80
            const char* syscall,
81
            const char* data,
82
            enum encoding encoding)
83
      : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
84
        encoding_(encoding),
85
        syscall_(syscall),
86
13834
        data_(data) {
87
27668
    Wrap(object(), this);
88
13834
  }
89
90
27664
  ~FSReqWrap() { ReleaseEarly(); }
91
92
  void* operator new(size_t size) = delete;
93
  void* operator new(size_t size, char* storage) { return storage; }
94
27680
  char* inline_data() { return reinterpret_cast<char*>(this + 1); }
95
96
  const char* syscall_;
97
  const char* data_;
98
99
  DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
100
};
101
102
#define ASSERT_PATH(path)                                                   \
103
  if (*path == nullptr)                                                     \
104
    return TYPE_ERROR( #path " must be a string or Buffer");
105
106
13834
FSReqWrap* FSReqWrap::New(Environment* env,
107
                          Local<Object> req,
108
                          const char* syscall,
109
                          const char* data,
110
                          enum encoding encoding,
111
                          Ownership ownership) {
112
13834
  const bool copy = (data != nullptr && ownership == COPY);
113
13834
  const size_t size = copy ? 1 + strlen(data) : 0;
114
  FSReqWrap* that;
115
13834
  char* const storage = new char[sizeof(*that) + size];
116
13834
  that = new(storage) FSReqWrap(env, req, syscall, data, encoding);
117
13834
  if (copy)
118
28
    that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
119
13834
  return that;
120
}
121
122
123
13832
void FSReqWrap::Dispose() {
124
13832
  this->~FSReqWrap();
125
13832
  delete[] reinterpret_cast<char*>(this);
126
13832
}
127
128
129
13843
static void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
130
13843
  CHECK(args.IsConstructCall());
131
13843
}
132
133
134
static inline bool IsInt64(double x) {
135
15
  return x == static_cast<double>(static_cast<int64_t>(x));
136
}
137
138
13834
static void After(uv_fs_t *req) {
139
13834
  FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
140
27668
  CHECK_EQ(req_wrap->req(), req);
141
13834
  req_wrap->ReleaseEarly();  // Free memory that's no longer used now.
142
143
13834
  Environment* env = req_wrap->env();
144
27666
  HandleScope handle_scope(env->isolate());
145
41500
  Context::Scope context_scope(env->context());
146
147
  // there is always at least one argument. "error"
148
13834
  int argc = 1;
149
150
  // Allocate space for two args. We may only use one depending on the case.
151
  // (Feel free to increase this if you need more)
152
69170
  Local<Value> argv[2];
153
13834
  Local<Value> link;
154
155
13834
  if (req->result < 0) {
156
    // An error happened.
157
    argv[0] = UVException(env->isolate(),
158
                          req->result,
159
                          req_wrap->syscall(),
160
                          nullptr,
161
                          req->path,
162
426
                          req_wrap->data());
163
  } else {
164
    // error value is empty or null for non-error.
165
40224
    argv[0] = Null(env->isolate());
166
167
    // All have at least two args now.
168
13408
    argc = 2;
169
170


13408
    switch (req->fs_type) {
171
      // These all have no data to pass.
172
      case UV_FS_ACCESS:
173
      case UV_FS_CLOSE:
174
      case UV_FS_RENAME:
175
      case UV_FS_UNLINK:
176
      case UV_FS_RMDIR:
177
      case UV_FS_MKDIR:
178
      case UV_FS_FTRUNCATE:
179
      case UV_FS_FSYNC:
180
      case UV_FS_FDATASYNC:
181
      case UV_FS_LINK:
182
      case UV_FS_SYMLINK:
183
      case UV_FS_CHMOD:
184
      case UV_FS_FCHMOD:
185
      case UV_FS_CHOWN:
186
      case UV_FS_FCHOWN:
187
        // These, however, don't.
188
        argc = 1;
189
        break;
190
191
      case UV_FS_UTIME:
192
      case UV_FS_FUTIME:
193
14
        argc = 0;
194
14
        break;
195
196
      case UV_FS_OPEN:
197
756
        argv[1] = Integer::New(env->isolate(), req->result);
198
378
        break;
199
200
      case UV_FS_WRITE:
201
20698
        argv[1] = Integer::New(env->isolate(), req->result);
202
10349
        break;
203
204
      case UV_FS_STAT:
205
      case UV_FS_LSTAT:
206
      case UV_FS_FSTAT:
207
        argv[1] = BuildStatsObject(env,
208
1039
                                   static_cast<const uv_stat_t*>(req->ptr));
209
1039
        break;
210
211
      case UV_FS_MKDTEMP:
212
        link = StringBytes::Encode(env->isolate(),
213
5
                                   static_cast<const char*>(req->path),
214
10
                                   req_wrap->encoding_);
215
5
        if (link.IsEmpty()) {
216
          argv[0] = UVException(env->isolate(),
217
                                UV_EINVAL,
218
                                req_wrap->syscall(),
219
                                "Invalid character encoding for filename",
220
                                req->path,
221
                                req_wrap->data());
222
        } else {
223
5
          argv[1] = link;
224
        }
225
        break;
226
227
      case UV_FS_READLINK:
228
        link = StringBytes::Encode(env->isolate(),
229
24
                                   static_cast<const char*>(req->ptr),
230
48
                                   req_wrap->encoding_);
231
24
        if (link.IsEmpty()) {
232
          argv[0] = UVException(env->isolate(),
233
                                UV_EINVAL,
234
                                req_wrap->syscall(),
235
                                "Invalid character encoding for link",
236
                                req->path,
237
                                req_wrap->data());
238
        } else {
239
24
          argv[1] = link;
240
        }
241
        break;
242
243
      case UV_FS_REALPATH:
244
        link = StringBytes::Encode(env->isolate(),
245
                                   static_cast<const char*>(req->ptr),
246
                                   req_wrap->encoding_);
247
        if (link.IsEmpty()) {
248
          argv[0] = UVException(env->isolate(),
249
                                UV_EINVAL,
250
                                req_wrap->syscall(),
251
                                "Invalid character encoding for link",
252
                                req->path,
253
                                req_wrap->data());
254
        } else {
255
          argv[1] = link;
256
        }
257
        break;
258
259
      case UV_FS_READ:
260
        // Buffer interface
261
920
        argv[1] = Integer::New(env->isolate(), req->result);
262
460
        break;
263
264
      case UV_FS_SCANDIR:
265
        {
266
          int r;
267
222
          Local<Array> names = Array::New(env->isolate(), 0);
268
222
          Local<Function> fn = env->push_values_to_array_function();
269
3774
          Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
270
          size_t name_idx = 0;
271
272
3106
          for (int i = 0; ; i++) {
273
            uv_dirent_t ent;
274
275
3328
            r = uv_fs_scandir_next(req, &ent);
276
3328
            if (r == UV_EOF)
277
              break;
278
3106
            if (r != 0) {
279
              argv[0] = UVException(r,
280
                                    nullptr,
281
                                    req_wrap->syscall(),
282
                                    static_cast<const char*>(req->path));
283
              break;
284
            }
285
286
            Local<Value> filename = StringBytes::Encode(env->isolate(),
287
                                                        ent.name,
288
3106
                                                        req_wrap->encoding_);
289
3106
            if (filename.IsEmpty()) {
290
              argv[0] = UVException(env->isolate(),
291
                                    UV_EINVAL,
292
                                    req_wrap->syscall(),
293
                                    "Invalid character encoding for filename",
294
                                    req->path,
295
                                    req_wrap->data());
296
              break;
297
            }
298
3106
            name_argv[name_idx++] = filename;
299
300
3106
            if (name_idx >= arraysize(name_argv)) {
301
1320
              fn->Call(env->context(), names, name_idx, name_argv)
302
330
                  .ToLocalChecked();
303
330
              name_idx = 0;
304
            }
305
          }
306
307
222
          if (name_idx > 0) {
308
868
            fn->Call(env->context(), names, name_idx, name_argv)
309
217
                .ToLocalChecked();
310
          }
311
312
222
          argv[1] = names;
313
        }
314
222
        break;
315
316
      default:
317
        CHECK(0 && "Unhandled eio response");
318
    }
319
  }
320
321
13834
  req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
322
323
13832
  uv_fs_req_cleanup(req_wrap->req());
324
13832
  req_wrap->Dispose();
325
13832
}
326
327
// This struct is only used on sync fs calls.
328
// For async calls FSReqWrap is used.
329
class fs_req_wrap {
330
 public:
331
  fs_req_wrap() {}
332
144685
  ~fs_req_wrap() { uv_fs_req_cleanup(&req); }
333
  uv_fs_t req;
334
335
 private:
336
  DISALLOW_COPY_AND_ASSIGN(fs_req_wrap);
337
};
338
339
340
#define ASYNC_DEST_CALL(func, request, dest, encoding, ...)                   \
341
  Environment* env = Environment::GetCurrent(args);                           \
342
  CHECK(request->IsObject());                                                 \
343
  FSReqWrap* req_wrap = FSReqWrap::New(env, request.As<Object>(),             \
344
                                       #func, dest, encoding);                \
345
  int err = uv_fs_ ## func(env->event_loop(),                                 \
346
                           req_wrap->req(),                                   \
347
                           __VA_ARGS__,                                       \
348
                           After);                                            \
349
  req_wrap->Dispatched();                                                     \
350
  if (err < 0) {                                                              \
351
    uv_fs_t* uv_req = req_wrap->req();                                        \
352
    uv_req->result = err;                                                     \
353
    uv_req->path = nullptr;                                                   \
354
    After(uv_req);                                                            \
355
    req_wrap = nullptr;                                                       \
356
  } else {                                                                    \
357
    args.GetReturnValue().Set(req_wrap->persistent());                        \
358
  }
359
360
#define ASYNC_CALL(func, req, encoding, ...)                                  \
361
  ASYNC_DEST_CALL(func, req, nullptr, encoding, __VA_ARGS__)                  \
362
363
#define SYNC_DEST_CALL(func, path, dest, ...)                                 \
364
  fs_req_wrap req_wrap;                                                       \
365
  env->PrintSyncTrace();                                                      \
366
  int err = uv_fs_ ## func(env->event_loop(),                                 \
367
                         &req_wrap.req,                                       \
368
                         __VA_ARGS__,                                         \
369
                         nullptr);                                            \
370
  if (err < 0) {                                                              \
371
    return env->ThrowUVException(err, #func, nullptr, path, dest);            \
372
  }                                                                           \
373
374
#define SYNC_CALL(func, path, ...)                                            \
375
  SYNC_DEST_CALL(func, path, nullptr, __VA_ARGS__)                            \
376
377
#define SYNC_REQ req_wrap.req
378
379
#define SYNC_RESULT err
380
381
141
static void Access(const FunctionCallbackInfo<Value>& args) {
382
282
  Environment* env = Environment::GetCurrent(args.GetIsolate());
383
260
  HandleScope scope(env->isolate());
384
385
141
  if (args.Length() < 2)
386
22
    return TYPE_ERROR("path and mode are required");
387
141
  if (!args[1]->IsInt32())
388
    return TYPE_ERROR("mode must be an integer");
389
390
260
  BufferValue path(env->isolate(), args[0]);
391
141
  ASSERT_PATH(path)
392
393
139
  int mode = static_cast<int>(args[1]->Int32Value());
394
395
139
  if (args[2]->IsObject()) {
396

704
    ASYNC_CALL(access, args[2], UTF8, *path, mode);
397
  } else {
398
153
    SYNC_CALL(access, *path, *path, mode);
399
  }
400
}
401
402
403
10944
static void Close(const FunctionCallbackInfo<Value>& args) {
404
10944
  Environment* env = Environment::GetCurrent(args);
405
406
10944
  if (args.Length() < 1)
407
    return TYPE_ERROR("fd is required");
408
10944
  if (!args[0]->IsInt32())
409
    return TYPE_ERROR("fd must be a file descriptor");
410
411
10944
  int fd = args[0]->Int32Value();
412
413
10944
  if (args[1]->IsObject()) {
414

2608
    ASYNC_CALL(close, args[1], UTF8, fd)
415
  } else {
416
31854
    SYNC_CALL(close, 0, fd)
417
  }
418
}
419
420
421
97768
Local<Value> BuildStatsObject(Environment* env, const uv_stat_t* s) {
422
195536
  EscapableHandleScope handle_scope(env->isolate());
423
424
  // If you hit this assertion, you forgot to enter the v8::Context first.
425
293304
  CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
426
427
  // The code below is very nasty-looking but it prevents a segmentation fault
428
  // when people run JS code like the snippet below. It's apparently more
429
  // common than you would expect, several people have reported this crash...
430
  //
431
  //   function crash() {
432
  //     fs.statSync('.');
433
  //     crash();
434
  //   }
435
  //
436
  // We need to check the return value of Number::New() and Date::New()
437
  // and make sure that we bail out when V8 returns an empty handle.
438
439
  // Unsigned integers. It does not actually seem to be specified whether
440
  // uid and gid are unsigned or not, but in practice they are unsigned,
441
  // and Node’s (F)Chown functions do check their arguments for unsignedness.
442
#define X(name)                                                               \
443
  Local<Value> name = Integer::NewFromUnsigned(env->isolate(), s->st_##name); \
444
  if (name.IsEmpty())                                                         \
445
    return Local<Object>();                                                   \
446
447
195536
  X(uid)
448
195536
  X(gid)
449
# if defined(__POSIX__)
450
195536
  X(blksize)
451
# else
452
  Local<Value> blksize = Undefined(env->isolate());
453
# endif
454
#undef X
455
456
  // Integers.
457
#define X(name)                                                               \
458
  Local<Value> name = Integer::New(env->isolate(), s->st_##name);             \
459
  if (name.IsEmpty())                                                         \
460
    return Local<Object>();                                                   \
461
462
195536
  X(dev)
463
195536
  X(mode)
464
195536
  X(nlink)
465
195536
  X(rdev)
466
#undef X
467
468
  // Numbers.
469
#define X(name)                                                               \
470
  Local<Value> name = Number::New(env->isolate(),                             \
471
                                  static_cast<double>(s->st_##name));         \
472
  if (name.IsEmpty())                                                         \
473
    return Local<Object>();                                                   \
474
475
195536
  X(ino)
476
195536
  X(size)
477
# if defined(__POSIX__)
478
195536
  X(blocks)
479
# else
480
  Local<Value> blocks = Undefined(env->isolate());
481
# endif
482
#undef X
483
484
  // Dates.
485
#define X(name)                                                               \
486
  Local<Value> name##_msec =                                                  \
487
    Number::New(env->isolate(),                                               \
488
        (static_cast<double>(s->st_##name.tv_sec) * 1000) +                   \
489
        (static_cast<double>(s->st_##name.tv_nsec / 1000000)));               \
490
                                                                              \
491
  if (name##_msec.IsEmpty())                                                  \
492
    return Local<Object>();                                                   \
493
494
195536
  X(atim)
495
195536
  X(mtim)
496
195536
  X(ctim)
497
195536
  X(birthtim)
498
#undef X
499
500
  // Pass stats as the first argument, this is the object we are modifying.
501
  Local<Value> argv[] = {
502
    dev,
503
    mode,
504
    nlink,
505
    uid,
506
    gid,
507
    rdev,
508
    blksize,
509
    ino,
510
    size,
511
    blocks,
512
    atim_msec,
513
    mtim_msec,
514
    ctim_msec,
515
    birthtim_msec
516
97768
  };
517
518
  // Call out to JavaScript to create the stats object.
519
  Local<Value> stats =
520
293304
      env->fs_stats_constructor_function()->NewInstance(
521
          env->context(),
522
97768
          arraysize(argv),
523
586608
          argv).FromMaybe(Local<Value>());
524
525
97768
  if (stats.IsEmpty())
526
3
    return handle_scope.Escape(Local<Object>());
527
528
  return handle_scope.Escape(stats);
529
}
530
531
// Used to speed up module loading.  Returns the contents of the file as
532
// a string or undefined when the file cannot be opened.  The speedup
533
// comes from not creating Error objects on failure.
534
1798
static void InternalModuleReadFile(const FunctionCallbackInfo<Value>& args) {
535
1798
  Environment* env = Environment::GetCurrent(args);
536
1798
  uv_loop_t* loop = env->event_loop();
537
538
3596
  CHECK(args[0]->IsString());
539
3487
  node::Utf8Value path(env->isolate(), args[0]);
540
541
  uv_fs_t open_req;
542
1798
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
543
1798
  uv_fs_req_cleanup(&open_req);
544
545
1798
  if (fd < 0) {
546
109
    return;
547
  }
548
549
1689
  const size_t kBlockSize = 32 << 10;
550
3378
  std::vector<char> chars;
551
1689
  int64_t offset = 0;
552
  ssize_t numchars;
553
  do {
554
3378
    const size_t start = chars.size();
555
1689
    chars.resize(start + kBlockSize);
556
557
    uv_buf_t buf;
558
3378
    buf.base = &chars[start];
559
1689
    buf.len = kBlockSize;
560
561
    uv_fs_t read_req;
562
1689
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
563
1689
    uv_fs_req_cleanup(&read_req);
564
565
1689
    CHECK_GE(numchars, 0);
566
1689
    offset += numchars;
567
1689
  } while (static_cast<size_t>(numchars) == kBlockSize);
568
569
  uv_fs_t close_req;
570
1689
  CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
571
1689
  uv_fs_req_cleanup(&close_req);
572
573
1689
  size_t start = 0;
574

1689
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
575
    start = 3;  // Skip UTF-8 BOM.
576
  }
577
578
  Local<String> chars_string =
579
      String::NewFromUtf8(env->isolate(),
580
3378
                          &chars[start],
581
                          String::kNormalString,
582
3378
                          offset - start);
583
3378
  args.GetReturnValue().Set(chars_string);
584
}
585
586
// Used to speed up module loading.  Returns 0 if the path refers to
587
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
588
// The speedup comes from not creating thousands of Stat and Error objects.
589
20556
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
590
20556
  Environment* env = Environment::GetCurrent(args);
591
592
41112
  CHECK(args[0]->IsString());
593
41112
  node::Utf8Value path(env->isolate(), args[0]);
594
595
  uv_fs_t req;
596
41112
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
597
20556
  if (rc == 0) {
598
12459
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
599
12459
    rc = !!(s->st_mode & S_IFDIR);
600
  }
601
20556
  uv_fs_req_cleanup(&req);
602
603
41112
  args.GetReturnValue().Set(rc);
604
20556
}
605
606
21465
static void Stat(const FunctionCallbackInfo<Value>& args) {
607
21465
  Environment* env = Environment::GetCurrent(args);
608
609
21465
  if (args.Length() < 1)
610
3
    return TYPE_ERROR("path required");
611
612
42927
  BufferValue path(env->isolate(), args[0]);
613
21465
  ASSERT_PATH(path)
614
615
21465
  if (args[1]->IsObject()) {
616

1272
    ASYNC_CALL(stat, args[1], UTF8, *path)
617
  } else {
618
63918
    SYNC_CALL(stat, *path, *path)
619
63909
    args.GetReturnValue().Set(
620
42606
        BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
621
  }
622
}
623
624
67586
static void LStat(const FunctionCallbackInfo<Value>& args) {
625
67586
  Environment* env = Environment::GetCurrent(args);
626
627
67586
  if (args.Length() < 1)
628
1
    return TYPE_ERROR("path required");
629
630
135171
  BufferValue path(env->isolate(), args[0]);
631
67586
  ASSERT_PATH(path)
632
633
67586
  if (args[1]->IsObject()) {
634

7312
    ASYNC_CALL(lstat, args[1], UTF8, *path)
635
  } else {
636
200016
    SYNC_CALL(lstat, *path, *path)
637
200013
    args.GetReturnValue().Set(
638
133342
        BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
639
  }
640
}
641
642
8837
static void FStat(const FunctionCallbackInfo<Value>& args) {
643
8837
  Environment* env = Environment::GetCurrent(args);
644
645
8837
  if (args.Length() < 1)
646
    return TYPE_ERROR("fd is required");
647
8837
  if (!args[0]->IsInt32())
648
    return TYPE_ERROR("fd must be a file descriptor");
649
650
8837
  int fd = args[0]->Int32Value();
651
652
8837
  if (args[1]->IsObject()) {
653

704
    ASYNC_CALL(fstat, args[1], UTF8, fd)
654
  } else {
655
26247
    SYNC_CALL(fstat, 0, fd)
656
26247
    args.GetReturnValue().Set(
657
17498
        BuildStatsObject(env, static_cast<const uv_stat_t*>(SYNC_REQ.ptr)));
658
  }
659
}
660
661
36
static void Symlink(const FunctionCallbackInfo<Value>& args) {
662
36
  Environment* env = Environment::GetCurrent(args);
663
664
36
  int len = args.Length();
665
36
  if (len < 1)
666
1
    return TYPE_ERROR("target path required");
667
36
  if (len < 2)
668
    return TYPE_ERROR("src path required");
669
670
71
  BufferValue target(env->isolate(), args[0]);
671
36
  ASSERT_PATH(target)
672
71
  BufferValue path(env->isolate(), args[1]);
673
36
  ASSERT_PATH(path)
674
675
36
  int flags = 0;
676
677
72
  if (args[2]->IsString()) {
678
38
    node::Utf8Value mode(env->isolate(), args[2]);
679
19
    if (strcmp(*mode, "dir") == 0) {
680
      flags |= UV_FS_SYMLINK_DIR;
681
9
    } else if (strcmp(*mode, "junction") == 0) {
682
      flags |= UV_FS_SYMLINK_JUNCTION;
683
6
    } else if (strcmp(*mode, "file") != 0) {
684
      return env->ThrowError("Unknown symlink type");
685
    }
686
  }
687
688
36
  if (args[3]->IsObject()) {
689

32
    ASYNC_DEST_CALL(symlink, args[3], *path, UTF8, *target, *path, flags)
690
  } else {
691
96
    SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
692
  }
693
}
694
695
7
static void Link(const FunctionCallbackInfo<Value>& args) {
696
7
  Environment* env = Environment::GetCurrent(args);
697
698
7
  int len = args.Length();
699
7
  if (len < 1)
700
4
    return TYPE_ERROR("src path required");
701
7
  if (len < 2)
702
    return TYPE_ERROR("dest path required");
703
704
10
  BufferValue src(env->isolate(), args[0]);
705
7
  ASSERT_PATH(src)
706
707
9
  BufferValue dest(env->isolate(), args[1]);
708
6
  ASSERT_PATH(dest)
709
710
5
  if (args[2]->IsObject()) {
711

24
    ASYNC_DEST_CALL(link, args[2], *dest, UTF8, *src, *dest)
712
  } else {
713
6
    SYNC_DEST_CALL(link, *src, *dest, *src, *dest)
714
  }
715
}
716
717
55
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
718
55
  Environment* env = Environment::GetCurrent(args);
719
720
55
  const int argc = args.Length();
721
722
55
  if (argc < 1)
723
1
    return TYPE_ERROR("path required");
724
725
109
  BufferValue path(env->isolate(), args[0]);
726
55
  ASSERT_PATH(path)
727
728
55
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
729
730
165
  Local<Value> callback = Null(env->isolate());
731
55
  if (argc == 3)
732
    callback = args[2];
733
734
55
  if (callback->IsObject()) {
735

150
    ASYNC_CALL(readlink, callback, encoding, *path)
736
  } else {
737
90
    SYNC_CALL(readlink, *path, *path)
738
29
    const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
739
    Local<Value> rc = StringBytes::Encode(env->isolate(),
740
                                          link_path,
741
29
                                          encoding);
742
29
    if (rc.IsEmpty()) {
743
      return env->ThrowUVException(UV_EINVAL,
744
                                   "readlink",
745
                                   "Invalid character encoding for link",
746
                                   *path);
747
    }
748
58
    args.GetReturnValue().Set(rc);
749
  }
750
}
751
752
9
static void Rename(const FunctionCallbackInfo<Value>& args) {
753
9
  Environment* env = Environment::GetCurrent(args);
754
755
9
  int len = args.Length();
756
9
  if (len < 1)
757
2
    return TYPE_ERROR("old path required");
758
9
  if (len < 2)
759
    return TYPE_ERROR("new path required");
760
761
16
  BufferValue old_path(env->isolate(), args[0]);
762
9
  ASSERT_PATH(old_path)
763
16
  BufferValue new_path(env->isolate(), args[1]);
764
9
  ASSERT_PATH(new_path)
765
766
9
  if (args[2]->IsObject()) {
767

56
    ASYNC_DEST_CALL(rename, args[2], *new_path, UTF8, *old_path, *new_path)
768
  } else {
769
6
    SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
770
  }
771
}
772
773
15
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
774
15
  Environment* env = Environment::GetCurrent(args);
775
776
15
  if (args.Length() < 2)
777
    return TYPE_ERROR("fd and length are required");
778
15
  if (!args[0]->IsInt32())
779
    return TYPE_ERROR("fd must be a file descriptor");
780
781
15
  int fd = args[0]->Int32Value();
782
783
  // FIXME(bnoordhuis) It's questionable to reject non-ints here but still
784
  // allow implicit coercion from null or undefined to zero.  Probably best
785
  // handled in lib/fs.js.
786
15
  Local<Value> len_v(args[1]);
787

60
  if (!len_v->IsUndefined() &&
788

45
      !len_v->IsNull() &&
789
30
      !IsInt64(len_v->NumberValue())) {
790
    return env->ThrowTypeError("Not an integer");
791
  }
792
793
15
  const int64_t len = len_v->IntegerValue();
794
795
15
  if (args[2]->IsObject()) {
796

64
    ASYNC_CALL(ftruncate, args[2], UTF8, fd, len)
797
  } else {
798
21
    SYNC_CALL(ftruncate, 0, fd, len)
799
  }
800
}
801
802
2
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
803
2
  Environment* env = Environment::GetCurrent(args);
804
805
2
  if (args.Length() < 1)
806
    return TYPE_ERROR("fd is required");
807
2
  if (!args[0]->IsInt32())
808
    return TYPE_ERROR("fd must be a file descriptor");
809
810
2
  int fd = args[0]->Int32Value();
811
812
2
  if (args[1]->IsObject()) {
813

8
    ASYNC_CALL(fdatasync, args[1], UTF8, fd)
814
  } else {
815
3
    SYNC_CALL(fdatasync, 0, fd)
816
  }
817
}
818
819
14
static void Fsync(const FunctionCallbackInfo<Value>& args) {
820
14
  Environment* env = Environment::GetCurrent(args);
821
822
14
  if (args.Length() < 1)
823
    return TYPE_ERROR("fd is required");
824
14
  if (!args[0]->IsInt32())
825
    return TYPE_ERROR("fd must be a file descriptor");
826
827
14
  int fd = args[0]->Int32Value();
828
829
14
  if (args[1]->IsObject()) {
830

8
    ASYNC_CALL(fsync, args[1], UTF8, fd)
831
  } else {
832
39
    SYNC_CALL(fsync, 0, fd)
833
  }
834
}
835
836
444
static void Unlink(const FunctionCallbackInfo<Value>& args) {
837
444
  Environment* env = Environment::GetCurrent(args);
838
839
444
  if (args.Length() < 1)
840
27
    return TYPE_ERROR("path required");
841
842
861
  BufferValue path(env->isolate(), args[0]);
843
444
  ASSERT_PATH(path)
844
845
444
  if (args[1]->IsObject()) {
846

2072
    ASYNC_CALL(unlink, args[1], UTF8, *path)
847
  } else {
848
555
    SYNC_CALL(unlink, *path, *path)
849
  }
850
}
851
852
757
static void RMDir(const FunctionCallbackInfo<Value>& args) {
853
757
  Environment* env = Environment::GetCurrent(args);
854
855
757
  if (args.Length() < 1)
856
152
    return TYPE_ERROR("path required");
857
858
1362
  BufferValue path(env->isolate(), args[0]);
859
757
  ASSERT_PATH(path)
860
861
757
  if (args[1]->IsObject()) {
862

3232
    ASYNC_CALL(rmdir, args[1], UTF8, *path)
863
  } else {
864
1059
    SYNC_CALL(rmdir, *path, *path)
865
  }
866
}
867
868
2012
static void MKDir(const FunctionCallbackInfo<Value>& args) {
869
2012
  Environment* env = Environment::GetCurrent(args);
870
871
2012
  if (args.Length() < 2)
872
1772
    return TYPE_ERROR("path and mode are required");
873
2012
  if (!args[1]->IsInt32())
874
    return TYPE_ERROR("mode must be an integer");
875
876
2252
  BufferValue path(env->isolate(), args[0]);
877
2012
  ASSERT_PATH(path)
878
879
2012
  int mode = static_cast<int>(args[1]->Int32Value());
880
881
2012
  if (args[2]->IsObject()) {
882

432
    ASYNC_CALL(mkdir, args[2], UTF8, *path, mode)
883
  } else {
884
5874
    SYNC_CALL(mkdir, *path, *path, mode)
885
  }
886
}
887
888
static void RealPath(const FunctionCallbackInfo<Value>& args) {
889
  Environment* env = Environment::GetCurrent(args);
890
891
  const int argc = args.Length();
892
893
  if (argc < 1)
894
    return TYPE_ERROR("path required");
895
896
  BufferValue path(env->isolate(), args[0]);
897
  ASSERT_PATH(path)
898
899
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
900
901
  Local<Value> callback = Null(env->isolate());
902
  if (argc == 3)
903
    callback = args[2];
904
905
  if (callback->IsObject()) {
906
    ASYNC_CALL(realpath, callback, encoding, *path);
907
  } else {
908
    SYNC_CALL(realpath, *path, *path);
909
    const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
910
    Local<Value> rc = StringBytes::Encode(env->isolate(),
911
                                          link_path,
912
                                          encoding);
913
    if (rc.IsEmpty()) {
914
      return env->ThrowUVException(UV_EINVAL,
915
                                   "realpath",
916
                                   "Invalid character encoding for path",
917
                                   *path);
918
    }
919
    args.GetReturnValue().Set(rc);
920
  }
921
}
922
923
606
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
924
606
  Environment* env = Environment::GetCurrent(args);
925
926
606
  const int argc = args.Length();
927
928
606
  if (argc < 1)
929
20
    return TYPE_ERROR("path required");
930
931
1192
  BufferValue path(env->isolate(), args[0]);
932
606
  ASSERT_PATH(path)
933
934
606
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
935
936
1818
  Local<Value> callback = Null(env->isolate());
937
606
  if (argc == 3)
938
    callback = args[2];
939
940
606
  if (callback->IsObject()) {
941

1350
    ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/)
942
  } else {
943
1143
    SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
944
945
361
    CHECK_GE(SYNC_REQ.result, 0);
946
    int r;
947
361
    Local<Array> names = Array::New(env->isolate(), 0);
948
361
    Local<Function> fn = env->push_values_to_array_function();
949
6137
    Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
950
    size_t name_idx = 0;
951
952
4518
    for (int i = 0; ; i++) {
953
      uv_dirent_t ent;
954
955
4879
      r = uv_fs_scandir_next(&SYNC_REQ, &ent);
956
4879
      if (r == UV_EOF)
957
        break;
958
4518
      if (r != 0)
959
        return env->ThrowUVException(r, "readdir", "", *path);
960
961
      Local<Value> filename = StringBytes::Encode(env->isolate(),
962
                                                  ent.name,
963
4518
                                                  encoding);
964
4518
      if (filename.IsEmpty()) {
965
        return env->ThrowUVException(UV_EINVAL,
966
                                     "readdir",
967
                                     "Invalid character encoding for filename",
968
                                     *path);
969
      }
970
971
4518
      name_v[name_idx++] = filename;
972
973
4518
      if (name_idx >= arraysize(name_v)) {
974
1716
        fn->Call(env->context(), names, name_idx, name_v)
975
429
            .ToLocalChecked();
976
429
        name_idx = 0;
977
      }
978
    }
979
980
361
    if (name_idx > 0) {
981
1364
      fn->Call(env->context(), names, name_idx, name_v).ToLocalChecked();
982
    }
983
984
722
    args.GetReturnValue().Set(names);
985
  }
986
}
987
988
11344
static void Open(const FunctionCallbackInfo<Value>& args) {
989
11344
  Environment* env = Environment::GetCurrent(args);
990
991
11344
  int len = args.Length();
992
11344
  if (len < 1)
993
4
    return TYPE_ERROR("path required");
994
11344
  if (len < 2)
995
    return TYPE_ERROR("flags required");
996
11344
  if (len < 3)
997
    return TYPE_ERROR("mode required");
998
11344
  if (!args[1]->IsInt32())
999
    return TYPE_ERROR("flags must be an int");
1000
11344
  if (!args[2]->IsInt32())
1001
    return TYPE_ERROR("mode must be an int");
1002
1003
22684
  BufferValue path(env->isolate(), args[0]);
1004
11344
  ASSERT_PATH(path)
1005
1006
11344
  int flags = args[1]->Int32Value();
1007
11344
  int mode = static_cast<int>(args[2]->Int32Value());
1008
1009
11344
  if (args[3]->IsObject()) {
1010

3280
    ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
1011
  } else {
1012
32802
    SYNC_CALL(open, *path, *path, flags, mode)
1013
21860
    args.GetReturnValue().Set(SYNC_RESULT);
1014
  }
1015
}
1016
1017
1018
// Wrapper for write(2).
1019
//
1020
// bytesWritten = write(fd, buffer, offset, length, position, callback)
1021
// 0 fd        integer. file descriptor
1022
// 1 buffer    the data to write
1023
// 2 offset    where in the buffer to start from
1024
// 3 length    how much to write
1025
// 4 position  if integer, position to write at in the file.
1026
//             if null, write from the current position
1027
24346
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
1028
24346
  Environment* env = Environment::GetCurrent(args);
1029
1030
24346
  if (!args[0]->IsInt32())
1031
10324
    return env->ThrowTypeError("First argument must be file descriptor");
1032
1033
24345
  CHECK(Buffer::HasInstance(args[1]));
1034
1035
24345
  int fd = args[0]->Int32Value();
1036
48690
  Local<Object> obj = args[1].As<Object>();
1037
24345
  const char* buf = Buffer::Data(obj);
1038
24345
  size_t buffer_length = Buffer::Length(obj);
1039
24345
  size_t off = args[2]->Uint32Value();
1040
24345
  size_t len = args[3]->Uint32Value();
1041
26129
  int64_t pos = GET_OFFSET(args[4]);
1042
24345
  Local<Value> req = args[5];
1043
1044
24345
  if (off > buffer_length)
1045
    return env->ThrowRangeError("offset out of bounds");
1046
24345
  if (len > buffer_length)
1047
    return env->ThrowRangeError("length out of bounds");
1048
24345
  if (off + len < off)
1049
    return env->ThrowRangeError("off + len overflow");
1050
24345
  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1051
    return env->ThrowRangeError("off + len > buffer.length");
1052
1053
24345
  buf += off;
1054
1055
24345
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1056
1057
24345
  if (req->IsObject()) {
1058

61938
    ASYNC_CALL(write, req, UTF8, fd, &uvbuf, 1, pos)
1059
    return;
1060
  }
1061
1062
42066
  SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1063
28044
  args.GetReturnValue().Set(SYNC_RESULT);
1064
}
1065
1066
1067
// Wrapper for writev(2).
1068
//
1069
// bytesWritten = writev(fd, chunks, position, callback)
1070
// 0 fd        integer. file descriptor
1071
// 1 chunks    array of buffers to write
1072
// 2 position  if integer, position to write at in the file.
1073
//             if null, write from the current position
1074
4
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1075
4
  Environment* env = Environment::GetCurrent(args);
1076
1077
4
  CHECK(args[0]->IsInt32());
1078
4
  CHECK(args[1]->IsArray());
1079
1080
4
  int fd = args[0]->Int32Value();
1081
8
  Local<Array> chunks = args[1].As<Array>();
1082
4
  int64_t pos = GET_OFFSET(args[2]);
1083
4
  Local<Value> req = args[3];
1084
1085
8
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1086
1087
424
  for (uint32_t i = 0; i < iovs.length(); i++) {
1088
420
    Local<Value> chunk = chunks->Get(i);
1089
1090
420
    if (!Buffer::HasInstance(chunk))
1091
      return env->ThrowTypeError("Array elements all need to be buffers");
1092
1093
840
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1094
  }
1095
1096
4
  if (req->IsObject()) {
1097

24
    ASYNC_CALL(write, req, UTF8, fd, *iovs, iovs.length(), pos)
1098
    return;
1099
  }
1100
1101
  SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
1102
  args.GetReturnValue().Set(SYNC_RESULT);
1103
}
1104
1105
1106
// Wrapper for write(2).
1107
//
1108
// bytesWritten = write(fd, string, position, enc, callback)
1109
// 0 fd        integer. file descriptor
1110
// 1 string    non-buffer values are converted to strings
1111
// 2 position  if integer, position to write at in the file.
1112
//             if null, write from the current position
1113
// 3 enc       encoding of string
1114
497
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1115
497
  Environment* env = Environment::GetCurrent(args);
1116
1117
497
  if (!args[0]->IsInt32())
1118
    return env->ThrowTypeError("First argument must be file descriptor");
1119
1120
496
  Local<Value> req;
1121
496
  Local<Value> string = args[1];
1122
496
  int fd = args[0]->Int32Value();
1123
496
  char* buf = nullptr;
1124
  int64_t pos;
1125
  size_t len;
1126
496
  FSReqWrap::Ownership ownership = FSReqWrap::COPY;
1127
1128
  // will assign buf and len if string was external
1129
496
  if (!StringBytes::GetExternalParts(env->isolate(),
1130
                                     string,
1131
                                     const_cast<const char**>(&buf),
1132
                                     &len)) {
1133
496
    enum encoding enc = ParseEncoding(env->isolate(), args[3], UTF8);
1134
496
    len = StringBytes::StorageSize(env->isolate(), string, enc);
1135
496
    buf = new char[len];
1136
    // StorageSize may return too large a char, so correct the actual length
1137
    // by the write size
1138
496
    len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
1139
496
    ownership = FSReqWrap::MOVE;
1140
  }
1141
518
  pos = GET_OFFSET(args[2]);
1142
496
  req = args[4];
1143
1144
496
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1145
1146
496
  if (!req->IsObject()) {
1147
    // SYNC_CALL returns on error.  Make sure to always free the memory.
1148
    struct Delete {
1149
474
      inline explicit Delete(char* pointer) : pointer_(pointer) {}
1150
474
      inline ~Delete() { delete[] pointer_; }
1151
      char* const pointer_;
1152
    };
1153
1422
    Delete delete_on_return(ownership == FSReqWrap::MOVE ? buf : nullptr);
1154
1422
    SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1155
948
    return args.GetReturnValue().Set(SYNC_RESULT);
1156
  }
1157
1158
  FSReqWrap* req_wrap =
1159
44
      FSReqWrap::New(env, req.As<Object>(), "write", buf, UTF8, ownership);
1160
66
  int err = uv_fs_write(env->event_loop(),
1161
                        req_wrap->req(),
1162
                        fd,
1163
                        &uvbuf,
1164
                        1,
1165
                        pos,
1166
22
                        After);
1167
44
  req_wrap->Dispatched();
1168
22
  if (err < 0) {
1169
    uv_fs_t* uv_req = req_wrap->req();
1170
    uv_req->result = err;
1171
    uv_req->path = nullptr;
1172
    After(uv_req);
1173
    return;
1174
  }
1175
1176
44
  return args.GetReturnValue().Set(req_wrap->persistent());
1177
}
1178
1179
1180
/*
1181
 * Wrapper for read(2).
1182
 *
1183
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1184
 *
1185
 * 0 fd        integer. file descriptor
1186
 * 1 buffer    instance of Buffer
1187
 * 2 offset    integer. offset to start reading into inside buffer
1188
 * 3 length    integer. length to read
1189
 * 4 position  file position - null for current position
1190
 *
1191
 */
1192
9324
static void Read(const FunctionCallbackInfo<Value>& args) {
1193
9324
  Environment* env = Environment::GetCurrent(args);
1194
1195
9324
  if (args.Length() < 2)
1196
    return TYPE_ERROR("fd and buffer are required");
1197
9324
  if (!args[0]->IsInt32())
1198
    return TYPE_ERROR("fd must be a file descriptor");
1199
9324
  if (!Buffer::HasInstance(args[1]))
1200
    return TYPE_ERROR("Second argument needs to be a buffer");
1201
1202
9324
  int fd = args[0]->Int32Value();
1203
1204
9324
  Local<Value> req;
1205
1206
  size_t len;
1207
  int64_t pos;
1208
1209
9324
  char * buf = nullptr;
1210
1211
18648
  Local<Object> buffer_obj = args[1]->ToObject(env->isolate());
1212
9324
  char *buffer_data = Buffer::Data(buffer_obj);
1213
9324
  size_t buffer_length = Buffer::Length(buffer_obj);
1214
1215
9324
  size_t off = args[2]->Int32Value();
1216
9324
  if (off >= buffer_length) {
1217
    return env->ThrowError("Offset is out of bounds");
1218
  }
1219
1220
9324
  len = args[3]->Int32Value();
1221
9324
  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1222
    return env->ThrowRangeError("Length extends beyond buffer");
1223
1224
9556
  pos = GET_OFFSET(args[4]);
1225
1226
9324
  buf = buffer_data + off;
1227
1228
9324
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1229
1230
9324
  req = args[5];
1231
1232
9324
  if (req->IsObject()) {
1233

2784
    ASYNC_CALL(read, req, UTF8, fd, &uvbuf, 1, pos);
1234
  } else {
1235
26580
    SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
1236
17720
    args.GetReturnValue().Set(SYNC_RESULT);
1237
  }
1238
}
1239
1240
1241
/* fs.chmod(path, mode);
1242
 * Wrapper for chmod(1) / EIO_CHMOD
1243
 */
1244
10
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1245
10
  Environment* env = Environment::GetCurrent(args);
1246
1247
10
  if (args.Length() < 2)
1248
1
    return TYPE_ERROR("path and mode are required");
1249
10
  if (!args[1]->IsInt32())
1250
    return TYPE_ERROR("mode must be an integer");
1251
1252
19
  BufferValue path(env->isolate(), args[0]);
1253
10
  ASSERT_PATH(path)
1254
1255
10
  int mode = static_cast<int>(args[1]->Int32Value());
1256
1257
10
  if (args[2]->IsObject()) {
1258

32
    ASYNC_CALL(chmod, args[2], UTF8, *path, mode);
1259
  } else {
1260
18
    SYNC_CALL(chmod, *path, *path, mode);
1261
  }
1262
}
1263
1264
1265
/* fs.fchmod(fd, mode);
1266
 * Wrapper for fchmod(1) / EIO_FCHMOD
1267
 */
1268
2
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1269
2
  Environment* env = Environment::GetCurrent(args);
1270
1271
2
  if (args.Length() < 2)
1272
    return TYPE_ERROR("fd and mode are required");
1273
2
  if (!args[0]->IsInt32())
1274
    return TYPE_ERROR("fd must be a file descriptor");
1275
2
  if (!args[1]->IsInt32())
1276
    return TYPE_ERROR("mode must be an integer");
1277
1278
2
  int fd = args[0]->Int32Value();
1279
2
  int mode = static_cast<int>(args[1]->Int32Value());
1280
1281
2
  if (args[2]->IsObject()) {
1282

8
    ASYNC_CALL(fchmod, args[2], UTF8, fd, mode);
1283
  } else {
1284
3
    SYNC_CALL(fchmod, 0, fd, mode);
1285
  }
1286
}
1287
1288
1289
/* fs.chown(path, uid, gid);
1290
 * Wrapper for chown(1) / EIO_CHOWN
1291
 */
1292
9
static void Chown(const FunctionCallbackInfo<Value>& args) {
1293
9
  Environment* env = Environment::GetCurrent(args);
1294
1295
9
  int len = args.Length();
1296
9
  if (len < 1)
1297
    return TYPE_ERROR("path required");
1298
9
  if (len < 2)
1299
    return TYPE_ERROR("uid required");
1300
9
  if (len < 3)
1301
    return TYPE_ERROR("gid required");
1302
9
  if (!args[1]->IsUint32())
1303
    return TYPE_ERROR("uid must be an unsigned int");
1304
9
  if (!args[2]->IsUint32())
1305
    return TYPE_ERROR("gid must be an unsigned int");
1306
1307
18
  BufferValue path(env->isolate(), args[0]);
1308
9
  ASSERT_PATH(path)
1309
1310
9
  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1311
9
  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1312
1313
9
  if (args[3]->IsObject()) {
1314

72
    ASYNC_CALL(chown, args[3], UTF8, *path, uid, gid);
1315
  } else {
1316
    SYNC_CALL(chown, *path, *path, uid, gid);
1317
  }
1318
}
1319
1320
1321
/* fs.fchown(fd, uid, gid);
1322
 * Wrapper for fchown(1) / EIO_FCHOWN
1323
 */
1324
static void FChown(const FunctionCallbackInfo<Value>& args) {
1325
  Environment* env = Environment::GetCurrent(args);
1326
1327
  int len = args.Length();
1328
  if (len < 1)
1329
    return TYPE_ERROR("fd required");
1330
  if (len < 2)
1331
    return TYPE_ERROR("uid required");
1332
  if (len < 3)
1333
    return TYPE_ERROR("gid required");
1334
  if (!args[0]->IsInt32())
1335
    return TYPE_ERROR("fd must be an int");
1336
  if (!args[1]->IsUint32())
1337
    return TYPE_ERROR("uid must be an unsigned int");
1338
  if (!args[2]->IsUint32())
1339
    return TYPE_ERROR("gid must be an unsigned int");
1340
1341
  int fd = args[0]->Int32Value();
1342
  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1343
  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1344
1345
  if (args[3]->IsObject()) {
1346
    ASYNC_CALL(fchown, args[3], UTF8, fd, uid, gid);
1347
  } else {
1348
    SYNC_CALL(fchown, 0, fd, uid, gid);
1349
  }
1350
}
1351
1352
1353
26
static void UTimes(const FunctionCallbackInfo<Value>& args) {
1354
26
  Environment* env = Environment::GetCurrent(args);
1355
1356
26
  int len = args.Length();
1357
26
  if (len < 1)
1358
6
    return TYPE_ERROR("path required");
1359
26
  if (len < 2)
1360
    return TYPE_ERROR("atime required");
1361
26
  if (len < 3)
1362
    return TYPE_ERROR("mtime required");
1363
26
  if (!args[1]->IsNumber())
1364
    return TYPE_ERROR("atime must be a number");
1365
26
  if (!args[2]->IsNumber())
1366
    return TYPE_ERROR("mtime must be a number");
1367
1368
46
  BufferValue path(env->isolate(), args[0]);
1369
26
  ASSERT_PATH(path)
1370
1371
26
  const double atime = static_cast<double>(args[1]->NumberValue());
1372
26
  const double mtime = static_cast<double>(args[2]->NumberValue());
1373
1374
26
  if (args[3]->IsObject()) {
1375

112
    ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime);
1376
  } else {
1377
36
    SYNC_CALL(utime, *path, *path, atime, mtime);
1378
  }
1379
}
1380
1381
24
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
1382
24
  Environment* env = Environment::GetCurrent(args);
1383
1384
24
  int len = args.Length();
1385
24
  if (len < 1)
1386
    return TYPE_ERROR("fd required");
1387
24
  if (len < 2)
1388
    return TYPE_ERROR("atime required");
1389
24
  if (len < 3)
1390
    return TYPE_ERROR("mtime required");
1391
24
  if (!args[0]->IsInt32())
1392
    return TYPE_ERROR("fd must be an int");
1393
24
  if (!args[1]->IsNumber())
1394
    return TYPE_ERROR("atime must be a number");
1395
24
  if (!args[2]->IsNumber())
1396
    return TYPE_ERROR("mtime must be a number");
1397
1398
24
  const int fd = args[0]->Int32Value();
1399
24
  const double atime = static_cast<double>(args[1]->NumberValue());
1400
24
  const double mtime = static_cast<double>(args[2]->NumberValue());
1401
1402
24
  if (args[3]->IsObject()) {
1403

96
    ASYNC_CALL(futime, args[3], UTF8, fd, atime, mtime);
1404
  } else {
1405
36
    SYNC_CALL(futime, 0, fd, atime, mtime);
1406
  }
1407
}
1408
1409
9
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
1410
9
  Environment* env = Environment::GetCurrent(args);
1411
1412
9
  CHECK_GE(args.Length(), 2);
1413
1414
18
  BufferValue tmpl(env->isolate(), args[0]);
1415
9
  if (*tmpl == nullptr)
1416
    return TYPE_ERROR("template must be a string or Buffer");
1417
1418
9
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
1419
1420
9
  if (args[2]->IsObject()) {
1421

40
    ASYNC_CALL(mkdtemp, args[2], encoding, *tmpl);
1422
  } else {
1423
12
    SYNC_CALL(mkdtemp, *tmpl, *tmpl);
1424
4
    const char* path = static_cast<const char*>(SYNC_REQ.path);
1425
4
    Local<Value> rc = StringBytes::Encode(env->isolate(), path, encoding);
1426
4
    if (rc.IsEmpty()) {
1427
      return env->ThrowUVException(UV_EINVAL,
1428
                                   "mkdtemp",
1429
                                   "Invalid character encoding for filename",
1430
                                   *tmpl);
1431
    }
1432
8
    args.GetReturnValue().Set(rc);
1433
  }
1434
}
1435
1436
1698
void FSInitialize(const FunctionCallbackInfo<Value>& args) {
1437
3396
  Local<Function> stats_constructor = args[0].As<Function>();
1438
1698
  CHECK(stats_constructor->IsFunction());
1439
1440
1698
  Environment* env = Environment::GetCurrent(args);
1441
1698
  env->set_fs_stats_constructor_function(stats_constructor);
1442
1698
}
1443
1444
1698
void InitFs(Local<Object> target,
1445
            Local<Value> unused,
1446
            Local<Context> context,
1447
            void* priv) {
1448
1698
  Environment* env = Environment::GetCurrent(context);
1449
1450
  // Function which creates a new Stats object.
1451
6792
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSInitialize"),
1452
5094
              env->NewFunctionTemplate(FSInitialize)->GetFunction());
1453
1454
1698
  env->SetMethod(target, "access", Access);
1455
1698
  env->SetMethod(target, "close", Close);
1456
1698
  env->SetMethod(target, "open", Open);
1457
1698
  env->SetMethod(target, "read", Read);
1458
1698
  env->SetMethod(target, "fdatasync", Fdatasync);
1459
1698
  env->SetMethod(target, "fsync", Fsync);
1460
1698
  env->SetMethod(target, "rename", Rename);
1461
1698
  env->SetMethod(target, "ftruncate", FTruncate);
1462
1698
  env->SetMethod(target, "rmdir", RMDir);
1463
1698
  env->SetMethod(target, "mkdir", MKDir);
1464
1698
  env->SetMethod(target, "readdir", ReadDir);
1465
1698
  env->SetMethod(target, "internalModuleReadFile", InternalModuleReadFile);
1466
1698
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
1467
1698
  env->SetMethod(target, "stat", Stat);
1468
1698
  env->SetMethod(target, "lstat", LStat);
1469
1698
  env->SetMethod(target, "fstat", FStat);
1470
1698
  env->SetMethod(target, "link", Link);
1471
1698
  env->SetMethod(target, "symlink", Symlink);
1472
1698
  env->SetMethod(target, "readlink", ReadLink);
1473
1698
  env->SetMethod(target, "unlink", Unlink);
1474
1698
  env->SetMethod(target, "writeBuffer", WriteBuffer);
1475
1698
  env->SetMethod(target, "writeBuffers", WriteBuffers);
1476
1698
  env->SetMethod(target, "writeString", WriteString);
1477
1698
  env->SetMethod(target, "realpath", RealPath);
1478
1479
1698
  env->SetMethod(target, "chmod", Chmod);
1480
1698
  env->SetMethod(target, "fchmod", FChmod);
1481
  // env->SetMethod(target, "lchmod", LChmod);
1482
1483
1698
  env->SetMethod(target, "chown", Chown);
1484
1698
  env->SetMethod(target, "fchown", FChown);
1485
  // env->SetMethod(target, "lchown", LChown);
1486
1487
1698
  env->SetMethod(target, "utimes", UTimes);
1488
1698
  env->SetMethod(target, "futimes", FUTimes);
1489
1490
1698
  env->SetMethod(target, "mkdtemp", Mkdtemp);
1491
1492
1698
  StatWatcher::Initialize(env, target);
1493
1494
  // Create FunctionTemplate for FSReqWrap
1495
  Local<FunctionTemplate> fst =
1496
3396
      FunctionTemplate::New(env->isolate(), NewFSReqWrap);
1497
3396
  fst->InstanceTemplate()->SetInternalFieldCount(1);
1498
1698
  fst->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"));
1499
6792
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"),
1500
1698
              fst->GetFunction());
1501
1698
}
1502
1503
}  // end namespace node
1504
1505
1705
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs, node::InitFs)