GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/fs_event_wrap.cc Lines: 62 70 88.6 %
Date: 2016-07-26 Branches: 23 38 60.5 %

Line 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
11
                 AsyncWrap::PROVIDER_FSEVENTWRAP) {}
56
57
58
30
FSEventWrap::~FSEventWrap() {
59
10
  CHECK_EQ(initialized_, false);
60
20
}
61
62
63
1561
void FSEventWrap::Initialize(Local<Object> target,
64
                             Local<Value> unused,
65
                             Local<Context> context) {
66
1561
  Environment* env = Environment::GetCurrent(context);
67
68
3122
  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
69
3122
  t->InstanceTemplate()->SetInternalFieldCount(1);
70
1561
  t->SetClassName(env->fsevent_string());
71
72
1561
  env->SetProtoMethod(t, "start", Start);
73
1561
  env->SetProtoMethod(t, "close", Close);
74
75
7805
  target->Set(env->fsevent_string(), t->GetFunction());
76
1561
}
77
78
79
11
void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
80
11
  CHECK(args.IsConstructCall());
81
11
  Environment* env = Environment::GetCurrent(args);
82
22
  new FSEventWrap(env, args.This());
83
11
}
84
85
86
11
void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
87
11
  Environment* env = Environment::GetCurrent(args);
88
89
  FSEventWrap* wrap;
90
11
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
91
11
  CHECK_EQ(wrap->initialized_, false);
92
93
  static const char kErrMsg[] = "filename must be a string or Buffer";
94
11
  if (args.Length() < 1)
95
    return env->ThrowTypeError(kErrMsg);
96
97
22
  BufferValue path(env->isolate(), args[0]);
98
11
  if (*path == nullptr)
99
    return env->ThrowTypeError(kErrMsg);
100
101
11
  unsigned int flags = 0;
102
11
  if (args[2]->IsTrue())
103
    flags |= UV_FS_EVENT_RECURSIVE;
104
105
22
  wrap->encoding_ = ParseEncoding(env->isolate(), args[3], kDefaultEncoding);
106
107
11
  int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
108
11
  if (err == 0) {
109
11
    wrap->initialized_ = true;
110
111
11
    err = uv_fs_event_start(&wrap->handle_, OnEvent, *path, flags);
112
113
11
    if (err == 0) {
114
      // Check for persistent argument
115
10
      if (!args[1]->IsTrue()) {
116
1
        uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
117
      }
118
    } else {
119
1
      FSEventWrap::Close(args);
120
    }
121
  }
122
123
22
  args.GetReturnValue().Set(err);
124
}
125
126
127
6
void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
128
    int events, int status) {
129
6
  FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
130
6
  Environment* env = wrap->env();
131
132
12
  HandleScope handle_scope(env->isolate());
133
18
  Context::Scope context_scope(env->context());
134
135
12
  CHECK_EQ(wrap->persistent().IsEmpty(), false);
136
137
  // We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but
138
  // the Node API only lets us pass a single event to JS land.
139
  //
140
  // The obvious solution is to run the callback twice, once for each event.
141
  // However, since the second event is not allowed to fire if the handle is
142
  // closed after the first event, and since there is no good way to detect
143
  // closed handles, that option is out.
144
  //
145
  // For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
146
  // assumption that a rename implicitly means an attribute change. Not too
147
  // unreasonable, right? Still, we should revisit this before v1.0.
148
6
  Local<String> event_string;
149
6
  if (status) {
150
    event_string = String::Empty(env->isolate());
151
6
  } else if (events & UV_RENAME) {
152
4
    event_string = env->rename_string();
153
2
  } else if (events & UV_CHANGE) {
154
2
    event_string = env->change_string();
155
  } else {
156
    CHECK(0 && "bad fs events flag");
157
    ABORT();
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
11
void FSEventWrap::Close(const FunctionCallbackInfo<Value>& args) {
186
  FSEventWrap* wrap;
187
11
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
188
189
11
  if (wrap == nullptr || wrap->initialized_ == false)
190
    return;
191
10
  wrap->initialized_ = false;
192
193
10
  HandleWrap::Close(args);
194
}
195
196
}  // namespace node
197
198
1566
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs_event_wrap, node::FSEventWrap::Initialize)