11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci#include "async_wrap-inl.h"
231cb0ef41Sopenharmony_ci#include "env-inl.h"
241cb0ef41Sopenharmony_ci#include "handle_wrap.h"
251cb0ef41Sopenharmony_ci#include "node.h"
261cb0ef41Sopenharmony_ci#include "node_external_reference.h"
271cb0ef41Sopenharmony_ci#include "string_bytes.h"
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cinamespace node {
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciusing v8::Context;
321cb0ef41Sopenharmony_ciusing v8::DontDelete;
331cb0ef41Sopenharmony_ciusing v8::DontEnum;
341cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
351cb0ef41Sopenharmony_ciusing v8::FunctionTemplate;
361cb0ef41Sopenharmony_ciusing v8::HandleScope;
371cb0ef41Sopenharmony_ciusing v8::Integer;
381cb0ef41Sopenharmony_ciusing v8::Isolate;
391cb0ef41Sopenharmony_ciusing v8::Local;
401cb0ef41Sopenharmony_ciusing v8::MaybeLocal;
411cb0ef41Sopenharmony_ciusing v8::Object;
421cb0ef41Sopenharmony_ciusing v8::PropertyAttribute;
431cb0ef41Sopenharmony_ciusing v8::ReadOnly;
441cb0ef41Sopenharmony_ciusing v8::Signature;
451cb0ef41Sopenharmony_ciusing v8::String;
461cb0ef41Sopenharmony_ciusing v8::Value;
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cinamespace {
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciclass FSEventWrap: public HandleWrap {
511cb0ef41Sopenharmony_ci public:
521cb0ef41Sopenharmony_ci  static void Initialize(Local<Object> target,
531cb0ef41Sopenharmony_ci                         Local<Value> unused,
541cb0ef41Sopenharmony_ci                         Local<Context> context,
551cb0ef41Sopenharmony_ci                         void* priv);
561cb0ef41Sopenharmony_ci  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
571cb0ef41Sopenharmony_ci  static void New(const FunctionCallbackInfo<Value>& args);
581cb0ef41Sopenharmony_ci  static void Start(const FunctionCallbackInfo<Value>& args);
591cb0ef41Sopenharmony_ci  static void GetInitialized(const FunctionCallbackInfo<Value>& args);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  SET_NO_MEMORY_INFO()
621cb0ef41Sopenharmony_ci  SET_MEMORY_INFO_NAME(FSEventWrap)
631cb0ef41Sopenharmony_ci  SET_SELF_SIZE(FSEventWrap)
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci private:
661cb0ef41Sopenharmony_ci  static const encoding kDefaultEncoding = UTF8;
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  FSEventWrap(Environment* env, Local<Object> object);
691cb0ef41Sopenharmony_ci  ~FSEventWrap() override = default;
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  static void OnEvent(uv_fs_event_t* handle, const char* filename, int events,
721cb0ef41Sopenharmony_ci    int status);
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  uv_fs_event_t handle_;
751cb0ef41Sopenharmony_ci  enum encoding encoding_ = kDefaultEncoding;
761cb0ef41Sopenharmony_ci};
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ciFSEventWrap::FSEventWrap(Environment* env, Local<Object> object)
801cb0ef41Sopenharmony_ci    : HandleWrap(env,
811cb0ef41Sopenharmony_ci                 object,
821cb0ef41Sopenharmony_ci                 reinterpret_cast<uv_handle_t*>(&handle_),
831cb0ef41Sopenharmony_ci                 AsyncWrap::PROVIDER_FSEVENTWRAP) {
841cb0ef41Sopenharmony_ci  MarkAsUninitialized();
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_civoid FSEventWrap::GetInitialized(const FunctionCallbackInfo<Value>& args) {
891cb0ef41Sopenharmony_ci  FSEventWrap* wrap = Unwrap<FSEventWrap>(args.This());
901cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(wrap);
911cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(!wrap->IsHandleClosing());
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_civoid FSEventWrap::Initialize(Local<Object> target,
951cb0ef41Sopenharmony_ci                             Local<Value> unused,
961cb0ef41Sopenharmony_ci                             Local<Context> context,
971cb0ef41Sopenharmony_ci                             void* priv) {
981cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(context);
991cb0ef41Sopenharmony_ci  Isolate* isolate = env->isolate();
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  Local<FunctionTemplate> t = NewFunctionTemplate(isolate, New);
1021cb0ef41Sopenharmony_ci  t->InstanceTemplate()->SetInternalFieldCount(
1031cb0ef41Sopenharmony_ci      FSEventWrap::kInternalFieldCount);
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  t->Inherit(HandleWrap::GetConstructorTemplate(env));
1061cb0ef41Sopenharmony_ci  SetProtoMethod(isolate, t, "start", Start);
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  Local<FunctionTemplate> get_initialized_templ =
1091cb0ef41Sopenharmony_ci      FunctionTemplate::New(env->isolate(),
1101cb0ef41Sopenharmony_ci                            GetInitialized,
1111cb0ef41Sopenharmony_ci                            Local<Value>(),
1121cb0ef41Sopenharmony_ci                            Signature::New(env->isolate(), t));
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  t->PrototypeTemplate()->SetAccessorProperty(
1151cb0ef41Sopenharmony_ci      FIXED_ONE_BYTE_STRING(env->isolate(), "initialized"),
1161cb0ef41Sopenharmony_ci      get_initialized_templ,
1171cb0ef41Sopenharmony_ci      Local<FunctionTemplate>(),
1181cb0ef41Sopenharmony_ci      static_cast<PropertyAttribute>(ReadOnly | DontDelete | DontEnum));
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  SetConstructorFunction(context, target, "FSEvent", t);
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_civoid FSEventWrap::RegisterExternalReferences(
1241cb0ef41Sopenharmony_ci    ExternalReferenceRegistry* registry) {
1251cb0ef41Sopenharmony_ci  registry->Register(New);
1261cb0ef41Sopenharmony_ci  registry->Register(Start);
1271cb0ef41Sopenharmony_ci  registry->Register(GetInitialized);
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_civoid FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
1311cb0ef41Sopenharmony_ci  CHECK(args.IsConstructCall());
1321cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1331cb0ef41Sopenharmony_ci  new FSEventWrap(env, args.This());
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci// wrap.start(filename, persistent, recursive, encoding)
1371cb0ef41Sopenharmony_civoid FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
1381cb0ef41Sopenharmony_ci  Environment* env = Environment::GetCurrent(args);
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  FSEventWrap* wrap = Unwrap<FSEventWrap>(args.This());
1411cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(wrap);
1421cb0ef41Sopenharmony_ci  CHECK(wrap->IsHandleClosing());  // Check that Start() has not been called.
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  const int argc = args.Length();
1451cb0ef41Sopenharmony_ci  CHECK_GE(argc, 4);
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  BufferValue path(env->isolate(), args[0]);
1481cb0ef41Sopenharmony_ci  CHECK_NOT_NULL(*path);
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  unsigned int flags = 0;
1511cb0ef41Sopenharmony_ci  if (args[2]->IsTrue())
1521cb0ef41Sopenharmony_ci    flags |= UV_FS_EVENT_RECURSIVE;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  wrap->encoding_ = ParseEncoding(env->isolate(), args[3], kDefaultEncoding);
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
1571cb0ef41Sopenharmony_ci  if (err != 0) {
1581cb0ef41Sopenharmony_ci    return args.GetReturnValue().Set(err);
1591cb0ef41Sopenharmony_ci  }
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  err = uv_fs_event_start(&wrap->handle_, OnEvent, *path, flags);
1621cb0ef41Sopenharmony_ci  wrap->MarkAsInitialized();
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  if (err != 0) {
1651cb0ef41Sopenharmony_ci    FSEventWrap::Close(args);
1661cb0ef41Sopenharmony_ci    return args.GetReturnValue().Set(err);
1671cb0ef41Sopenharmony_ci  }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  // Check for persistent argument
1701cb0ef41Sopenharmony_ci  if (!args[1]->IsTrue()) {
1711cb0ef41Sopenharmony_ci    uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(err);
1751cb0ef41Sopenharmony_ci}
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_civoid FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
1791cb0ef41Sopenharmony_ci    int events, int status) {
1801cb0ef41Sopenharmony_ci  FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
1811cb0ef41Sopenharmony_ci  Environment* env = wrap->env();
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  HandleScope handle_scope(env->isolate());
1841cb0ef41Sopenharmony_ci  Context::Scope context_scope(env->context());
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  CHECK_EQ(wrap->persistent().IsEmpty(), false);
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  // We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but
1891cb0ef41Sopenharmony_ci  // the Node API only lets us pass a single event to JS land.
1901cb0ef41Sopenharmony_ci  //
1911cb0ef41Sopenharmony_ci  // The obvious solution is to run the callback twice, once for each event.
1921cb0ef41Sopenharmony_ci  // However, since the second event is not allowed to fire if the handle is
1931cb0ef41Sopenharmony_ci  // closed after the first event, and since there is no good way to detect
1941cb0ef41Sopenharmony_ci  // closed handles, that option is out.
1951cb0ef41Sopenharmony_ci  //
1961cb0ef41Sopenharmony_ci  // For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
1971cb0ef41Sopenharmony_ci  // assumption that a rename implicitly means an attribute change. Not too
1981cb0ef41Sopenharmony_ci  // unreasonable, right? Still, we should revisit this before v1.0.
1991cb0ef41Sopenharmony_ci  Local<String> event_string;
2001cb0ef41Sopenharmony_ci  if (status) {
2011cb0ef41Sopenharmony_ci    event_string = String::Empty(env->isolate());
2021cb0ef41Sopenharmony_ci  } else if (events & UV_RENAME) {
2031cb0ef41Sopenharmony_ci    event_string = env->rename_string();
2041cb0ef41Sopenharmony_ci  } else if (events & UV_CHANGE) {
2051cb0ef41Sopenharmony_ci    event_string = env->change_string();
2061cb0ef41Sopenharmony_ci  } else {
2071cb0ef41Sopenharmony_ci    UNREACHABLE("bad fs events flag");
2081cb0ef41Sopenharmony_ci  }
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci  Local<Value> argv[] = {
2111cb0ef41Sopenharmony_ci    Integer::New(env->isolate(), status),
2121cb0ef41Sopenharmony_ci    event_string,
2131cb0ef41Sopenharmony_ci    Null(env->isolate())
2141cb0ef41Sopenharmony_ci  };
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  if (filename != nullptr) {
2171cb0ef41Sopenharmony_ci    Local<Value> error;
2181cb0ef41Sopenharmony_ci    MaybeLocal<Value> fn = StringBytes::Encode(env->isolate(),
2191cb0ef41Sopenharmony_ci                                               filename,
2201cb0ef41Sopenharmony_ci                                               wrap->encoding_,
2211cb0ef41Sopenharmony_ci                                               &error);
2221cb0ef41Sopenharmony_ci    if (fn.IsEmpty()) {
2231cb0ef41Sopenharmony_ci      argv[0] = Integer::New(env->isolate(), UV_EINVAL);
2241cb0ef41Sopenharmony_ci      argv[2] = StringBytes::Encode(env->isolate(),
2251cb0ef41Sopenharmony_ci                                    filename,
2261cb0ef41Sopenharmony_ci                                    strlen(filename),
2271cb0ef41Sopenharmony_ci                                    BUFFER,
2281cb0ef41Sopenharmony_ci                                    &error).ToLocalChecked();
2291cb0ef41Sopenharmony_ci    } else {
2301cb0ef41Sopenharmony_ci      argv[2] = fn.ToLocalChecked();
2311cb0ef41Sopenharmony_ci    }
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci  wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
2351cb0ef41Sopenharmony_ci}
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci}  // anonymous namespace
2381cb0ef41Sopenharmony_ci}  // namespace node
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(fs_event_wrap,
2411cb0ef41Sopenharmony_ci                                    node::FSEventWrap::Initialize)
2421cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(fs_event_wrap,
2431cb0ef41Sopenharmony_ci                                node::FSEventWrap::RegisterExternalReferences)
244