Exemplo n.º 1
0
  void kqueue_monitor::initialize_kqueue()
  {
    if (kq != -1) throw libfsw_exception(_("kqueue already running."));

    kq = kqueue();

    if (kq == -1)
    {
      perror("kqueue()");
      throw libfsw_exception(_("kqueue failed."));
    }
  }
Exemplo n.º 2
0
  fsw_event_flag event::get_event_flag_by_name(const string &name)
  {
#define FSW_MAKE_PAIR_FROM_NAME(p) {#p, p}
    static const map<string, fsw_event_flag> flag_by_names = {
      FSW_MAKE_PAIR_FROM_NAME(NoOp),
      FSW_MAKE_PAIR_FROM_NAME(PlatformSpecific),
      FSW_MAKE_PAIR_FROM_NAME(Created),
      FSW_MAKE_PAIR_FROM_NAME(Updated),
      FSW_MAKE_PAIR_FROM_NAME(Removed),
      FSW_MAKE_PAIR_FROM_NAME(Renamed),
      FSW_MAKE_PAIR_FROM_NAME(OwnerModified),
      FSW_MAKE_PAIR_FROM_NAME(AttributeModified),
      FSW_MAKE_PAIR_FROM_NAME(MovedFrom),
      FSW_MAKE_PAIR_FROM_NAME(MovedTo),
      FSW_MAKE_PAIR_FROM_NAME(IsFile),
      FSW_MAKE_PAIR_FROM_NAME(IsDir),
      FSW_MAKE_PAIR_FROM_NAME(IsSymLink),
      FSW_MAKE_PAIR_FROM_NAME(Link),
      FSW_MAKE_PAIR_FROM_NAME(Overflow)
    };
#undef FSW_MAKE_PAIR_FROM_NAME

    auto flag = flag_by_names.find(name);

    if (flag == flag_by_names.end())
      throw libfsw_exception(_("Unknown event type: ") + name, FSW_ERR_UNKNOWN_VALUE);

    return flag->second;
  }
Exemplo n.º 3
0
  void fsevents_monitor::fsevents_callback(ConstFSEventStreamRef streamRef,
                                           void *clientCallBackInfo,
                                           size_t numEvents,
                                           void *eventPaths,
                                           const FSEventStreamEventFlags eventFlags[],
                                           const FSEventStreamEventId eventIds[])
  {
    fsevents_monitor *fse_monitor =
      static_cast<fsevents_monitor *> (clientCallBackInfo);

    if (!fse_monitor)
    {
      throw libfsw_exception(_("The callback info cannot be cast to fsevents_monitor."));
    }

    vector<event> events;

    time_t curr_time;
    time(&curr_time);

    for (size_t i = 0; i < numEvents; ++i)
    {
      events.push_back({((char **) eventPaths)[i], curr_time, decode_flags(eventFlags[i])});
    }

    if (events.size() > 0)
    {
      fse_monitor->notify_events(events);
    }
  }
Exemplo n.º 4
0
  string event::get_event_flag_name(const fsw_event_flag &flag)
  {
#define FSW_MAKE_PAIR_FROM_NAME(p) {p, #p}
    static const map<fsw_event_flag, string> names_by_flag = {
      FSW_MAKE_PAIR_FROM_NAME(NoOp),
      FSW_MAKE_PAIR_FROM_NAME(PlatformSpecific),
      FSW_MAKE_PAIR_FROM_NAME(Created),
      FSW_MAKE_PAIR_FROM_NAME(Updated),
      FSW_MAKE_PAIR_FROM_NAME(Removed),
      FSW_MAKE_PAIR_FROM_NAME(Renamed),
      FSW_MAKE_PAIR_FROM_NAME(OwnerModified),
      FSW_MAKE_PAIR_FROM_NAME(AttributeModified),
      FSW_MAKE_PAIR_FROM_NAME(MovedFrom),
      FSW_MAKE_PAIR_FROM_NAME(MovedTo),
      FSW_MAKE_PAIR_FROM_NAME(IsFile),
      FSW_MAKE_PAIR_FROM_NAME(IsDir),
      FSW_MAKE_PAIR_FROM_NAME(IsSymLink),
      FSW_MAKE_PAIR_FROM_NAME(Link),
      FSW_MAKE_PAIR_FROM_NAME(Overflow)
    };
#undef FSW_MAKE_PAIR_FROM_NAME

    auto name = names_by_flag.find(flag);

    if (name == names_by_flag.end())
      throw libfsw_exception(_("Unknown event type."), FSW_ERR_UNKNOWN_VALUE);

    return name->second;
  }
Exemplo n.º 5
0
  void monitor::set_latency(double latency)
  {
    if (latency < 0)
    {
      throw libfsw_exception(_("Latency cannot be negative."), FSW_ERR_INVALID_LATENCY);
    }

    this->latency = latency;
  }
Exemplo n.º 6
0
  void monitor::notify_overflow(const std::string& path) const
  {
    if (!allow_overflow) throw libfsw_exception(_("Event queue overflow."));

    time_t curr_time;
    time(&curr_time);

    notify_events({{path, curr_time, {fsw_event_flag::Overflow}}});
  }
Exemplo n.º 7
0
 monitor::monitor(std::vector<std::string> paths,
                  FSW_EVENT_CALLBACK * callback,
                  void * context) :
   paths(paths), callback(callback), context(context)
 {
   if (callback == nullptr)
   {
     throw libfsw_exception(_("Callback cannot be null."), FSW_ERR_CALLBACK_NOT_SET);
   }
 }
Exemplo n.º 8
0
  void fsevents_monitor::run()
  {
    if (stream) return;

    // parsing paths
    vector<CFStringRef> dirs;

    for (string path : paths)
    {
      dirs.push_back(CFStringCreateWithCString(NULL,
                                               path.c_str(),
                                               kCFStringEncodingUTF8));
    }

    if (dirs.size() == 0) return;

    CFArrayRef pathsToWatch =
      CFArrayCreate(NULL,
                    reinterpret_cast<const void **> (&dirs[0]),
                    dirs.size(),
                    &kCFTypeArrayCallBacks);

    FSEventStreamContext *context = new FSEventStreamContext();
    context->version = 0;
    context->info = this;
    context->retain = nullptr;
    context->release = nullptr;
    context->copyDescription = nullptr;

    FSW_ELOG(_("Creating FSEvent stream...\n"));
    unique_lock<mutex> run_loop_lock(run_mutex);
    stream = FSEventStreamCreate(NULL,
                                 &fsevents_monitor::fsevents_callback,
                                 context,
                                 pathsToWatch,
                                 kFSEventStreamEventIdSinceNow,
                                 latency,
                                 kFSEventStreamCreateFlagFileEvents);

    if (!stream) throw libfsw_exception(_("Event stream could not be created."));

    run_loop = CFRunLoopGetCurrent();
    run_loop_lock.unlock();

    FSW_ELOG(_("Scheduling stream with run loop...\n"));
    FSEventStreamScheduleWithRunLoop(stream,
                                     run_loop,
                                     kCFRunLoopDefaultMode);

    FSW_ELOG(_("Starting event stream...\n"));
    FSEventStreamStart(stream);

    FSW_ELOG(_("Starting run loop...\n"));
    CFRunLoopRun();
  }
Exemplo n.º 9
0
  void fsevents_monitor::on_stop()
  {
    lock_guard<mutex> run_loop_lock(run_mutex);
    if (!run_loop) throw libfsw_exception(_("run loop is null"));

    FSW_ELOG(_("Stopping event stream...\n"));
    FSEventStreamStop(stream);
    stream = nullptr;

    FSW_ELOG(_("Stopping run loop...\n"));
    CFRunLoopStop(run_loop);
    run_loop = nullptr;
  }
Exemplo n.º 10
0
  monitor * monitor::create_monitor(fsw_monitor_type type,
                                    std::vector<std::string> paths,
                                    FSW_EVENT_CALLBACK * callback,
                                    void * context)
  {
    switch (type)
    {
    case system_default_monitor_type:
      return monitor::create_default_monitor(paths, callback, context);

    case fsevents_monitor_type:
#if defined(HAVE_FSEVENTS_FILE_EVENTS)
      return new fsevents_monitor(paths, callback, context);
#else
      throw libfsw_exception("Unsupported monitor.", FSW_ERR_UNKNOWN_MONITOR_TYPE);
#endif      

    case kqueue_monitor_type:
#if defined(HAVE_SYS_EVENT_H)
      return new kqueue_monitor(paths, callback, context);
#else
      throw libfsw_exception("Unsupported monitor.", FSW_ERR_UNKNOWN_MONITOR_TYPE);
#endif      

    case inotify_monitor_type:
#if defined(HAVE_SYS_INOTIFY_H)
      return new inotify_monitor(paths, callback, context);
#else
      throw libfsw_exception("Unsupported monitor.", FSW_ERR_UNKNOWN_MONITOR_TYPE);
#endif      

    case poll_monitor_type:
      return new poll_monitor(paths, callback, context);

    default:
      throw libfsw_exception("Unsupported monitor.", FSW_ERR_UNKNOWN_MONITOR_TYPE);
    }
  }
Exemplo n.º 11
0
  inotify_monitor::inotify_monitor(vector<string> paths_to_monitor,
                                   FSW_EVENT_CALLBACK * callback,
                                   void * context) :
    monitor(paths_to_monitor, callback, context),
    impl(new inotify_monitor_impl())
  {
    impl->inotify_monitor_handle = inotify_init();

    if (impl->inotify_monitor_handle == -1)
    {
      perror("inotify_init");
      throw libfsw_exception(_("Cannot initialize inotify."));
    }
  }
Exemplo n.º 12
0
  void monitor::add_filter(const monitor_filter &filter)
  {
    regex_t regex;
    int flags = 0;

    if (!filter.case_sensitive) flags |= REG_ICASE;
    if (filter.extended) flags |= REG_EXTENDED;

    if (::regcomp(&regex, filter.text.c_str(), flags))
    {
      string err = _("An error occurred during the compilation of ") + filter.text;
      throw libfsw_exception(err, FSW_ERR_INVALID_REGEX);
    }

    this->filters.push_back({regex, filter.type});
  }
Exemplo n.º 13
0
  monitor::monitor(std::vector<std::string> paths,
                   FSW_EVENT_CALLBACK *callback,
                   void *context) :
    paths(std::move(paths)), callback(callback), context(context), latency(1)
  {
    if (callback == nullptr)
    {
      throw libfsw_exception(_("Callback cannot be null."),
                             FSW_ERR_CALLBACK_NOT_SET);
    }

#ifdef HAVE_INACTIVITY_CALLBACK
    milliseconds epoch =
      duration_cast<milliseconds>(system_clock::now().time_since_epoch());
    last_notification.store(epoch);
#endif
  }
Exemplo n.º 14
0
  monitor *monitor_factory::create_monitor(fsw_monitor_type type,
                                           std::vector<std::string> paths,
                                           FSW_EVENT_CALLBACK *callback,
                                           void *context)
  {
    switch (type)
    {
    case system_default_monitor_type:
      return create_default_monitor(paths, callback, context);

    default:
      auto c = creators_by_type().find(type);

      if (c == creators_by_type().end())
        throw libfsw_exception("Unsupported monitor.",
                               FSW_ERR_UNKNOWN_MONITOR_TYPE);
      return c->second(paths, callback, context);
    }
  }
Exemplo n.º 15
0
  int kqueue_monitor::wait_for_events(const vector<struct kevent>& changes,
                                      vector<struct kevent>& event_list)
  {
    struct timespec ts = create_timespec_from_latency(latency);

    int event_num = kevent(kq,
                           &changes[0],
                           (int) changes.size(),
                           &event_list[0],
                           (int) event_list.size(),
                           &ts);

    if (event_num == -1)
    {
      perror("kevent");
      throw libfsw_exception(_("kevent returned -1, invalid event number."));
    }

    return event_num;
  }
Exemplo n.º 16
0
  void monitor::add_filter(const monitor_filter& filter)
  {
    std::regex::flag_type regex_flags = std::regex::basic;

    if (filter.extended) regex_flags = std::regex::extended;
    if (!filter.case_sensitive) regex_flags |= std::regex::icase;

    try
    {
      this->filters.push_back({std::regex(filter.text, regex_flags),
                               filter.type});
    }
    catch (std::regex_error& error)
    {
      throw libfsw_exception(
        string_utils::string_from_format(
          _("An error occurred during the compilation of %s"),
          filter.text.c_str()),
        FSW_ERR_INVALID_REGEX);
    }
  }
Exemplo n.º 17
0
  void monitor::inactivity_callback(monitor *mon)
  {
    if (!mon) throw libfsw_exception(_("Callback argument cannot be null."));

    FSW_ELOG(_("Inactivity notification thread: starting\n"));

    for (;;)
    {
      std::unique_lock<std::mutex> run_guard(mon->run_mutex);
      if (mon->should_stop) break;
      run_guard.unlock();

      milliseconds elapsed =
        duration_cast<milliseconds>(system_clock::now().time_since_epoch())
        - mon->last_notification.load();

      // Sleep and loop again if sufficient time has not elapsed yet.
      if (elapsed < mon->get_latency_ms())
      {
        milliseconds to_sleep = mon->get_latency_ms() - elapsed;
        seconds max_sleep_time(2);

        std::this_thread::sleep_for(
          to_sleep > max_sleep_time ? max_sleep_time : to_sleep);
        continue;
      }

      // Build a fake event.
      time_t curr_time;
      time(&curr_time);

      std::vector<event> events;
      events.push_back({"", curr_time, {NoOp}});

      mon->notify_events(events);
    }

    FSW_ELOG(_("Inactivity notification thread: exiting\n"));
  }
Exemplo n.º 18
0
  void inotify_monitor::run()
  {
    char buffer[BUFFER_SIZE];

    while (true)
    {
      process_pending_events();

      scan_root_paths();

      // If no files can be watched, sleep and repeat the loop.
      if (!impl->watched_descriptors.size())
      {
        sleep(latency);
        continue;
      }

      // Use select to timeout on file descriptor read the amount specified by
      // the monitor latency.  This way, the monitor has a chance to update its
      // watches with at least the periodicity expected by the user.
      fd_set set;
      struct timeval timeout;

      FD_ZERO(&set);
      FD_SET(impl->inotify_monitor_handle, &set);
      double sec;
      double frac = modf(this->latency, &sec);
      timeout.tv_sec = sec;
      timeout.tv_usec = 1000 * 1000 * frac;

      int rv = select(impl->inotify_monitor_handle + 1,
                      &set,
                      nullptr,
                      nullptr,
                      &timeout);

      if (rv == -1)
      {
        throw libfsw_exception(_("::select() on inotify descriptor encountered an error."));
      }

      // In case of read timeout just repeat the loop.
      if (rv == 0)
      {
        continue;
      }

      ssize_t record_num = read(impl->inotify_monitor_handle,
                                buffer,
                                BUFFER_SIZE);

      {
        ostringstream log;
        log << _("Number of records: ") << record_num << "\n";
        FSW_ELOG(log.str().c_str());
      }

      if (!record_num)
      {
        throw libfsw_exception(_("read() on inotify descriptor read 0 records."));
      }

      if (record_num == -1)
      {
        perror("read()");
        throw libfsw_exception(_("read() on inotify descriptor returned -1."));
      }

      time(&impl->curr_time);

      for (char *p = buffer; p < buffer + record_num;)
      {
        struct inotify_event * event = reinterpret_cast<struct inotify_event *> (p);

        preprocess_event(event);

        p += (sizeof (struct inotify_event)) + event->len;
      }

      if (impl->events.size())
      {
        notify_events(impl->events);

        impl->events.clear();
      }

      sleep(latency);
    }
  }