Пример #1
0
//关闭监控句柄等,解除绑定reactor等
int ZCE_Event_INotify::close()
{

#if defined (ZCE_OS_LINUX)

    //由于是HASH MAP速度有点慢
    HDL_TO_EIN_MAP::iterator iter_temp =  watch_event_map_.begin();
    for (; iter_temp != watch_event_map_.end();)
    {
        rm_watch(iter_temp->second.watch_handle_);
        //让迭代器继续从最开始干起
        iter_temp = watch_event_map_.begin();
    }


    //关闭监控句柄
    if (inotify_handle_ != ZCE_INVALID_HANDLE)
    {
        //从反应器移除
        reactor()->remove_handler(this, false);

        ::close(inotify_handle_);
        inotify_handle_ = ZCE_INVALID_HANDLE;
    }

#elif defined (ZCE_OS_WINDOWS)

    rm_watch(watch_handle_);

#endif

    return 0;
}
Пример #2
0
static void rm_watch(int wd, bool update_parent) {
  watch_node* node = table_get(watches, wd);
  if (node == NULL) {
    return;
  }

  userlog(LOG_DEBUG, "unwatching %s: %d (%p)", node->path, node->wd, node);

  if (inotify_rm_watch(inotify_fd, node->wd) < 0) {
    userlog(LOG_DEBUG, "inotify_rm_watch(%d:%s): %s", node->wd, node->path, strerror(errno));
  }

  for (int i=0; i<array_size(node->kids); i++) {
    watch_node* kid = array_get(node->kids, i);
    if (kid != NULL) {
      rm_watch(kid->wd, false);
    }
  }

  if (update_parent && node->parent != NULL) {
    for (int i=0; i<array_size(node->parent->kids); i++) {
      if (array_get(node->parent->kids, i) == node) {
        array_put(node->parent->kids, i, NULL);
        break;
      }
    }
  }

  array_delete(node->kids);
  free(node);
  table_put(watches, wd, NULL);
}
Пример #3
0
static int walk_tree(int path_len, watch_node* parent, bool recursive, array* mounts) {
  for (int j=0; j<array_size(mounts); j++) {
    char* mount = array_get(mounts, j);
    if (strncmp(path_buf, mount, strlen(mount)) == 0) {
      userlog(LOG_DEBUG, "watch path '%s' crossed mount point '%s' - skipping", path_buf, mount);
      return ERR_IGNORE;
    }
  }

  DIR* dir = NULL;
  if (recursive) {
    if ((dir = opendir(path_buf)) == NULL) {
      if (errno == EACCES || errno == ENOENT || errno == ENOTDIR) {
        userlog(LOG_DEBUG, "opendir(%s): %d", path_buf, errno);
        return ERR_IGNORE;
      }
      else {
        userlog(LOG_ERR, "opendir(%s): %s", path_buf, strerror(errno));
        return ERR_CONTINUE;
      }
    }
  }

  int id = add_watch(path_len, parent);

  if (dir == NULL) {
    return id;
  }
  else if (id < 0) {
    closedir(dir);
    return id;
  }

  path_buf[path_len] = '/';

  struct dirent* entry;
  while ((entry = readdir(dir)) != NULL) {
    if (entry->d_type != DT_DIR ||
        strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
      continue;
    }

    int name_len = strlen(entry->d_name);
    memcpy(path_buf + path_len + 1, entry->d_name, name_len + 1);

    int subdir_id = walk_tree(path_len + 1 + name_len, table_get(watches, id), recursive, mounts);
    if (subdir_id < 0 && subdir_id != ERR_IGNORE) {
      rm_watch(id, true);
      id = subdir_id;
      break;
    }
  }

  closedir(dir);
  return id;
}
Пример #4
0
static int walk_tree(const char* path, watch_node* parent, array* ignores) {
  if (is_ignored(path, ignores)) {
    return ERR_IGNORE;
  }

  DIR* dir = opendir(path);
  if (dir == NULL) {
    if (errno == EACCES) {
      return ERR_IGNORE;
    }
    else if (errno == ENOTDIR) {  // flat root
      return add_watch(path, parent);
    }
    userlog(LOG_ERR, "opendir(%s): %s", path, strerror(errno));
    return ERR_CONTINUE;
  }

  int id = add_watch(path, parent);
  if (id < 0) {
    closedir(dir);
    return id;
  }

  struct dirent* entry;
  char subdir[PATH_MAX];
  strcpy(subdir, path);
  if (subdir[strlen(subdir) - 1] != '/') {
    strcat(subdir, "/");
  }
  char* p = subdir + strlen(subdir);

  while ((entry = readdir(dir)) != NULL) {
    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
      continue;
    }

    strcpy(p, entry->d_name);
    if (!is_directory(entry, subdir)) {
      continue;
    }

    int subdir_id = walk_tree(subdir, table_get(watches, id), ignores);
    if (subdir_id < 0 && subdir_id != ERR_IGNORE) {
      rm_watch(id, true);
      id = subdir_id;
      break;
    }
  }

  closedir(dir);
  return id;
}
Пример #5
0
static bool process_inotify_event(struct inotify_event* event) {
  watch_node* node = table_get(watches, event->wd);
  if (node == NULL) {
    return true;
  }

  bool is_dir = (event->mask & IN_ISDIR) == IN_ISDIR;
  userlog(LOG_DEBUG, "inotify: wd=%d mask=%d dir=%d name=%s", event->wd, event->mask & (~IN_ISDIR), is_dir, node->path);

  memcpy(path_buf, node->path, node->path_len + 1);
  int path_len = node->path_len;
  if (event->len > 0) {
    path_buf[node->path_len] = '/';
    int name_len = strlen(event->name);
    memcpy(path_buf + path_len + 1, event->name, name_len + 1);
    path_len += name_len + 1;
  }

  if (is_dir && event->mask & (IN_CREATE | IN_MOVED_TO)) {
    int result = walk_tree(path_len, node, true, NULL);
    if (result < 0 && result != ERR_IGNORE && result != ERR_CONTINUE) {
      return false;
    }
  }

  if (is_dir && event->mask & (IN_DELETE | IN_MOVED_FROM)) {
    for (int i=0; i<array_size(node->kids); i++) {
      watch_node* kid = array_get(node->kids, i);
      if (kid != NULL && strncmp(path_buf, kid->path, kid->path_len) == 0) {
        rm_watch(kid->wd, false);
        array_put(node->kids, i, NULL);
        break;
      }
    }
  }

  if (callback != NULL) {
    (*callback)(path_buf, event->mask);
  }

  return true;
}
Пример #6
0
static bool process_inotify_event(struct inotify_event* event) {
  watch_node* node = table_get(watches, event->wd);
  if (node == NULL) {
    return true;
  }

  userlog(LOG_DEBUG, "inotify: wd=%d mask=%d dir=%d name=%s",
      event->wd, event->mask & (~IN_ISDIR), (event->mask & IN_ISDIR) != 0, node->name);

  char path[PATH_MAX];
  strcpy(path, node->name);
  if (event->len > 0) {
    if (path[strlen(path) - 1] != '/') {
      strcat(path, "/");
    }
    strcat(path, event->name);
  }

  if ((event->mask & IN_CREATE || event->mask & IN_MOVED_TO) && event->mask & IN_ISDIR) {
    int result = walk_tree(path, node, NULL);
    if (result < 0 && result != ERR_IGNORE) {
      return false;
    }
  }

  if ((event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) && event->mask & IN_ISDIR) {
    for (int i=0; i<array_size(node->kids); i++) {
      watch_node* kid = array_get(node->kids, i);
      if (kid != NULL && strcmp(kid->name, path) == 0) {
        rm_watch(kid->wd, false);
        array_put(node->kids, i, NULL);
        break;
      }
    }
  }

  if (callback != NULL) {
    (*callback)(path, event->mask);
  }
  return true;
}
Пример #7
0
//读取事件触发调用函数
int ZCE_Event_INotify::handle_input ()
{

#if defined (ZCE_OS_LINUX)

    ZCE_LOG(RS_DEBUG, "ZCE_Event_INotify::handle_input");

    int detect_ret = 0;
    size_t watch_event_num = 0;

    //读取
    ssize_t read_ret = ZCE_LIB::read(inotify_handle_, read_buffer_, READ_BUFFER_LEN);
    if (read_ret <= 0)
    {
        return -1;
    }

    uint32_t read_len = static_cast<uint32_t>(read_ret);
    uint32_t next_entry_offset = 0;

    //可能一次读取出来多个inotify_event数据,所以要循环处理
    do
    {
        detect_ret = 0;

        ::inotify_event *ne_ptr = (::inotify_event *) (read_buffer_ + next_entry_offset);

        //检查读取的数据是否还有一个,
        read_len -= (sizeof(::inotify_event) + ne_ptr->len);
        next_entry_offset += sizeof(::inotify_event) + ne_ptr->len;

        HDL_TO_EIN_MAP::iterator active_iter = watch_event_map_.find(ne_ptr->wd);
        if (active_iter == watch_event_map_.end())
        {
            //某个FD在MAP中间无法找到,最大的可能是
            ZCE_LOG(RS_DEBUG,
                    "You code error or a handle not in map (delete in this do while), please check you code. handle[%u]",
                    ne_ptr->wd);
            continue;
        }
        EVENT_INOTIFY_NODE *node_ptr = &(active_iter->second);
        const char *active_path = ne_ptr->name;
        //根据返回的mask决定如何处理

        //注意下面的代码分支用的if else if ,而不是if if,我的初步看法是这些事件不会一起触发,但也许不对。
        //下面5个是和Windows 共有的,
        uint32_t event_mask = ne_ptr->mask;
        if (event_mask & IN_CREATE )
        {
            detect_ret = inotify_create(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_DELETE  )
        {
            detect_ret = inotify_delete(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if ( event_mask & IN_MODIFY )
        {
            detect_ret = inotify_modify(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if ( event_mask & IN_MOVED_FROM)
        {
            detect_ret = inotify_moved_from(node_ptr->watch_handle_,
                                            event_mask,
                                            node_ptr->watch_path_,
                                            active_path);
        }
        else if ( event_mask & IN_MOVED_TO)
        {
            detect_ret = inotify_moved_to(node_ptr->watch_handle_,
                                          event_mask,
                                          node_ptr->watch_path_,
                                          active_path);
        }
        //下面这些是LINUX自己特有的
        else if ( event_mask & IN_ACCESS)
        {
            detect_ret = inotify_access(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_OPEN)
        {
            detect_ret = inotify_open(node_ptr->watch_handle_,
                                      event_mask,
                                      node_ptr->watch_path_,
                                      active_path);
        }
        else if (event_mask & IN_CLOSE_WRITE || event_mask | IN_CLOSE_NOWRITE)
        {
            detect_ret = inotify_close(node_ptr->watch_handle_,
                                       event_mask,
                                       node_ptr->watch_path_,
                                       active_path);
        }
        else if (event_mask & IN_ATTRIB)
        {
            detect_ret = inotify_attrib(node_ptr->watch_handle_,
                                        event_mask,
                                        node_ptr->watch_path_,
                                        active_path);
        }
        else if (event_mask & IN_MOVE_SELF)
        {
            detect_ret = inotify_move_slef(node_ptr->watch_handle_,
                                           event_mask,
                                           node_ptr->watch_path_,
                                           active_path);
        }
        else if (event_mask & IN_DELETE_SELF)
        {
            detect_ret = inotify_delete_slef(node_ptr->watch_handle_,
                                             event_mask,
                                             node_ptr->watch_path_,
                                             active_path);
        }

        //返回-1,关闭之,
        if (detect_ret == -1)
        {
            rm_watch(node_ptr->watch_handle_);
        }

        //累计发现事件计数
        ++(watch_event_num);

    }
    while (read_len > 0);

    return 0;

#elif defined (ZCE_OS_WINDOWS)

    int detect_ret = 0;
    DWORD num_read = 0;
    BOOL bret = ::GetOverlappedResult(watch_handle_,
                                      &over_lapped_,
                                      &num_read,
                                      FALSE);

    //读取结果失败
    if (FALSE == bret)
    {
        ZCE_LOG(RS_ERROR, "[%s] ::GetOverlappedResult fail,error [%u].",
                __ZCE_FUNC__,
                ZCE_LIB::last_error());
        return -1;
    }


    //记录当前处理的句柄,


    FILE_NOTIFY_INFORMATION *read_ptr = NULL;
    DWORD next_entry_offset = 0;
    do
    {
        detect_ret = 0;
        read_ptr = (FILE_NOTIFY_INFORMATION *)(read_buffer_ + next_entry_offset);

        //文件名称进行转换,从宽字节转换为多字节,
        //天杀的Windows在这些地方又埋了陷阱FILE_NOTIFY_INFORMATION里面的长度FileNameLength是字节长度
        //而WideCharToMultiByte函数需要的长度是字长度,你能TMD统一一点吗?
        int length_of_ws = ::WideCharToMultiByte(CP_ACP,
                                                 0,
                                                 read_ptr->FileName,
                                                 read_ptr->FileNameLength / sizeof(wchar_t),
                                                 NULL,
                                                 0,
                                                 NULL,
                                                 NULL);
        //Windows 的目录名称最大长度可以到3K,我没有兴趣去搞一套这个玩
        if (length_of_ws >= MAX_PATH)
        {
            ZCE_LOG(RS_ALERT, "My God ,your path length [%u] more than MAX_PATH [%u],I don't process this.",
                    length_of_ws,
                    MAX_PATH);
            continue;
        }
        char active_path[MAX_PATH + 1];
        ::WideCharToMultiByte(CP_ACP,
                              0,
                              read_ptr->FileName,
                              read_ptr->FileNameLength / sizeof(wchar_t),
                              active_path,
                              length_of_ws,
                              NULL,
                              NULL);
        active_path[length_of_ws] = '\0';

        //根据Action和mask确定调用函数
        switch (read_ptr->Action)
        {
            case FILE_ACTION_ADDED:
                if (watch_mask_ | IN_CREATE)
                {
                    detect_ret = inotify_create(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
            case FILE_ACTION_REMOVED:
                if (watch_mask_ | IN_DELETE)
                {
                    detect_ret = inotify_delete(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
                //注意Windows 下的这个类型,包括了属性更改
            case FILE_ACTION_MODIFIED:
                if (watch_mask_ | IN_MODIFY)
                {
                    detect_ret = inotify_modify(watch_handle_,
                                                watch_mask_,
                                                watch_path_,
                                                active_path);
                }
                break;
            case FILE_ACTION_RENAMED_OLD_NAME:
                if (watch_mask_ | IN_MOVED_FROM)
                {
                    detect_ret = inotify_moved_from(watch_handle_,
                                                    watch_mask_,
                                                    watch_path_,
                                                    active_path);
                }
                break;
            case FILE_ACTION_RENAMED_NEW_NAME:
                if (watch_mask_ | IN_MOVED_TO)
                {
                    detect_ret = inotify_moved_to(watch_handle_,
                                                  watch_mask_,
                                                  watch_path_,
                                                  active_path);
                }
                break;
        }

        //累计偏移长度
        next_entry_offset += read_ptr->NextEntryOffset;

        //返回-1,关闭之
        if (detect_ret == -1)
        {
            handle_close();
        }

        //为什么要这样做,因为上面的处理过程,可能有人已经调用了rm_watch,或者handle_close,
        if (watch_handle_ == ZCE_INVALID_HANDLE)
        {
            return 0;
        }

    }
    while (read_ptr->NextEntryOffset != 0);

    DWORD bytes_returned = 0;

    //继续进行监控处理
    bret = ::ReadDirectoryChangesW(
               watch_handle_,            // handle to directory
               read_buffer_, // read results buffer
               READ_BUFFER_LEN,                               // length of buffer
               watch_sub_dir_,                                 // monitoring option
               FILE_NOTIFY_CHANGE_SECURITY |
               FILE_NOTIFY_CHANGE_CREATION |
               FILE_NOTIFY_CHANGE_LAST_ACCESS |
               FILE_NOTIFY_CHANGE_LAST_WRITE |
               FILE_NOTIFY_CHANGE_SIZE |
               FILE_NOTIFY_CHANGE_ATTRIBUTES |
               FILE_NOTIFY_CHANGE_DIR_NAME |
               FILE_NOTIFY_CHANGE_FILE_NAME,          // filter conditions
               &bytes_returned,                       // bytes returned
               & (over_lapped_), // overlapped buffer
               NULL                                   // completion routine
           );
    if (FALSE == bret)
    {
        ZCE_LOG(RS_ERROR, "[zcelib][%s] ::ReadDirectoryChangesW fail,error [%u].",
                __ZCE_FUNC__,
                ZCE_LIB::last_error());
    }

    return 0;

#endif
}
Пример #8
0
pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const char *device_name) {
    pa_reserve_monitor_wrapper *w;
    int k;
    char *t;
#ifdef HAVE_DBUS
    DBusError error;

    dbus_error_init(&error);
#endif

    pa_assert(c);
    pa_assert(device_name);

    t = pa_sprintf_malloc("reserve-monitor-wrapper@%s", device_name);

    if ((w = pa_shared_get(c, t))) {
        pa_xfree(t);

        pa_assert(PA_REFCNT_VALUE(w) >= 1);
        PA_REFCNT_INC(w);

        return w;
    }

    w = pa_xnew0(pa_reserve_monitor_wrapper, 1);
    PA_REFCNT_INIT(w);
    w->core = c;
    pa_hook_init(&w->hook, w);
    w->shared_name = t;

    pa_assert_se(pa_shared_set(c, w->shared_name, w) >= 0);

#ifdef HAVE_DBUS
    if (!(w->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);

        /* We don't treat this as error here because we want allow PA
         * to run even when no session bus is available. */
        return w;
    }

    if ((k = rm_watch(
                 &w->monitor,
                 pa_dbus_connection_get(w->connection),
                 device_name,
                 change_cb,
                 NULL)) < 0) {

        pa_log_debug("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k));
        goto fail;
    }

    pa_log_debug("Successfully create reservation lock monitor for device '%s'", device_name);

    rm_set_userdata(w->monitor, w);
    return w;

fail:
    dbus_error_free(&error);

    reserve_monitor_wrapper_free(w);

    return NULL;
#else
    return w;
#endif
}
Пример #9
0
void unwatch(int id) {
  rm_watch(id, true);
}