GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/fs_event_wrap.cc Lines: 63 71 88.7 %
Date: 2016-12-18 Branches: 23 38 60.5 %

Line Branch Exec Source
1
#include "async-wrap.h"
2
#include "async-wrap-inl.h"
3
#include "env.h"
4
#include "env-inl.h"
5
#include "util.h"
6
#include "util-inl.h"
7
#include "node.h"
8
#include "handle_wrap.h"
9
#include "string_bytes.h"
10
11
#include <stdlib.h>
12
13
namespace node {
14
15
using v8::Context;
16
using v8::FunctionCallbackInfo;
17
using v8::FunctionTemplate;
18
using v8::HandleScope;
19
using v8::Integer;
20
using v8::Local;
21
using v8::Object;
22
using v8::String;
23
using v8::Value;
24
25
class FSEventWrap: public HandleWrap {
26
 public:
27
  static void Initialize(Local<Object> target,
28
                         Local<Value> unused,
29
                         Local<Context> context);
30
  static void New(const FunctionCallbackInfo<Value>& args);
31
  static void Start(const FunctionCallbackInfo<Value>& args);
32
  static void Close(const FunctionCallbackInfo<Value>& args);
33
34
  size_t self_size() const override { return sizeof(*this); }
35
36
 private:
37
  static const encoding kDefaultEncoding = UTF8;
38
39
  FSEventWrap(Environment* env, Local<Object> object);
40
  ~FSEventWrap() override;
41
42
  static void OnEvent(uv_fs_event_t* handle, const char* filename, int events,
43
    int status);
44
45
  uv_fs_event_t handle_;
46
  bool initialized_ = false;
47
  enum encoding encoding_ = kDefaultEncoding;
48
};
49
50
51
FSEventWrap::FSEventWrap(Environment* env, Local<Object> object)
52
    : HandleWrap(env,
53
                 object,
54
                 reinterpret_cast<uv_handle_t*>(&handle_),
55
12
                 AsyncWrap::PROVIDER_FSEVENTWRAP) {}
56
57
58
33
FSEventWrap::~FSEventWrap() {
59
11
  CHECK_EQ(initialized_, false);
60
22
}
61
62
63
1727
void FSEventWrap::Initialize(Local<Object> target,
64
                             Local<Value> unused,
65
                             Local<Context> context) {
66
1727
  Environment* env = Environment::GetCurrent(context);
67
68
1727
  auto fsevent_string = FIXED_ONE_BYTE_STRING(env->isolate(), "FSEvent");
69
3454
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
70
3454
  t->InstanceTemplate()->SetInternalFieldCount(1);
71
1727
  t->SetClassName(fsevent_string);
72
73
1727
  env->SetProtoMethod(t, "start", Start);
74
1727
  env->SetProtoMethod(t, "close", Close);
75
76
6908
  target->Set(fsevent_string, t->GetFunction());
77
1727
}
78
79
80
12
void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
81
12
  CHECK(args.IsConstructCall());
82
12
  Environment* env = Environment::GetCurrent(args);
83
24
  new FSEventWrap(env, args.This());
84
12
}
85
86
87
12
void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
88
12
  Environment* env = Environment::GetCurrent(args);
89
90
  FSEventWrap* wrap;
91
12
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
92
12
  CHECK_EQ(wrap->initialized_, false);
93
94
  static const char kErrMsg[] = "filename must be a string or Buffer";
95
12
  if (args.Length() < 1)
96
    return env->ThrowTypeError(kErrMsg);
97
98
24
  BufferValue path(env->isolate(), args[0]);
99
12
  if (*path == nullptr)
100
    return env->ThrowTypeError(kErrMsg);
101
102
12
  unsigned int flags = 0;
103
12
  if (args[2]->IsTrue())
104
    flags |= UV_FS_EVENT_RECURSIVE;
105
106
24
  wrap->encoding_ = ParseEncoding(env->isolate(), args[3], kDefaultEncoding);
107
108
12
  int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
109
12
  if (err == 0) {
110
12
    wrap->initialized_ = true;
111
112
12
    err = uv_fs_event_start(&wrap->handle_, OnEvent, *path, flags);
113
114
12
    if (err == 0) {
115
      // Check for persistent argument
116
11
      if (!args[1]->IsTrue()) {
117
1
        uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
118
      }
119
    } else {
120
1
      FSEventWrap::Close(args);
121
    }
122
  }
123
124
24
  args.GetReturnValue().Set(err);
125
}
126
127
128
6
void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
129
    int events, int status) {
130
6
  FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
131
6
  Environment* env = wrap->env();
132
133
12
  HandleScope handle_scope(env->isolate());
134
18
  Context::Scope context_scope(env->context());
135
136
12
  CHECK_EQ(wrap->persistent().IsEmpty(), false);
137
138
  // We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but
139
  // the Node API only lets us pass a single event to JS land.
140
  //
141
  // The obvious solution is to run the callback twice, once for each event.
142
  // However, since the second event is not allowed to fire if the handle is
143
  // closed after the first event, and since there is no good way to detect
144
  // closed handles, that option is out.
145
  //
146
  // For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
147
  // assumption that a rename implicitly means an attribute change. Not too
148
  // unreasonable, right? Still, we should revisit this before v1.0.
149
6
  Local<String> event_string;
150
6
  if (status) {
151
    event_string = String::Empty(env->isolate());
152
6
  } else if (events & UV_RENAME) {
153
4
    event_string = env->rename_string();
154
2
  } else if (events & UV_CHANGE) {
155
2
    event_string = env->change_string();
156
  } else {
157
    CHECK(0 && "bad fs events flag");
158
  }
159
160
  Local<Value> argv[] = {
161
    Integer::New(env->isolate(), status),
162
    event_string,
163
    Null(env->isolate())
164
30
  };
165
166
6
  if (filename != nullptr) {
167
    Local<Value> fn = StringBytes::Encode(env->isolate(),
168
                                          filename,
169
6
                                          wrap->encoding_);
170
6
    if (fn.IsEmpty()) {
171
      argv[0] = Integer::New(env->isolate(), UV_EINVAL);
172
      argv[2] = StringBytes::Encode(env->isolate(),
173
                                    filename,
174
                                    strlen(filename),
175
                                    BUFFER);
176
    } else {
177
6
      argv[2] = fn;
178
    }
179
  }
180
181
12
  wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
182
6
}
183
184
185
12
void FSEventWrap::Close(const FunctionCallbackInfo<Value>& args) {
186
  FSEventWrap* wrap;
187
12
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
188
189

12
  if (wrap == nullptr || wrap->initialized_ == false)
190
    return;
191
11
  wrap->initialized_ = false;
192
193
11
  HandleWrap::Close(args);
194
}
195
196
}  // namespace node
197
198
1734
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs_event_wrap, node::FSEventWrap::Initialize)