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: 660 758 87.1 %
Date: 2017-11-19 Branches: 464 695 66.8 %

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-inl.h"
27
#include "string_bytes.h"
28
#include "string_search.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
363271
  void ReleaseEarly() {
84
363271
    if (data_ != inline_data()) {
85
361114
      delete[] data_;
86
361114
      data_ = nullptr;
87
    }
88
363271
  }
89
90
15419
  const char* syscall() const { return syscall_; }
91
15419
  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
181642
  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
181642
        data_(data) {
106
181642
    Wrap(object(), this);
107
181642
  }
108
109
363264
  ~FSReqWrap() {
110
181632
    ReleaseEarly();
111
181632
    ClearWrap(object());
112
181632
  }
113
114
  void* operator new(size_t size) = delete;
115
181642
  void* operator new(size_t size, char* storage) { return storage; }
116
364350
  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
181642
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

181642
  const bool copy = (data != nullptr && ownership == COPY);
135
181642
  const size_t size = copy ? 1 + strlen(data) : 0;
136
  FSReqWrap* that;
137
181642
  char* const storage = new char[sizeof(*that) + size];
138
181642
  that = new(storage) FSReqWrap(env, req, syscall, data, encoding);
139
181642
  if (copy)
140
1079
    that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
141
181642
  return that;
142
}
143
144
145
181632
void FSReqWrap::Dispose() {
146
181632
  this->~FSReqWrap();
147
181632
  delete[] reinterpret_cast<char*>(this);
148
181632
}
149
150
151
181652
void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
152
181652
  CHECK(args.IsConstructCall());
153
181652
  ClearWrap(args.This());
154
181652
}
155
156
157
38
inline bool IsInt64(double x) {
158
38
  return x == static_cast<double>(static_cast<int64_t>(x));
159
}
160
161
181639
void After(uv_fs_t *req) {
162
181639
  FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
163
181639
  CHECK_EQ(req_wrap->req(), req);
164
181639
  req_wrap->ReleaseEarly();  // Free memory that's no longer used now.
165
166
181639
  Environment* env = req_wrap->env();
167
181639
  HandleScope handle_scope(env->isolate());
168
181639
  Context::Scope context_scope(env->context());
169
170
  // there is always at least one argument. "error"
171
181639
  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
544917
  Local<Value> argv[2];
176
  MaybeLocal<Value> link;
177
  Local<Value> error;
178
179
181639
  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
15419
                          req_wrap->data());
187
  } else {
188
    // error value is empty or null for non-error.
189
332440
    argv[0] = Null(env->isolate());
190
191
    // All have at least two args now.
192
166220
    argc = 2;
193
194


166220
    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
39733
        argc = 1;
214
39733
        break;
215
216
      case UV_FS_STAT:
217
      case UV_FS_LSTAT:
218
      case UV_FS_FSTAT:
219
37566
        argc = 1;
220
        FillStatsArray(env->fs_stats_field_array(),
221
37566
                       static_cast<const uv_stat_t*>(req->ptr));
222
37566
        break;
223
224
      case UV_FS_UTIME:
225
      case UV_FS_FUTIME:
226
8694
        argc = 0;
227
8694
        break;
228
229
      case UV_FS_OPEN:
230
64658
        argv[1] = Integer::New(env->isolate(), req->result);
231
32329
        break;
232
233
      case UV_FS_WRITE:
234
42512
        argv[1] = Integer::New(env->isolate(), req->result);
235
21256
        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
13
                                   &error);
268
13
        if (link.IsEmpty()) {
269
          argv[0] = error;
270
        } else {
271
13
          argv[1] = link.ToLocalChecked();
272
        }
273
13
        break;
274
275
      case UV_FS_READ:
276
        // Buffer interface
277
51104
        argv[1] = Integer::New(env->isolate(), req->result);
278
25552
        break;
279
280
      case UV_FS_SCANDIR:
281
        {
282
          int r;
283
1044
          Local<Array> names = Array::New(env->isolate(), 0);
284
1044
          Local<Function> fn = env->push_values_to_array_function();
285
9396
          Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
286
1044
          size_t name_idx = 0;
287
288
14092
          for (int i = 0; ; i++) {
289
            uv_dirent_t ent;
290
291
14092
            r = uv_fs_scandir_next(req, &ent);
292
14092
            if (r == UV_EOF)
293
2088
              break;
294
13048
            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
13048
                                    &error);
307
13048
            if (filename.IsEmpty()) {
308
              argv[0] = error;
309
              break;
310
            }
311
26096
            name_argv[name_idx++] = filename.ToLocalChecked();
312
313
13048
            if (name_idx >= arraysize(name_argv)) {
314
4512
              fn->Call(env->context(), names, name_idx, name_argv)
315
2256
                  .ToLocalChecked();
316
1128
              name_idx = 0;
317
            }
318
13048
          }
319
320
1044
          if (name_idx > 0) {
321
3996
            fn->Call(env->context(), names, name_idx, name_argv)
322
1998
                .ToLocalChecked();
323
          }
324
325
1044
          argv[1] = names;
326
        }
327
1044
        break;
328
329
      default:
330
        CHECK(0 && "Unhandled eio response");
331
    }
332
  }
333
334
181639
  req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
335
336
181632
  uv_fs_req_cleanup(req_wrap->req());
337
363264
  req_wrap->Dispose();
338
181632
}
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
242087
  fs_req_wrap() {}
345
242087
  ~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
175
void Access(const FunctionCallbackInfo<Value>& args) {
395
175
  Environment* env = Environment::GetCurrent(args.GetIsolate());
396
175
  HandleScope scope(env->isolate());
397
398
175
  if (args.Length() < 2)
399
    return TYPE_ERROR("path and mode are required");
400
350
  if (!args[1]->IsInt32())
401
    return TYPE_ERROR("mode must be an integer");
402
403
275
  BufferValue path(env->isolate(), args[0]);
404
175
  ASSERT_PATH(path)
405
406
346
  int mode = static_cast<int>(args[1]->Int32Value());
407
408
346
  if (args[2]->IsObject()) {
409

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

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

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

32340
    SYNC_CALL(close, 0, fd)
430
  }
431
}
432
433
}  // anonymous namespace
434
435
164028
void FillStatsArray(double* fields, const uv_stat_t* s) {
436
164028
  fields[0] = s->st_dev;
437
164028
  fields[1] = s->st_mode;
438
164028
  fields[2] = s->st_nlink;
439
164028
  fields[3] = s->st_uid;
440
164028
  fields[4] = s->st_gid;
441
164028
  fields[5] = s->st_rdev;
442
#if defined(__POSIX__)
443
164028
  fields[6] = s->st_blksize;
444
#else
445
  fields[6] = -1;
446
#endif
447
164028
  fields[7] = s->st_ino;
448
164028
  fields[8] = s->st_size;
449
#if defined(__POSIX__)
450
164028
  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
164028
  X(10, atim)
463
164028
  X(11, mtim)
464
164028
  X(12, ctim)
465
164028
  X(13, birthtim)
466
#undef X
467
164028
}
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.  Returns an empty
471
// string when the file does not contain the substring '"main"' because that
472
// is the property we care about.
473
12583
static void InternalModuleReadFile(const FunctionCallbackInfo<Value>& args) {
474
12583
  Environment* env = Environment::GetCurrent(args);
475
12583
  uv_loop_t* loop = env->event_loop();
476
477
37749
  CHECK(args[0]->IsString());
478
12583
  node::Utf8Value path(env->isolate(), args[0]);
479
480
12583
  if (strlen(*path) != path.length())
481
2
    return;  // Contains a nul byte.
482
483
  uv_fs_t open_req;
484
12581
  const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
485
12581
  uv_fs_req_cleanup(&open_req);
486
487
12581
  if (fd < 0) {
488
5971
    return;
489
  }
490
491
6610
  const size_t kBlockSize = 32 << 10;
492
13220
  std::vector<char> chars;
493
6610
  int64_t offset = 0;
494
  ssize_t numchars;
495
6610
  do {
496
6610
    const size_t start = chars.size();
497
6610
    chars.resize(start + kBlockSize);
498
499
    uv_buf_t buf;
500
6610
    buf.base = &chars[start];
501
6610
    buf.len = kBlockSize;
502
503
    uv_fs_t read_req;
504
6610
    numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
505
6610
    uv_fs_req_cleanup(&read_req);
506
507
6610
    CHECK_GE(numchars, 0);
508
6610
    offset += numchars;
509
  } while (static_cast<size_t>(numchars) == kBlockSize);
510
511
  uv_fs_t close_req;
512
6610
  CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
513
6610
  uv_fs_req_cleanup(&close_req);
514
515
6610
  size_t start = 0;
516

6610
  if (offset >= 3 && 0 == memcmp(&chars[0], "\xEF\xBB\xBF", 3)) {
517
1
    start = 3;  // Skip UTF-8 BOM.
518
  }
519
520
6610
  const size_t size = offset - start;
521

6610
  if (size == 0 || size == SearchString(&chars[start], size, "\"main\"")) {
522
5756
    args.GetReturnValue().SetEmptyString();
523
  } else {
524
    Local<String> chars_string =
525
        String::NewFromUtf8(env->isolate(),
526
3732
                            &chars[start],
527
                            String::kNormalString,
528
7464
                            size);
529
7464
    args.GetReturnValue().Set(chars_string);
530
6610
  }
531
}
532
533
// Used to speed up module loading.  Returns 0 if the path refers to
534
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
535
// The speedup comes from not creating thousands of Stat and Error objects.
536
84344
static void InternalModuleStat(const FunctionCallbackInfo<Value>& args) {
537
84344
  Environment* env = Environment::GetCurrent(args);
538
539
253032
  CHECK(args[0]->IsString());
540
84344
  node::Utf8Value path(env->isolate(), args[0]);
541
542
  uv_fs_t req;
543
84344
  int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr);
544
84344
  if (rc == 0) {
545
50023
    const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
546
50023
    rc = !!(s->st_mode & S_IFDIR);
547
  }
548
84344
  uv_fs_req_cleanup(&req);
549
550
168688
  args.GetReturnValue().Set(rc);
551
84344
}
552
553
24702
static void Stat(const FunctionCallbackInfo<Value>& args) {
554
24702
  Environment* env = Environment::GetCurrent(args);
555
556
24702
  if (args.Length() < 1)
557
4
    return TYPE_ERROR("path required");
558
559
24702
  BufferValue path(env->isolate(), args[0]);
560
24702
  ASSERT_PATH(path)
561
562
49404
  if (args[1]->IsObject()) {
563

12726
    ASYNC_CALL(stat, args[1], UTF8, *path)
564
  } else {
565
22884
    SYNC_CALL(stat, *path, *path)
566
    FillStatsArray(env->fs_stats_field_array(),
567

22880
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
568
24698
  }
569
}
570
571
99816
static void LStat(const FunctionCallbackInfo<Value>& args) {
572
99816
  Environment* env = Environment::GetCurrent(args);
573
574
99816
  if (args.Length() < 1)
575
1
    return TYPE_ERROR("path required");
576
577
99816
  BufferValue path(env->isolate(), args[0]);
578
99816
  ASSERT_PATH(path)
579
580
199632
  if (args[1]->IsObject()) {
581

173159
    ASYNC_CALL(lstat, args[1], UTF8, *path)
582
  } else {
583
75079
    SYNC_CALL(lstat, *path, *path)
584
    FillStatsArray(env->fs_stats_field_array(),
585

75078
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
586
99815
  }
587
}
588
589
51198
static void FStat(const FunctionCallbackInfo<Value>& args) {
590
51198
  Environment* env = Environment::GetCurrent(args);
591
592
51198
  if (args.Length() < 1)
593
    return TYPE_ERROR("fd is required");
594
102396
  if (!args[0]->IsInt32())
595
    return TYPE_ERROR("fd must be a file descriptor");
596
597
102396
  int fd = args[0]->Int32Value();
598
599
102396
  if (args[1]->IsObject()) {
600

158879
    ASYNC_CALL(fstat, args[1], UTF8, fd)
601
  } else {
602
28501
    SYNC_CALL(fstat, nullptr, fd)
603
    FillStatsArray(env->fs_stats_field_array(),
604
28498
                   static_cast<const uv_stat_t*>(SYNC_REQ.ptr));
605
  }
606
}
607
608
79
static void Symlink(const FunctionCallbackInfo<Value>& args) {
609
79
  Environment* env = Environment::GetCurrent(args);
610
611
79
  int len = args.Length();
612
79
  if (len < 1)
613
1
    return TYPE_ERROR("target path required");
614
79
  if (len < 2)
615
    return TYPE_ERROR("src path required");
616
617
79
  BufferValue target(env->isolate(), args[0]);
618
79
  ASSERT_PATH(target)
619
157
  BufferValue path(env->isolate(), args[1]);
620
79
  ASSERT_PATH(path)
621
622
79
  int flags = 0;
623
624
237
  if (args[2]->IsString()) {
625
50
    node::Utf8Value mode(env->isolate(), args[2]);
626
50
    if (strcmp(*mode, "dir") == 0) {
627
20
      flags |= UV_FS_SYMLINK_DIR;
628
30
    } else if (strcmp(*mode, "junction") == 0) {
629
18
      flags |= UV_FS_SYMLINK_JUNCTION;
630
12
    } else if (strcmp(*mode, "file") != 0) {
631
      return env->ThrowError("Unknown symlink type");
632
50
    }
633
  }
634
635
158
  if (args[3]->IsObject()) {
636

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

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

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

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

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

74
    args.GetReturnValue().Set(rc.ToLocalChecked());
697
79
  }
698
}
699
700
993
static void Rename(const FunctionCallbackInfo<Value>& args) {
701
993
  Environment* env = Environment::GetCurrent(args);
702
703
993
  int len = args.Length();
704
993
  if (len < 1)
705
2
    return TYPE_ERROR("old path required");
706
993
  if (len < 2)
707
    return TYPE_ERROR("new path required");
708
709
993
  BufferValue old_path(env->isolate(), args[0]);
710
993
  ASSERT_PATH(old_path)
711
1984
  BufferValue new_path(env->isolate(), args[1]);
712
993
  ASSERT_PATH(new_path)
713
714
1986
  if (args[2]->IsObject()) {
715

6937
    ASYNC_DEST_CALL(rename, args[2], *new_path, UTF8, *old_path, *new_path)
716
  } else {
717

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

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

152
      !len_v->IsNull() &&
737
38
      !IsInt64(len_v->NumberValue())) {
738
    return env->ThrowTypeError("Not an integer");
739
  }
740
741
38
  const int64_t len = len_v->IntegerValue();
742
743
76
  if (args[2]->IsObject()) {
744

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

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

7
    ASYNC_CALL(fdatasync, args[1], UTF8, fd)
762
  } else {
763

1
    SYNC_CALL(fdatasync, 0, fd)
764
  }
765
}
766
767
16
static void Fsync(const FunctionCallbackInfo<Value>& args) {
768
16
  Environment* env = Environment::GetCurrent(args);
769
770
16
  if (args.Length() < 1)
771
    return TYPE_ERROR("fd is required");
772
32
  if (!args[0]->IsInt32())
773
    return TYPE_ERROR("fd must be a file descriptor");
774
775
32
  int fd = args[0]->Int32Value();
776
777
32
  if (args[1]->IsObject()) {
778

21
    ASYNC_CALL(fsync, args[1], UTF8, fd)
779
  } else {
780

13
    SYNC_CALL(fsync, 0, fd)
781
  }
782
}
783
784
4502
static void Unlink(const FunctionCallbackInfo<Value>& args) {
785
4502
  Environment* env = Environment::GetCurrent(args);
786
787
4502
  if (args.Length() < 1)
788
30
    return TYPE_ERROR("path required");
789
790
4502
  BufferValue path(env->isolate(), args[0]);
791
4502
  ASSERT_PATH(path)
792
793
9004
  if (args[1]->IsObject()) {
794

29610
    ASYNC_CALL(unlink, args[1], UTF8, *path)
795
  } else {
796

272
    SYNC_CALL(unlink, *path, *path)
797
4472
  }
798
}
799
800
1389
static void RMDir(const FunctionCallbackInfo<Value>& args) {
801
1389
  Environment* env = Environment::GetCurrent(args);
802
803
1389
  if (args.Length() < 1)
804
199
    return TYPE_ERROR("path required");
805
806
1389
  BufferValue path(env->isolate(), args[0]);
807
1389
  ASSERT_PATH(path)
808
809
2778
  if (args[1]->IsObject()) {
810

6405
    ASYNC_CALL(rmdir, args[1], UTF8, *path)
811
  } else {
812

474
    SYNC_CALL(rmdir, *path, *path)
813
1190
  }
814
}
815
816
6844
static void MKDir(const FunctionCallbackInfo<Value>& args) {
817
6844
  Environment* env = Environment::GetCurrent(args);
818
819
6844
  if (args.Length() < 2)
820
3709
    return TYPE_ERROR("path and mode are required");
821
13688
  if (!args[1]->IsInt32())
822
    return TYPE_ERROR("mode must be an integer");
823
824
6844
  BufferValue path(env->isolate(), args[0]);
825
6844
  ASSERT_PATH(path)
826
827
13688
  int mode = static_cast<int>(args[1]->Int32Value());
828
829
13688
  if (args[2]->IsObject()) {
830

20006
    ASYNC_CALL(mkdir, args[2], UTF8, *path, mode)
831
  } else {
832

3986
    SYNC_CALL(mkdir, *path, *path, mode)
833
3135
  }
834
}
835
836
30
static void RealPath(const FunctionCallbackInfo<Value>& args) {
837
30
  CHECK_GE(args.Length(), 2);
838
30
  Environment* env = Environment::GetCurrent(args);
839
30
  BufferValue path(env->isolate(), args[0]);
840
30
  ASSERT_PATH(path)
841
842
30
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
843
844
60
  if (args[2]->IsObject()) {
845

105
    ASYNC_CALL(realpath, args[2], encoding, *path);
846
  } else {
847
15
    SYNC_CALL(realpath, *path, *path);
848
14
    const char* link_path = static_cast<const char*>(SYNC_REQ.ptr);
849
850
    Local<Value> error;
851
    MaybeLocal<Value> rc = StringBytes::Encode(env->isolate(),
852
                                               link_path,
853
                                               encoding,
854
14
                                               &error);
855
14
    if (rc.IsEmpty()) {
856
      env->isolate()->ThrowException(error);
857
      return;
858
    }
859

28
    args.GetReturnValue().Set(rc.ToLocalChecked());
860
29
  }
861
}
862
863
2288
static void ReadDir(const FunctionCallbackInfo<Value>& args) {
864
2288
  Environment* env = Environment::GetCurrent(args);
865
866
2288
  const int argc = args.Length();
867
868
2288
  if (argc < 1)
869
38
    return TYPE_ERROR("path required");
870
871
2288
  BufferValue path(env->isolate(), args[0]);
872
2288
  ASSERT_PATH(path)
873
874
2288
  const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8);
875
876
2288
  Local<Value> callback = Null(env->isolate());
877
2288
  if (argc == 3)
878
1046
    callback = args[2];
879
880
2288
  if (callback->IsObject()) {
881

5230
    ASYNC_CALL(scandir, callback, encoding, *path, 0 /*flags*/)
882
  } else {
883
1242
    SYNC_CALL(scandir, *path, *path, 0 /*flags*/)
884
885
1204
    CHECK_GE(SYNC_REQ.result, 0);
886
    int r;
887
1204
    Local<Array> names = Array::New(env->isolate(), 0);
888
1204
    Local<Function> fn = env->push_values_to_array_function();
889
10836
    Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX];
890
1204
    size_t name_idx = 0;
891
892
30788
    for (int i = 0; ; i++) {
893
      uv_dirent_t ent;
894
895
30788
      r = uv_fs_scandir_next(&SYNC_REQ, &ent);
896
30788
      if (r == UV_EOF)
897
1204
        break;
898
29584
      if (r != 0)
899
        return env->ThrowUVException(r, "readdir", "", *path);
900
901
      Local<Value> error;
902
      MaybeLocal<Value> filename = StringBytes::Encode(env->isolate(),
903
                                                       ent.name,
904
                                                       encoding,
905
29584
                                                       &error);
906
29584
      if (filename.IsEmpty()) {
907
        env->isolate()->ThrowException(error);
908
        return;
909
      }
910
911
59168
      name_v[name_idx++] = filename.ToLocalChecked();
912
913
29584
      if (name_idx >= arraysize(name_v)) {
914
12816
        fn->Call(env->context(), names, name_idx, name_v)
915
6408
            .ToLocalChecked();
916
3204
        name_idx = 0;
917
      }
918
29584
    }
919
920
1204
    if (name_idx > 0) {
921
4668
      fn->Call(env->context(), names, name_idx, name_v).ToLocalChecked();
922
    }
923
924

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

235690
    ASYNC_CALL(open, args[3], UTF8, *path, flags, mode)
951
  } else {
952
32672
    SYNC_CALL(open, *path, *path, flags, mode)
953

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

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

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

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

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

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

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

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

153946
  pos = GET_OFFSET(args[4]);
1188
1189
54136
  buf = buffer_data + off;
1190
1191
54136
  uv_buf_t uvbuf = uv_buf_init(const_cast<char*>(buf), len);
1192
1193
54136
  req = args[5];
1194
1195
54136
  if (req->IsObject()) {
1196

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

2562
    ASYNC_CALL(chmod, args[2], UTF8, *path, mode);
1222
  } else {
1223

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

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

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

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

60858
    ASYNC_CALL(utime, args[3], UTF8, *path, atime, mtime);
1339
  } else {
1340

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

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

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

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

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