GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/node_file.cc Lines: 590 636 92.8 %
Date: 2016-07-23 Branches: 340 557 61.0 %

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