GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_file.cc Lines: 638 758 84.2 %
Date: 2017-10-21 Branches: 444 691 64.3 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_buffer.h"
23
#include "node_internals.h"
24
#include "node_stat_watcher.h"
25
26
#include "req-wrap.h"
27
#include "req-wrap-inl.h"
28
#include "string_bytes.h"
29
30
#include <fcntl.h>
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <string.h>
34
#include <errno.h>
35
#include <limits.h>
36
37
#if defined(__MINGW32__) || defined(_MSC_VER)
38
# include <io.h>
39
#endif
40
41
#include <vector>
42
43
namespace node {
44
namespace {
45
46
using v8::Array;
47
using v8::ArrayBuffer;
48
using v8::Context;
49
using v8::Float64Array;
50
using v8::Function;
51
using v8::FunctionCallbackInfo;
52
using v8::FunctionTemplate;
53
using v8::HandleScope;
54
using v8::Integer;
55
using v8::Local;
56
using v8::MaybeLocal;
57
using v8::Number;
58
using v8::Object;
59
using v8::String;
60
using v8::Value;
61
62
#ifndef MIN
63
# define MIN(a, b) ((a) < (b) ? (a) : (b))
64
#endif
65
66
#define TYPE_ERROR(msg) env->ThrowTypeError(msg)
67
68
#define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1)
69
70
class FSReqWrap: public ReqWrap<uv_fs_t> {
71
 public:
72
  enum Ownership { COPY, MOVE };
73
74
  inline static FSReqWrap* New(Environment* env,
75
                               Local<Object> req,
76
                               const char* syscall,
77
                               const char* data = nullptr,
78
                               enum encoding encoding = UTF8,
79
                               Ownership ownership = COPY);
80
81
  inline void Dispose();
82
83
384541
  void ReleaseEarly() {
84
384541
    if (data_ != inline_data()) {
85
382366
      delete[] data_;
86
382366
      data_ = nullptr;
87
    }
88
384541
  }
89
90
12989
  const char* syscall() const { return syscall_; }
91
12989
  const char* data() const { return data_; }
92
  const enum encoding encoding_;
93
94
  size_t self_size() const override { return sizeof(*this); }
95
96
 private:
97
192277
  FSReqWrap(Environment* env,
98
            Local<Object> req,
99
            const char* syscall,
100
            const char* data,
101
            enum encoding encoding)
102
      : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
103
        encoding_(encoding),
104
        syscall_(syscall),
105
192277
        data_(data) {
106
192277
    Wrap(object(), this);
107
192277
  }
108
109
384534
  ~FSReqWrap() {
110
192267
    ReleaseEarly();
111
192267
    ClearWrap(object());
112
192267
  }
113
114
  void* operator new(size_t size) = delete;
115
192277
  void* operator new(size_t size, char* storage) { return storage; }
116
385629
  char* inline_data() { return reinterpret_cast<char*>(this + 1); }
117
118
  const char* syscall_;
119
  const char* data_;
120
121
  DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
122
};
123
124
#define ASSERT_PATH(path)                                                   \
125
  if (*path == nullptr)                                                     \
126
    return TYPE_ERROR( #path " must be a string or Buffer");
127
128
192277
FSReqWrap* FSReqWrap::New(Environment* env,
129
                          Local<Object> req,
130
                          const char* syscall,
131
                          const char* data,
132
                          enum encoding encoding,
133
                          Ownership ownership) {
134

192277
  const bool copy = (data != nullptr && ownership == COPY);
135
192277
  const size_t size = copy ? 1 + strlen(data) : 0;
136
  FSReqWrap* that;
137
192277
  char* const storage = new char[sizeof(*that) + size];
138
192277
  that = new(storage) FSReqWrap(env, req, syscall, data, encoding);
139
192277
  if (copy)
140
1088
    that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
141
192277
  return that;
142
}
143
144
145
192267
void FSReqWrap::Dispose() {
146
192267
  this->~FSReqWrap();
147
192267
  delete[] reinterpret_cast<char*>(this);
148
192267
}
149
150
151
192287
void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
152
192287
  CHECK(args.IsConstructCall());
153
192287
  ClearWrap(args.This());
154
192287
}
155
156
157
38
inline bool IsInt64(double x) {
158
38
  return x == static_cast<double>(static_cast<int64_t>(x));
159
}
160
161
192274
void After(uv_fs_t *req) {
162
192274
  FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
163
192274
  CHECK_EQ(req_wrap->req(), req);
164
192274
  req_wrap->ReleaseEarly();  // Free memory that's no longer used now.
165
166
192274
  Environment* env = req_wrap->env();
167
192274
  HandleScope handle_scope(env->isolate());
168
192274
  Context::Scope context_scope(env->context());
169
170
  // there is always at least one argument. "error"
171
192274
  int argc = 1;
172
173
  // Allocate space for two args. We may only use one depending on the case.
174
  // (Feel free to increase this if you need more)
175
576822
  Local<Value> argv[2];
176
  MaybeLocal<Value> link;
177
  Local<Value> error;
178
179
192274
  if (req->result < 0) {
180
    // An error happened.
181
    argv[0] = UVException(env->isolate(),
182
                          req->result,
183
                          req_wrap->syscall(),
184
                          nullptr,
185
                          req->path,
186
12989
                          req_wrap->data());
187
  } else {
188
    // error value is empty or null for non-error.
189
358570
    argv[0] = Null(env->isolate());
190
191
    // All have at least two args now.
192
179285
    argc = 2;
193
194


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

511
    ASYNC_CALL(access, args[2], UTF8, *path, mode);
410
  } else {
411

118
    SYNC_CALL(access, *path, *path, mode);
412
97
  }
413
}
414
415
416
65081
void Close(const FunctionCallbackInfo<Value>& args) {
417
65081
  Environment* env = Environment::GetCurrent(args);
418
419
65081
  if (args.Length() < 1)
420
    return TYPE_ERROR("fd is required");
421
130162
  if (!args[0]->IsInt32())
422
    return TYPE_ERROR("fd must be a file descriptor");
423
424
130162
  int fd = args[0]->Int32Value();
425
426
130162
  if (args[1]->IsObject()) {
427

223769
    ASYNC_CALL(close, args[1], UTF8, fd)
428
  } else {
429

33114
    SYNC_CALL(close, 0, fd)
430
  }
431
}
432
433
}  // anonymous namespace
434
435
171086
void FillStatsArray(double* fields, const uv_stat_t* s) {
436
171086
  fields[0] = s->st_dev;
437
171086
  fields[1] = s->st_mode;
438
171086
  fields[2] = s->st_nlink;
439
171086
  fields[3] = s->st_uid;
440
171086
  fields[4] = s->st_gid;
441
171086
  fields[5] = s->st_rdev;
442
#if defined(__POSIX__)
443
171086
  fields[6] = s->st_blksize;
444
#else
445
  fields[6] = -1;
446
#endif
447
171086
  fields[7] = s->st_ino;
448
171086
  fields[8] = s->st_size;
449
#if defined(__POSIX__)
450
171086
  fields[9] = s->st_blocks;
451
#else
452
  fields[9] = -1;
453
#endif
454
// Dates.
455
// NO-LINT because the fields are 'long' and we just want to cast to `unsigned`
456
#define X(idx, name)                                           \
457
  /* NOLINTNEXTLINE(runtime/int) */                            \
458
  fields[idx] = ((unsigned long)(s->st_##name.tv_sec) * 1e3) + \
459
  /* NOLINTNEXTLINE(runtime/int) */                            \
460
                ((unsigned long)(s->st_##name.tv_nsec) / 1e6); \
461
462
171086
  X(10, atim)
463
171086
  X(11, mtim)
464
171086
  X(12, ctim)
465
171086
  X(13, birthtim)
466
#undef X
467
171086
}
468
469
// Used to speed up module loading.  Returns the contents of the file as
470
// a string or undefined when the file cannot be opened.  The speedup
471
// comes from not creating Error objects on failure.
472
13203
static void InternalModuleReadFile(const FunctionCallbackInfo<Value>& args) {
473
13203
  Environment* env = Environment::GetCurrent(args);
474
13203
  uv_loop_t* loop = env->event_loop();
475
476
39609
  CHECK(args[0]->IsString());
477
13203
  node::Utf8Value path(env->isolate(), args[0]);
478
479
13203
  if (strlen(*path) != path.length())
480
2
    return;  // Contains a nul byte.
481
482
  uv_fs_t open_req;
483
13201
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
484
13201
  uv_fs_req_cleanup(&open_req);
485
486
13201
  if (fd < 0) {
487
5821
    return;
488
  }
489
490
7380
  const size_t kBlockSize = 32 << 10;
491
14760
  std::vector<char> chars;
492
7380
  int64_t offset = 0;
493
  ssize_t numchars;
494
7380
  do {
495
7380
    const size_t start = chars.size();
496
7380
    chars.resize(start + kBlockSize);
497
498
    uv_buf_t buf;
499
7380
    buf.base = &chars[start];
500
7380
    buf.len = kBlockSize;
501
502
    uv_fs_t read_req;
503
7380
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
504
7380
    uv_fs_req_cleanup(&read_req);
505
506
7380
    CHECK_GE(numchars, 0);
507
7380
    offset += numchars;
508
  } while (static_cast<size_t>(numchars) == kBlockSize);
509
510
  uv_fs_t close_req;
511
7380
  CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
512
7380
  uv_fs_req_cleanup(&close_req);
513
514
7380
  size_t start = 0;
515

7380
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
516
    start = 3;  // Skip UTF-8 BOM.
517
  }
518
519
  Local<String> chars_string =
520
      String::NewFromUtf8(env->isolate(),
521
7380
                          &chars[start],
522
                          String::kNormalString,
523
14760
                          offset - start);
524
22140
  args.GetReturnValue().Set(chars_string);
525
}
526
527
// Used to speed up module loading.  Returns 0 if the path refers to
528
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
529
// The speedup comes from not creating thousands of Stat and Error objects.
530
94500
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
531
94500
  Environment* env = Environment::GetCurrent(args);
532
533
283500
  CHECK(args[0]->IsString());
534
94500
  node::Utf8Value path(env->isolate(), args[0]);
535
536
  uv_fs_t req;
537
94500
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
538
94500
  if (rc == 0) {
539
55644
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
540
55644
    rc = !!(s->st_mode & S_IFDIR);
541
  }
542
94500
  uv_fs_req_cleanup(&req);
543
544
189000
  args.GetReturnValue().Set(rc);
545
94500
}
546
547
31719
static void Stat(const FunctionCallbackInfo<Value>& args) {
548
31719
  Environment* env = Environment::GetCurrent(args);
549
550
31719
  if (args.Length() < 1)
551
4
    return TYPE_ERROR("path required");
552
553
31719
  BufferValue path(env->isolate(), args[0]);
554
31719
  ASSERT_PATH(path)
555
556
63438
  if (args[1]->IsObject()) {
557

66892
    ASYNC_CALL(stat, args[1], UTF8, *path)
558
  } else {
559
22163
    SYNC_CALL(stat, *path, *path)
560
    FillStatsArray(env->fs_stats_field_array(),
561

22159
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
562
31715
  }
563
}
564
565
90617
static void LStat(const FunctionCallbackInfo<Value>& args) {
566
90617
  Environment* env = Environment::GetCurrent(args);
567
568
90617
  if (args.Length() < 1)
569
2
    return TYPE_ERROR("path required");
570
571
90617
  BufferValue path(env->isolate(), args[0]);
572
90617
  ASSERT_PATH(path)
573
574
181234
  if (args[1]->IsObject()) {
575

103817
    ASYNC_CALL(lstat, args[1], UTF8, *path)
576
  } else {
577
75786
    SYNC_CALL(lstat, *path, *path)
578
    FillStatsArray(env->fs_stats_field_array(),
579

75784
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
580
90615
  }
581
}
582
583
51803
static void FStat(const FunctionCallbackInfo<Value>& args) {
584
51803
  Environment* env = Environment::GetCurrent(args);
585
586
51803
  if (args.Length() < 1)
587
    return TYPE_ERROR("fd is required");
588
103606
  if (!args[0]->IsInt32())
589
    return TYPE_ERROR("fd must be a file descriptor");
590
591
103606
  int fd = args[0]->Int32Value();
592
593
103606
  if (args[1]->IsObject()) {
594

156961
    ASYNC_CALL(fstat, args[1], UTF8, fd)
595
  } else {
596
29380
    SYNC_CALL(fstat, nullptr, fd)
597
    FillStatsArray(env->fs_stats_field_array(),
598
29377
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
599
  }
600
}
601
602
57
static void Symlink(const FunctionCallbackInfo<Value>& args) {
603
57
  Environment* env = Environment::GetCurrent(args);
604
605
57
  int len = args.Length();
606
57
  if (len < 1)
607
1
    return TYPE_ERROR("target path required");
608
57
  if (len < 2)
609
    return TYPE_ERROR("src path required");
610
611
57
  BufferValue target(env->isolate(), args[0]);
612
57
  ASSERT_PATH(target)
613
113
  BufferValue path(env->isolate(), args[1]);
614
57
  ASSERT_PATH(path)
615
616
57
  int flags = 0;
617
618
171
  if (args[2]->IsString()) {
619
34
    node::Utf8Value mode(env->isolate(), args[2]);
620
34
    if (strcmp(*mode, "dir") == 0) {
621
10
      flags |= UV_FS_SYMLINK_DIR;
622
24
    } else if (strcmp(*mode, "junction") == 0) {
623
18
      flags |= UV_FS_SYMLINK_JUNCTION;
624
6
    } else if (strcmp(*mode, "file") != 0) {
625
      return env->ThrowError("Unknown symlink type");
626
34
    }
627
  }
628
629
114
  if (args[3]->IsObject()) {
630

133
    ASYNC_DEST_CALL(symlink, args[3], *path, UTF8, *target, *path, flags)
631
  } else {
632

38
    SYNC_DEST_CALL(symlink, *target, *path, *target, *path, flags)
633
56
  }
634
}
635
636
71
static void Link(const FunctionCallbackInfo<Value>& args) {
637
71
  Environment* env = Environment::GetCurrent(args);
638
639
71
  int len = args.Length();
640
71
  if (len < 1)
641
4
    return TYPE_ERROR("src path required");
642
71
  if (len < 2)
643
    return TYPE_ERROR("dest path required");
644
645
71
  BufferValue src(env->isolate(), args[0]);
646
71
  ASSERT_PATH(src)
647
648
137
  BufferValue dest(env->isolate(), args[1]);
649
70
  ASSERT_PATH(dest)
650
651
138
  if (args[2]->IsObject()) {
652

469
    ASYNC_DEST_CALL(link, args[2], *dest, UTF8, *src, *dest)
653
  } else {
654

2
    SYNC_DEST_CALL(link, *src, *dest, *src, *dest)
655
67
  }
656
}
657
658
80
static void ReadLink(const FunctionCallbackInfo<Value>& args) {
659
80
  Environment* env = Environment::GetCurrent(args);
660
661
80
  const int argc = args.Length();
662
663
80
  if (argc < 1)
664
1
    return TYPE_ERROR("path required");
665
666
80
  BufferValue path(env->isolate(), args[0]);
667
80
  ASSERT_PATH(path)
668
669
80
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
670
671
80
  Local<Value> callback = Null(env->isolate());
672
80
  if (argc == 3)
673
42
    callback = args[2];
674
675
80
  if (callback->IsObject()) {
676

210
    ASYNC_CALL(readlink, callback, encoding, *path)
677
  } else {
678
38
    SYNC_CALL(readlink, *path, *path)
679
37
    const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
680
681
    Local<Value> error;
682
    MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
683
                                               link_path,
684
                                               encoding,
685
37
                                               &error);
686
37
    if (rc.IsEmpty()) {
687
      env->isolate()->ThrowException(error);
688
      return;
689
    }
690

74
    args.GetReturnValue().Set(rc.ToLocalChecked());
691
79
  }
692
}
693
694
1005
static void Rename(const FunctionCallbackInfo<Value>& args) {
695
1005
  Environment* env = Environment::GetCurrent(args);
696
697
1005
  int len = args.Length();
698
1005
  if (len < 1)
699
2
    return TYPE_ERROR("old path required");
700
1005
  if (len < 2)
701
    return TYPE_ERROR("new path required");
702
703
1005
  BufferValue old_path(env->isolate(), args[0]);
704
1005
  ASSERT_PATH(old_path)
705
2008
  BufferValue new_path(env->isolate(), args[1]);
706
1005
  ASSERT_PATH(new_path)
707
708
2010
  if (args[2]->IsObject()) {
709

7000
    ASYNC_DEST_CALL(rename, args[2], *new_path, UTF8, *old_path, *new_path)
710
  } else {
711

5
    SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path)
712
1003
  }
713
}
714
715
38
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
716
38
  Environment* env = Environment::GetCurrent(args);
717
718
38
  if (args.Length() < 2)
719
    return TYPE_ERROR("fd and length are required");
720
76
  if (!args[0]->IsInt32())
721
    return TYPE_ERROR("fd must be a file descriptor");
722
723
76
  int fd = args[0]->Int32Value();
724
725
  // FIXME(bnoordhuis) It's questionable to reject non-ints here but still
726
  // allow implicit coercion from null or undefined to zero.  Probably best
727
  // handled in lib/fs.js.
728
38
  Local<Value> len_v(args[1]);
729

152
  if (!len_v->IsUndefined() &&
730

152
      !len_v->IsNull() &&
731
38
      !IsInt64(len_v->NumberValue())) {
732
    return env->ThrowTypeError("Not an integer");
733
  }
734
735
38
  const int64_t len = len_v->IntegerValue();
736
737
76
  if (args[2]->IsObject()) {
738

203
    ASYNC_CALL(ftruncate, args[2], UTF8, fd, len)
739
  } else {
740

9
    SYNC_CALL(ftruncate, 0, fd, len)
741
  }
742
}
743
744
2
static void Fdatasync(const FunctionCallbackInfo<Value>& args) {
745
2
  Environment* env = Environment::GetCurrent(args);
746
747
2
  if (args.Length() < 1)
748
    return TYPE_ERROR("fd is required");
749
4
  if (!args[0]->IsInt32())
750
    return TYPE_ERROR("fd must be a file descriptor");
751
752
4
  int fd = args[0]->Int32Value();
753
754
4
  if (args[1]->IsObject()) {
755

7
    ASYNC_CALL(fdatasync, args[1], UTF8, fd)
756
  } else {
757

1
    SYNC_CALL(fdatasync, 0, fd)
758
  }
759
}
760
761
19
static void Fsync(const FunctionCallbackInfo<Value>& args) {
762
19
  Environment* env = Environment::GetCurrent(args);
763
764
19
  if (args.Length() < 1)
765
    return TYPE_ERROR("fd is required");
766
38
  if (!args[0]->IsInt32())
767
    return TYPE_ERROR("fd must be a file descriptor");
768
769
38
  int fd = args[0]->Int32Value();
770
771
38
  if (args[1]->IsObject()) {
772

21
    ASYNC_CALL(fsync, args[1], UTF8, fd)
773
  } else {
774

16
    SYNC_CALL(fsync, 0, fd)
775
  }
776
}
777
778
4480
static void Unlink(const FunctionCallbackInfo<Value>& args) {
779
4480
  Environment* env = Environment::GetCurrent(args);
780
781
4480
  if (args.Length() < 1)
782
27
    return TYPE_ERROR("path required");
783
784
4480
  BufferValue path(env->isolate(), args[0]);
785
4480
  ASSERT_PATH(path)
786
787
8960
  if (args[1]->IsObject()) {
788

29673
    ASYNC_CALL(unlink, args[1], UTF8, *path)
789
  } else {
790

241
    SYNC_CALL(unlink, *path, *path)
791
4453
  }
792
}
793
794
1370
static void RMDir(const FunctionCallbackInfo<Value>& args) {
795
1370
  Environment* env = Environment::GetCurrent(args);
796
797
1370
  if (args.Length() < 1)
798
192
    return TYPE_ERROR("path required");
799
800
1370
  BufferValue path(env->isolate(), args[0]);
801
1370
  ASSERT_PATH(path)
802
803
2740
  if (args[1]->IsObject()) {
804

6426
    ASYNC_CALL(rmdir, args[1], UTF8, *path)
805
  } else {
806

452
    SYNC_CALL(rmdir, *path, *path)
807
1178
  }
808
}
809
810
13493
static void MKDir(const FunctionCallbackInfo<Value>& args) {
811
13493
  Environment* env = Environment::GetCurrent(args);
812
813
13493
  if (args.Length() < 2)
814
3612
    return TYPE_ERROR("path and mode are required");
815
26986
  if (!args[1]->IsInt32())
816
    return TYPE_ERROR("mode must be an integer");
817
818
13493
  BufferValue path(env->isolate(), args[0]);
819
13493
  ASSERT_PATH(path)
820
821
26986
  int mode = static_cast<int>(args[1]->Int32Value());
822
823
26986
  if (args[2]->IsObject()) {
824

67340
    ASYNC_CALL(mkdir, args[2], UTF8, *path, mode)
825
  } else {
826

3873
    SYNC_CALL(mkdir, *path, *path, mode)
827
9881
  }
828
}
829
830
static void RealPath(const FunctionCallbackInfo<Value>& args) {
831
  Environment* env = Environment::GetCurrent(args);
832
833
  const int argc = args.Length();
834
835
  if (argc < 1)
836
    return TYPE_ERROR("path required");
837
838
  BufferValue path(env->isolate(), args[0]);
839
  ASSERT_PATH(path)
840
841
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
842
843
  Local<Value> callback = Null(env->isolate());
844
  if (argc == 3)
845
    callback = args[2];
846
847
  if (callback->IsObject()) {
848
    ASYNC_CALL(realpath, callback, encoding, *path);
849
  } else {
850
    SYNC_CALL(realpath, *path, *path);
851
    const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
852
853
    Local<Value> error;
854
    MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
855
                                               link_path,
856
                                               encoding,
857
                                               &error);
858
    if (rc.IsEmpty()) {
859
      env->isolate()->ThrowException(error);
860
      return;
861
    }
862
    args.GetReturnValue().Set(rc.ToLocalChecked());
863
  }
864
}
865
866
2234
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
867
2234
  Environment* env = Environment::GetCurrent(args);
868
869
2234
  const int argc = args.Length();
870
871
2234
  if (argc < 1)
872
38
    return TYPE_ERROR("path required");
873
874
2234
  BufferValue path(env->isolate(), args[0]);
875
2234
  ASSERT_PATH(path)
876
877
2234
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
878
879
2234
  Local<Value> callback = Null(env->isolate());
880
2234
  if (argc == 3)
881
1057
    callback = args[2];
882
883
2234
  if (callback->IsObject()) {
884

5285
    ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/)
885
  } else {
886
1177
    SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
887
888
1139
    CHECK_GE(SYNC_REQ.result, 0);
889
    int r;
890
1139
    Local<Array> names = Array::New(env->isolate(), 0);
891
1139
    Local<Function> fn = env->push_values_to_array_function();
892
10251
    Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
893
1139
    size_t name_idx = 0;
894
895
29246
    for (int i = 0; ; i++) {
896
      uv_dirent_t ent;
897
898
29246
      r = uv_fs_scandir_next(&SYNC_REQ, &ent);
899
29246
      if (r == UV_EOF)
900
1139
        break;
901
28107
      if (r != 0)
902
        return env->ThrowUVException(r, "readdir", "", *path);
903
904
      Local<Value> error;
905
      MaybeLocal<Value> filename = StringBytes::Encode(env->isolate(),
906
                                                       ent.name,
907
                                                       encoding,
908
28107
                                                       &error);
909
28107
      if (filename.IsEmpty()) {
910
        env->isolate()->ThrowException(error);
911
        return;
912
      }
913
914
56214
      name_v[name_idx++] = filename.ToLocalChecked();
915
916
28107
      if (name_idx >= arraysize(name_v)) {
917
12124
        fn->Call(env->context(), names, name_idx, name_v)
918
6062
            .ToLocalChecked();
919
3031
        name_idx = 0;
920
      }
921
28107
    }
922
923
1139
    if (name_idx > 0) {
924
4408
      fn->Call(env->context(), names, name_idx, name_v).ToLocalChecked();
925
    }
926
927

2278
    args.GetReturnValue().Set(names);
928
2196
  }
929
}
930
931
66266
static void Open(const FunctionCallbackInfo<Value>& args) {
932
66266
  Environment* env = Environment::GetCurrent(args);
933
934
66266
  int len = args.Length();
935
66266
  if (len < 1)
936
9
    return TYPE_ERROR("path required");
937
66266
  if (len < 2)
938
    return TYPE_ERROR("flags required");
939
66266
  if (len < 3)
940
    return TYPE_ERROR("mode required");
941
132532
  if (!args[1]->IsInt32())
942
    return TYPE_ERROR("flags must be an int");
943
132532
  if (!args[2]->IsInt32())
944
    return TYPE_ERROR("mode must be an int");
945
946
66266
  BufferValue path(env->isolate(), args[0]);
947
66266
  ASSERT_PATH(path)
948
949
132532
  int flags = args[1]->Int32Value();
950
132532
  int mode = static_cast<int>(args[2]->Int32Value());
951
952
132532
  if (args[3]->IsObject()) {
953

229733
    ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
954
  } else {
955
33447
    SYNC_CALL(open, *path, *path, flags, mode)
956

66876
    args.GetReturnValue().Set(SYNC_RESULT);
957
66257
  }
958
}
959
960
961
17
static void CopyFile(const FunctionCallbackInfo<Value>& args) {
962
17
  Environment* env = Environment::GetCurrent(args);
963
964
51
  if (!args[0]->IsString())
965
6
    return TYPE_ERROR("src must be a string");
966
48
  if (!args[1]->IsString())
967
1
    return TYPE_ERROR("dest must be a string");
968
30
  if (!args[2]->IsInt32())
969
    return TYPE_ERROR("flags must be an int");
970
971
15
  BufferValue src(env->isolate(), args[0]);
972
15
  ASSERT_PATH(src)
973
27
  BufferValue dest(env->isolate(), args[1]);
974
15
  ASSERT_PATH(dest)
975
30
  int flags = args[2]->Int32Value();
976
977
30
  if (args[3]->IsObject()) {
978

14
    ASYNC_DEST_CALL(copyfile, args[3], *dest, UTF8, *src, *dest, flags)
979
  } else {
980

13
    SYNC_DEST_CALL(copyfile, *src, *dest, *src, *dest, flags)
981
12
  }
982
}
983
984
985
// Wrapper for write(2).
986
//
987
// bytesWritten = write(fd, buffer, offset, length, position, callback)
988
// 0 fd        integer. file descriptor
989
// 1 buffer    the data to write
990
// 2 offset    where in the buffer to start from
991
// 3 length    how much to write
992
// 4 position  if integer, position to write at in the file.
993
//             if null, write from the current position
994
35682
static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
995
35682
  Environment* env = Environment::GetCurrent(args);
996
997
71364
  if (!args[0]->IsInt32())
998
20881
    return env->ThrowTypeError("First argument must be file descriptor");
999
1000
35681
  CHECK(Buffer::HasInstance(args[1]));
1001
1002
71362
  int fd = args[0]->Int32Value();
1003
71362
  Local<Object> obj = args[1].As<Object>();
1004
35681
  const char* buf = Buffer::Data(obj);
1005
35681
  size_t buffer_length = Buffer::Length(obj);
1006
71362
  size_t off = args[2]->Uint32Value();
1007
71362
  size_t len = args[3]->Uint32Value();
1008

78740
  int64_t pos = GET_OFFSET(args[4]);
1009
35681
  Local<Value> req = args[5];
1010
1011
35681
  if (off > buffer_length)
1012
    return env->ThrowRangeError("offset out of bounds");
1013
35681
  if (len > buffer_length)
1014
    return env->ThrowRangeError("length out of bounds");
1015
35681
  if (off + len < off)
1016
    return env->ThrowRangeError("off + len overflow");
1017
35681
  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1018
    return env->ThrowRangeError("off + len > buffer.length");
1019
1020
35681
  buf += off;
1021
1022
35681
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1023
1024
35681
  if (req->IsObject()) {
1025

104395
    ASYNC_CALL(write, req, UTF8, fd, &uvbuf, 1, pos)
1026
20879
    return;
1027
  }
1028
1029
14802
  SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1030
29604
  args.GetReturnValue().Set(SYNC_RESULT);
1031
}
1032
1033
1034
// Wrapper for writev(2).
1035
//
1036
// bytesWritten = writev(fd, chunks, position, callback)
1037
// 0 fd        integer. file descriptor
1038
// 1 chunks    array of buffers to write
1039
// 2 position  if integer, position to write at in the file.
1040
//             if null, write from the current position
1041
203
static void WriteBuffers(const FunctionCallbackInfo<Value>& args) {
1042
203
  Environment* env = Environment::GetCurrent(args);
1043
1044
406
  CHECK(args[0]->IsInt32());
1045
406
  CHECK(args[1]->IsArray());
1046
1047
406
  int fd = args[0]->Int32Value();
1048
406
  Local<Array> chunks = args[1].As<Array>();
1049

406
  int64_t pos = GET_OFFSET(args[2]);
1050
203
  Local<Value> req = args[3];
1051
1052
203
  MaybeStackBuffer<uv_buf_t> iovs(chunks->Length());
1053
1054
2966805
  for (uint32_t i = 0; i < iovs.length(); i++) {
1055
2966602
    Local<Value> chunk = chunks->Get(i);
1056
1057
2966602
    if (!Buffer::HasInstance(chunk))
1058
      return env->ThrowTypeError("Array elements all need to be buffers");
1059
1060
2966602
    iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk));
1061
  }
1062
1063
203
  if (req->IsObject()) {
1064

1015
    ASYNC_CALL(write, req, UTF8, fd, *iovs, iovs.length(), pos)
1065
203
    return;
1066
  }
1067
1068
  SYNC_CALL(write, nullptr, fd, *iovs, iovs.length(), pos)
1069
  args.GetReturnValue().Set(SYNC_RESULT);
1070
}
1071
1072
1073
// Wrapper for write(2).
1074
//
1075
// bytesWritten = write(fd, string, position, enc, callback)
1076
// 0 fd        integer. file descriptor
1077
// 1 string    non-buffer values are converted to strings
1078
// 2 position  if integer, position to write at in the file.
1079
//             if null, write from the current position
1080
// 3 enc       encoding of string
1081
1028
static void WriteString(const FunctionCallbackInfo<Value>& args) {
1082
1028
  Environment* env = Environment::GetCurrent(args);
1083
1084
2056
  if (!args[0]->IsInt32())
1085
1
    return env->ThrowTypeError("First argument must be file descriptor");
1086
1087
  Local<Value> req;
1088
1027
  Local<Value> string = args[1];
1089
2054
  int fd = args[0]->Int32Value();
1090
1027
  char* buf = nullptr;
1091
  int64_t pos;
1092
  size_t len;
1093
1027
  FSReqWrap::Ownership ownership = FSReqWrap::COPY;
1094
1095
  // will assign buf and len if string was external
1096
1027
  if (!StringBytes::GetExternalParts(string,
1097
                                     const_cast<const char**>(&buf),
1098
1027
                                     &len)) {
1099
1027
    enum encoding enc = ParseEncoding(env->isolate(), args[3], UTF8);
1100
1027
    len = StringBytes::StorageSize(env->isolate(), string, enc);
1101
1027
    buf = new char[len];
1102
    // StorageSize may return too large a char, so correct the actual length
1103
    // by the write size
1104
1027
    len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
1105
1027
    ownership = FSReqWrap::MOVE;
1106
  }
1107

2672
  pos = GET_OFFSET(args[2]);
1108
1027
  req = args[4];
1109
1110
1027
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1111
1112
1027
  if (!req->IsObject()) {
1113
    // SYNC_CALL returns on error.  Make sure to always free the memory.
1114
    struct Delete {
1115
721
      inline explicit Delete(char* pointer) : pointer_(pointer) {}
1116
721
      inline ~Delete() { delete[] pointer_; }
1117
      char* const pointer_;
1118
    };
1119
721
    Delete delete_on_return(ownership == FSReqWrap::MOVE ? buf : nullptr);
1120
1442
    SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
1121
2163
    return args.GetReturnValue().Set(SYNC_RESULT);
1122
  }
1123
1124
  FSReqWrap* req_wrap =
1125
612
      FSReqWrap::New(env, req.As<Object>(), "write", buf, UTF8, ownership);
1126
  int err = uv_fs_write(env->event_loop(),
1127
                        req_wrap->req(),
1128
                        fd,
1129
                        &uvbuf,
1130
                        1,
1131
                        pos,
1132
306
                        After);
1133
306
  req_wrap->Dispatched();
1134
306
  if (err < 0) {
1135
    uv_fs_t* uv_req = req_wrap->req();
1136
    uv_req->result = err;
1137
    uv_req->path = nullptr;
1138
    After(uv_req);
1139
    return;
1140
  }
1141
1142
918
  return args.GetReturnValue().Set(req_wrap->persistent());
1143
}
1144
1145
1146
/*
1147
 * Wrapper for read(2).
1148
 *
1149
 * bytesRead = fs.read(fd, buffer, offset, length, position)
1150
 *
1151
 * 0 fd        integer. file descriptor
1152
 * 1 buffer    instance of Buffer
1153
 * 2 offset    integer. offset to start reading into inside buffer
1154
 * 3 length    integer. length to read
1155
 * 4 position  file position - null for current position
1156
 *
1157
 */
1158
53615
static void Read(const FunctionCallbackInfo<Value>& args) {
1159
53615
  Environment* env = Environment::GetCurrent(args);
1160
1161
53615
  if (args.Length() < 2)
1162
2
    return TYPE_ERROR("fd and buffer are required");
1163
107230
  if (!args[0]->IsInt32())
1164
    return TYPE_ERROR("fd must be a file descriptor");
1165
53615
  if (!Buffer::HasInstance(args[1]))
1166
2
    return TYPE_ERROR("Second argument needs to be a buffer");
1167
1168
107226
  int fd = args[0]->Int32Value();
1169
1170
  Local<Value> req;
1171
1172
  size_t len;
1173
  int64_t pos;
1174
1175
53613
  char * buf = nullptr;
1176
1177
160839
  Local<Object> buffer_obj = args[1]->ToObject(env->isolate());
1178
53613
  char *buffer_data = Buffer::Data(buffer_obj);
1179
53613
  size_t buffer_length = Buffer::Length(buffer_obj);
1180
1181
107226
  size_t off = args[2]->Int32Value();
1182
53613
  if (off >= buffer_length) {
1183
    return env->ThrowError("Offset is out of bounds");
1184
  }
1185
1186
107226
  len = args[3]->Int32Value();
1187
53613
  if (!Buffer::IsWithinBounds(off, len, buffer_length))
1188
    return env->ThrowRangeError("Length extends beyond buffer");
1189
1190

152328
  pos = GET_OFFSET(args[4]);
1191
1192
53613
  buf = buffer_data + off;
1193
1194
53613
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1195
1196
53613
  req = args[5];
1197
1198
53613
  if (req->IsObject()) {
1199

120770
    ASYNC_CALL(read, req, UTF8, fd, &uvbuf, 1, pos);
1200
  } else {
1201
29459
    SYNC_CALL(read, 0, fd, &uvbuf, 1, pos)
1202
58918
    args.GetReturnValue().Set(SYNC_RESULT);
1203
  }
1204
}
1205
1206
1207
/* fs.chmod(path, mode);
1208
 * Wrapper for chmod(1) / EIO_CHMOD
1209
 */
1210
9068
static void Chmod(const FunctionCallbackInfo<Value>& args) {
1211
9068
  Environment* env = Environment::GetCurrent(args);
1212
1213
9068
  if (args.Length() < 2)
1214
1
    return TYPE_ERROR("path and mode are required");
1215
18136
  if (!args[1]->IsInt32())
1216
    return TYPE_ERROR("mode must be an integer");
1217
1218
9068
  BufferValue path(env->isolate(), args[0]);
1219
9068
  ASSERT_PATH(path)
1220
1221
18136
  int mode = static_cast<int>(args[1]->Int32Value());
1222
1223
18136
  if (args[2]->IsObject()) {
1224

63406
    ASYNC_CALL(chmod, args[2], UTF8, *path, mode);
1225
  } else {
1226

10
    SYNC_CALL(chmod, *path, *path, mode);
1227
9067
  }
1228
}
1229
1230
1231
/* fs.fchmod(fd, mode);
1232
 * Wrapper for fchmod(1) / EIO_FCHMOD
1233
 */
1234
2
static void FChmod(const FunctionCallbackInfo<Value>& args) {
1235
2
  Environment* env = Environment::GetCurrent(args);
1236
1237
2
  if (args.Length() < 2)
1238
    return TYPE_ERROR("fd and mode are required");
1239
4
  if (!args[0]->IsInt32())
1240
    return TYPE_ERROR("fd must be a file descriptor");
1241
4
  if (!args[1]->IsInt32())
1242
    return TYPE_ERROR("mode must be an integer");
1243
1244
4
  int fd = args[0]->Int32Value();
1245
4
  int mode = static_cast<int>(args[1]->Int32Value());
1246
1247
4
  if (args[2]->IsObject()) {
1248

7
    ASYNC_CALL(fchmod, args[2], UTF8, fd, mode);
1249
  } else {
1250

1
    SYNC_CALL(fchmod, 0, fd, mode);
1251
  }
1252
}
1253
1254
1255
/* fs.chown(path, uid, gid);
1256
 * Wrapper for chown(1) / EIO_CHOWN
1257
 */
1258
282
static void Chown(const FunctionCallbackInfo<Value>& args) {
1259
282
  Environment* env = Environment::GetCurrent(args);
1260
1261
282
  int len = args.Length();
1262
282
  if (len < 1)
1263
    return TYPE_ERROR("path required");
1264
282
  if (len < 2)
1265
    return TYPE_ERROR("uid required");
1266
282
  if (len < 3)
1267
    return TYPE_ERROR("gid required");
1268
564
  if (!args[1]->IsUint32())
1269
    return TYPE_ERROR("uid must be an unsigned int");
1270
564
  if (!args[2]->IsUint32())
1271
    return TYPE_ERROR("gid must be an unsigned int");
1272
1273
282
  BufferValue path(env->isolate(), args[0]);
1274
282
  ASSERT_PATH(path)
1275
1276
564
  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1277
564
  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1278
1279
564
  if (args[3]->IsObject()) {
1280

1960
    ASYNC_CALL(chown, args[3], UTF8, *path, uid, gid);
1281
  } else {
1282

2
    SYNC_CALL(chown, *path, *path, uid, gid);
1283
282
  }
1284
}
1285
1286
1287
/* fs.fchown(fd, uid, gid);
1288
 * Wrapper for fchown(1) / EIO_FCHOWN
1289
 */
1290
static void FChown(const FunctionCallbackInfo<Value>& args) {
1291
  Environment* env = Environment::GetCurrent(args);
1292
1293
  int len = args.Length();
1294
  if (len < 1)
1295
    return TYPE_ERROR("fd required");
1296
  if (len < 2)
1297
    return TYPE_ERROR("uid required");
1298
  if (len < 3)
1299
    return TYPE_ERROR("gid required");
1300
  if (!args[0]->IsInt32())
1301
    return TYPE_ERROR("fd must be an int");
1302
  if (!args[1]->IsUint32())
1303
    return TYPE_ERROR("uid must be an unsigned int");
1304
  if (!args[2]->IsUint32())
1305
    return TYPE_ERROR("gid must be an unsigned int");
1306
1307
  int fd = args[0]->Int32Value();
1308
  uv_uid_t uid = static_cast<uv_uid_t>(args[1]->Uint32Value());
1309
  uv_gid_t gid = static_cast<uv_gid_t>(args[2]->Uint32Value());
1310
1311
  if (args[3]->IsObject()) {
1312
    ASYNC_CALL(fchown, args[3], UTF8, fd, uid, gid);
1313
  } else {
1314
    SYNC_CALL(fchown, 0, fd, uid, gid);
1315
  }
1316
}
1317
1318
1319
8725
static void UTimes(const FunctionCallbackInfo<Value>& args) {
1320
8725
  Environment* env = Environment::GetCurrent(args);
1321
1322
8725
  int len = args.Length();
1323
8725
  if (len < 1)
1324
6
    return TYPE_ERROR("path required");
1325
8725
  if (len < 2)
1326
    return TYPE_ERROR("atime required");
1327
8725
  if (len < 3)
1328
    return TYPE_ERROR("mtime required");
1329
17450
  if (!args[1]->IsNumber())
1330
    return TYPE_ERROR("atime must be a number");
1331
17450
  if (!args[2]->IsNumber())
1332
    return TYPE_ERROR("mtime must be a number");
1333
1334
8725
  BufferValue path(env->isolate(), args[0]);
1335
8725
  ASSERT_PATH(path)
1336
1337
17450
  const double atime = static_cast<double>(args[1]->NumberValue());
1338
17450
  const double mtime = static_cast<double>(args[2]->NumberValue());
1339
1340
17450
  if (args[3]->IsObject()) {
1341

60984
    ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime);
1342
  } else {
1343

13
    SYNC_CALL(utime, *path, *path, atime, mtime);
1344
8719
  }
1345
}
1346
1347
24
static void FUTimes(const FunctionCallbackInfo<Value>& args) {
1348
24
  Environment* env = Environment::GetCurrent(args);
1349
1350
24
  int len = args.Length();
1351
24
  if (len < 1)
1352
    return TYPE_ERROR("fd required");
1353
24
  if (len < 2)
1354
    return TYPE_ERROR("atime required");
1355
24
  if (len < 3)
1356
    return TYPE_ERROR("mtime required");
1357
48
  if (!args[0]->IsInt32())
1358
    return TYPE_ERROR("fd must be an int");
1359
48
  if (!args[1]->IsNumber())
1360
    return TYPE_ERROR("atime must be a number");
1361
48
  if (!args[2]->IsNumber())
1362
    return TYPE_ERROR("mtime must be a number");
1363
1364
48
  const int fd = args[0]->Int32Value();
1365
48
  const double atime = static_cast<double>(args[1]->NumberValue());
1366
48
  const double mtime = static_cast<double>(args[2]->NumberValue());
1367
1368
48
  if (args[3]->IsObject()) {
1369

84
    ASYNC_CALL(futime, args[3], UTF8, fd, atime, mtime);
1370
  } else {
1371

12
    SYNC_CALL(futime, 0, fd, atime, mtime);
1372
  }
1373
}
1374
1375
12
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
1376
12
  Environment* env = Environment::GetCurrent(args);
1377
1378
12
  CHECK_GE(args.Length(), 2);
1379
1380
12
  BufferValue tmpl(env->isolate(), args[0]);
1381
12
  if (*tmpl == nullptr)
1382
    return TYPE_ERROR("template must be a string or Buffer");
1383
1384
12
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
1385
1386
24
  if (args[2]->IsObject()) {
1387

42
    ASYNC_CALL(mkdtemp, args[2], encoding, *tmpl);
1388
  } else {
1389
6
    SYNC_CALL(mkdtemp, *tmpl, *tmpl);
1390
6
    const char* path = static_cast<const char*>(SYNC_REQ.path);
1391
1392
    Local<Value> error;
1393
    MaybeLocal<Value> rc =
1394
6
        StringBytes::Encode(env->isolate(), path, encoding, &error);
1395
6
    if (rc.IsEmpty()) {
1396
      env->isolate()->ThrowException(error);
1397
      return;
1398
    }
1399

12
    args.GetReturnValue().Set(rc.ToLocalChecked());
1400
12
  }
1401
}
1402
1403
3200
void GetStatValues(const FunctionCallbackInfo<Value>& args) {
1404
3200
  Environment* env = Environment::GetCurrent(args);
1405
3200
  double* fields = env->fs_stats_field_array();
1406
3200
  if (fields == nullptr) {
1407
    // stat fields contains twice the number of entries because `fs.StatWatcher`
1408
    // needs room to store data for *two* `fs.Stats` instances.
1409
3200
    fields = new double[2 * 14];
1410
3200
    env->set_fs_stats_field_array(fields);
1411
  }
1412
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(),
1413
                                           fields,
1414
3200
                                           sizeof(double) * 2 * 14);
1415
3200
  Local<Float64Array> fields_array = Float64Array::New(ab, 0, 2 * 14);
1416
6400
  args.GetReturnValue().Set(fields_array);
1417
3200
}
1418
1419
3200
void InitFs(Local<Object> target,
1420
            Local<Value> unused,
1421
            Local<Context> context,
1422
            void* priv) {
1423
3200
  Environment* env = Environment::GetCurrent(context);
1424
1425
3200
  env->SetMethod(target, "access", Access);
1426
3200
  env->SetMethod(target, "close", Close);
1427
3200
  env->SetMethod(target, "open", Open);
1428
3200
  env->SetMethod(target, "read", Read);
1429
3200
  env->SetMethod(target, "fdatasync", Fdatasync);
1430
3200
  env->SetMethod(target, "fsync", Fsync);
1431
3200
  env->SetMethod(target, "rename", Rename);
1432
3200
  env->SetMethod(target, "ftruncate", FTruncate);
1433
3200
  env->SetMethod(target, "rmdir", RMDir);
1434
3200
  env->SetMethod(target, "mkdir", MKDir);
1435
3200
  env->SetMethod(target, "readdir", ReadDir);
1436
3200
  env->SetMethod(target, "internalModuleReadFile", InternalModuleReadFile);
1437
3200
  env->SetMethod(target, "internalModuleStat", InternalModuleStat);
1438
3200
  env->SetMethod(target, "stat", Stat);
1439
3200
  env->SetMethod(target, "lstat", LStat);
1440
3200
  env->SetMethod(target, "fstat", FStat);
1441
3200
  env->SetMethod(target, "link", Link);
1442
3200
  env->SetMethod(target, "symlink", Symlink);
1443
3200
  env->SetMethod(target, "readlink", ReadLink);
1444
3200
  env->SetMethod(target, "unlink", Unlink);
1445
3200
  env->SetMethod(target, "writeBuffer", WriteBuffer);
1446
3200
  env->SetMethod(target, "writeBuffers", WriteBuffers);
1447
3200
  env->SetMethod(target, "writeString", WriteString);
1448
3200
  env->SetMethod(target, "realpath", RealPath);
1449
3200
  env->SetMethod(target, "copyFile", CopyFile);
1450
1451
3200
  env->SetMethod(target, "chmod", Chmod);
1452
3200
  env->SetMethod(target, "fchmod", FChmod);
1453
  // env->SetMethod(target, "lchmod", LChmod);
1454
1455
3200
  env->SetMethod(target, "chown", Chown);
1456
3200
  env->SetMethod(target, "fchown", FChown);
1457
  // env->SetMethod(target, "lchown", LChown);
1458
1459
3200
  env->SetMethod(target, "utimes", UTimes);
1460
3200
  env->SetMethod(target, "futimes", FUTimes);
1461
1462
3200
  env->SetMethod(target, "mkdtemp", Mkdtemp);
1463
1464
3200
  env->SetMethod(target, "getStatValues", GetStatValues);
1465
1466
3200
  StatWatcher::Initialize(env, target);
1467
1468
  // Create FunctionTemplate for FSReqWrap
1469
  Local<FunctionTemplate> fst =
1470
3200
      FunctionTemplate::New(env->isolate(), NewFSReqWrap);
1471
6400
  fst->InstanceTemplate()->SetInternalFieldCount(1);
1472
3200
  AsyncWrap::AddWrapMethods(env, fst);
1473
  Local<String> wrapString =
1474
3200
      FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap");
1475
3200
  fst->SetClassName(wrapString);
1476
6400
  target->Set(wrapString, fst->GetFunction());
1477
3200
}
1478
1479
}  // end namespace node
1480
1481
3245
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs, node::InitFs)