Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
fs_event_wrap.cc
Go to the documentation of this file.
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 "async-wrap.h"
23 #include "async-wrap-inl.h"
24 #include "env.h"
25 #include "env-inl.h"
26 #include "util.h"
27 #include "util-inl.h"
28 #include "node.h"
29 #include "handle_wrap.h"
30 #include "string_bytes.h"
31 
32 #include <stdlib.h>
33 
34 namespace node {
35 
36 using v8::Context;
37 using v8::FunctionCallbackInfo;
38 using v8::FunctionTemplate;
39 using v8::HandleScope;
40 using v8::Integer;
41 using v8::Local;
42 using v8::MaybeLocal;
43 using v8::Object;
44 using v8::String;
45 using v8::Value;
46 
47 namespace {
48 
49 class FSEventWrap: public HandleWrap {
50  public:
51  static void Initialize(Local<Object> target,
52  Local<Value> unused,
53  Local<Context> context);
54  static void New(const FunctionCallbackInfo<Value>& args);
55  static void Start(const FunctionCallbackInfo<Value>& args);
56  static void Close(const FunctionCallbackInfo<Value>& args);
57 
58  size_t self_size() const override { return sizeof(*this); }
59 
60  private:
61  static const encoding kDefaultEncoding = UTF8;
62 
63  FSEventWrap(Environment* env, Local<Object> object);
64  ~FSEventWrap() override;
65 
66  static void OnEvent(uv_fs_event_t* handle, const char* filename, int events,
67  int status);
68 
69  uv_fs_event_t handle_;
70  bool initialized_ = false;
71  enum encoding encoding_ = kDefaultEncoding;
72 };
73 
74 
75 FSEventWrap::FSEventWrap(Environment* env, Local<Object> object)
76  : HandleWrap(env,
77  object,
78  reinterpret_cast<uv_handle_t*>(&handle_),
79  AsyncWrap::PROVIDER_FSEVENTWRAP) {}
80 
81 
82 FSEventWrap::~FSEventWrap() {
83  CHECK_EQ(initialized_, false);
84 }
85 
86 
87 void FSEventWrap::Initialize(Local<Object> target,
88  Local<Value> unused,
89  Local<Context> context) {
90  Environment* env = Environment::GetCurrent(context);
91 
92  auto fsevent_string = FIXED_ONE_BYTE_STRING(env->isolate(), "FSEvent");
93  Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
94  t->InstanceTemplate()->SetInternalFieldCount(1);
95  t->SetClassName(fsevent_string);
96 
97  AsyncWrap::AddWrapMethods(env, t);
98  env->SetProtoMethod(t, "start", Start);
99  env->SetProtoMethod(t, "close", Close);
100 
101  target->Set(fsevent_string, t->GetFunction());
102 }
103 
104 
105 void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
106  CHECK(args.IsConstructCall());
107  Environment* env = Environment::GetCurrent(args);
108  new FSEventWrap(env, args.This());
109 }
110 
111 
112 void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
113  Environment* env = Environment::GetCurrent(args);
114 
115  FSEventWrap* wrap;
116  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
117  CHECK_EQ(wrap->initialized_, false);
118 
119  static const char kErrMsg[] = "filename must be a string or Buffer";
120  if (args.Length() < 1)
121  return env->ThrowTypeError(kErrMsg);
122 
123  BufferValue path(env->isolate(), args[0]);
124  if (*path == nullptr)
125  return env->ThrowTypeError(kErrMsg);
126 
127  unsigned int flags = 0;
128  if (args[2]->IsTrue())
129  flags |= UV_FS_EVENT_RECURSIVE;
130 
131  wrap->encoding_ = ParseEncoding(env->isolate(), args[3], kDefaultEncoding);
132 
133  int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
134  if (err == 0) {
135  wrap->initialized_ = true;
136 
137  err = uv_fs_event_start(&wrap->handle_, OnEvent, *path, flags);
138 
139  if (err == 0) {
140  // Check for persistent argument
141  if (!args[1]->IsTrue()) {
142  uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
143  }
144  } else {
145  FSEventWrap::Close(args);
146  }
147  }
148 
149  args.GetReturnValue().Set(err);
150 }
151 
152 
153 void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
154  int events, int status) {
155  FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
156  Environment* env = wrap->env();
157 
158  HandleScope handle_scope(env->isolate());
159  Context::Scope context_scope(env->context());
160 
161  CHECK_EQ(wrap->persistent().IsEmpty(), false);
162 
163  // We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but
164  // the Node API only lets us pass a single event to JS land.
165  //
166  // The obvious solution is to run the callback twice, once for each event.
167  // However, since the second event is not allowed to fire if the handle is
168  // closed after the first event, and since there is no good way to detect
169  // closed handles, that option is out.
170  //
171  // For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
172  // assumption that a rename implicitly means an attribute change. Not too
173  // unreasonable, right? Still, we should revisit this before v1.0.
174  Local<String> event_string;
175  if (status) {
176  event_string = String::Empty(env->isolate());
177  } else if (events & UV_RENAME) {
178  event_string = env->rename_string();
179  } else if (events & UV_CHANGE) {
180  event_string = env->change_string();
181  } else {
182  CHECK(0 && "bad fs events flag");
183  }
184 
185  Local<Value> argv[] = {
186  Integer::New(env->isolate(), status),
187  event_string,
188  Null(env->isolate())
189  };
190 
191  if (filename != nullptr) {
192  Local<Value> error;
193  MaybeLocal<Value> fn = StringBytes::Encode(env->isolate(),
194  filename,
195  wrap->encoding_,
196  &error);
197  if (fn.IsEmpty()) {
198  argv[0] = Integer::New(env->isolate(), UV_EINVAL);
199  argv[2] = StringBytes::Encode(env->isolate(),
200  filename,
201  strlen(filename),
202  BUFFER,
203  &error).ToLocalChecked();
204  } else {
205  argv[2] = fn.ToLocalChecked();
206  }
207  }
208 
209  wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
210 }
211 
212 
213 void FSEventWrap::Close(const FunctionCallbackInfo<Value>& args) {
214  FSEventWrap* wrap;
215  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
216 
217  if (wrap == nullptr || wrap->initialized_ == false)
218  return;
219  wrap->initialized_ = false;
220 
221  HandleWrap::Close(args);
222 }
223 
224 } // anonymous namespace
225 } // namespace node
226 
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
QueryWrap * wrap
Definition: cares_wrap.cc:478
int status
Definition: cares_wrap.cc:479
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
Definition: node_http2.cc:1172
encoding
Definition: node.h:322
dtrace t
Definition: v8ustack.d:582
enum encoding ParseEncoding(const char *encoding, enum encoding default_encoding)
Definition: node.cc:1485
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
enum encoding encoding_
Definition: node_file.cc:96
int Start(Isolate *isolate, IsolateData *isolate_data, int argc, const char *const *argv, int exec_argc, const char *const *exec_argv)
Definition: node.cc:4536
NODE_DEPRECATED("Use ParseEncoding(isolate, ...)", inline enum encoding ParseEncoding(v8::Local< v8::Value > encoding_v, enum encoding default_encoding=LATIN1) { return ParseEncoding(v8::Isolate::GetCurrent(), encoding_v, default_encoding);}) NODE_EXTERN void FatalException(v8 NODE_DEPRECATED("Use FatalException(isolate, ...)", inline void FatalException(const v8::TryCatch &try_catch) { return FatalException(v8::Isolate::GetCurrent(), try_catch);}) NODE_EXTERN v8 NODE_EXTERN v8::Local< v8::Value > Encode(v8::Isolate *isolate, const uint16_t *buf, size_t len)
Definition: node.h:350