Example #1
0
static DIR *kqueue_root_start_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  struct kqueue_root_state *state = root->watch;
  DIR *osdir;
  struct stat st, osdirst;
  struct kevent k;
  int newwd;
  unused_parameter(watcher);

  osdir = opendir_nofollow(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, NULL);
    return NULL;
  }

  newwd = open(path, O_NOFOLLOW|O_EVTONLY|O_CLOEXEC);

  if (newwd == -1) {
    // directory got deleted between opendir and open
    handle_open_errno(root, dir, now, "open", errno, NULL);
    closedir(osdir);
    return NULL;
  }
  if (fstat(newwd, &st) == -1 || fstat(dirfd(osdir), &osdirst) == -1) {
    // whaaa?
    w_log(W_LOG_ERR, "fstat on opened dir %s failed: %s\n", path,
        strerror(errno));
    w_root_schedule_recrawl(root, "fstat failed");
    close(newwd);
    closedir(osdir);
    return NULL;
  }

  if (st.st_dev != osdirst.st_dev || st.st_ino != osdirst.st_ino) {
    // directory got replaced between opendir and open -- at this point its
    // parent's being watched, so we let filesystem events take care of it
    handle_open_errno(root, dir, now, "open", ENOTDIR, NULL);
    close(newwd);
    closedir(osdir);
    return NULL;
  }

  dir->wd = newwd;
  memset(&k, 0, sizeof(k));
  EV_SET(&k, dir->wd, EVFILT_VNODE, EV_ADD|EV_CLEAR,
      NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_RENAME,
      0, SET_DIR_BIT(dir));

  if (kevent(state->kq_fd, &k, 1, NULL, 0, 0)) {
    w_log(W_LOG_DBG, "kevent EV_ADD dir %s failed: %s",
        path, strerror(errno));
    close(dir->wd);
    dir->wd = -1;
  }

  return osdir;
}
Example #2
0
static DIR *portfs_root_start_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  struct portfs_root_state *state = root->watch;
  DIR *osdir;
  struct stat st;
  unused_parameter(watcher);

  osdir = opendir_nofollow(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, NULL);
    return NULL;
  }

  if (fstat(dirfd(osdir), &st) == -1) {
    // whaaa?
    w_log(W_LOG_ERR, "fstat on opened dir %s failed: %s\n", path,
        strerror(errno));
    w_root_schedule_recrawl(root, "fstat failed");
    closedir(osdir);
    return NULL;
  }

  dir->port_file.fo_mtime = st.st_atim;
  dir->port_file.fo_mtime = st.st_mtim;
  dir->port_file.fo_ctime = st.st_ctim;
  dir->port_file.fo_name = (char*)dir->path->buf;

  errno = 0;
  if (port_associate(state->port_fd, PORT_SOURCE_FILE,
        (uintptr_t)&dir->port_file, WATCHMAN_PORT_EVENTS,
        SET_DIR_BIT(dir))) {
    w_log(W_LOG_ERR, "port_associate %s %s\n",
        dir->port_file.fo_name, strerror(errno));
  }

  return osdir;
}
Example #3
0
static void kqueue_root_stop_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir) {
  struct kqueue_root_state *state = root->watch;
  struct kevent k;
  unused_parameter(watcher);

  if (dir->wd == -1) {
    return;
  }

  memset(&k, 0, sizeof(k));
  EV_SET(&k, dir->wd, EVFILT_VNODE, EV_DELETE,
      0, 0, SET_DIR_BIT(dir));

  if (kevent(state->kq_fd, &k, 1, NULL, 0, 0)) {
    w_log(W_LOG_ERR, "rm_watch: %d %.*s %s\n",
        dir->wd, dir->path->len, dir->path->buf,
        strerror(errno));
    w_root_schedule_recrawl(root, "rm_watch failed");
  }

  close(dir->wd);
  dir->wd = -1;
}
Example #4
0
static DIR *kqueue_root_start_watch_dir(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_dir *dir, struct timeval now,
    const char *path) {
  struct kqueue_root_state *state = root->watch;
  DIR *osdir;
  struct stat st, osdirst;
  struct kevent k;
  int newwd;
  unused_parameter(watcher);

  osdir = opendir_nofollow(path);
  if (!osdir) {
    handle_open_errno(root, dir, now, "opendir", errno, NULL);
    return NULL;
  }

  newwd = open(path, O_NOFOLLOW|O_EVTONLY|O_CLOEXEC);

  if (newwd == -1) {
    // directory got deleted between opendir and open
    handle_open_errno(root, dir, now, "open", errno, NULL);
    closedir(osdir);
    return NULL;
  }
  if (fstat(newwd, &st) == -1 || fstat(dirfd(osdir), &osdirst) == -1) {
    // whaaa?
    w_log(W_LOG_ERR, "fstat on opened dir %s failed: %s\n", path,
        strerror(errno));
    w_root_schedule_recrawl(root, "fstat failed");
    close(newwd);
    closedir(osdir);
    return NULL;
  }

  if (st.st_dev != osdirst.st_dev || st.st_ino != osdirst.st_ino) {
    // directory got replaced between opendir and open -- at this point its
    // parent's being watched, so we let filesystem events take care of it
    handle_open_errno(root, dir, now, "open", ENOTDIR, NULL);
    close(newwd);
    closedir(osdir);
    return NULL;
  }

  memset(&k, 0, sizeof(k));
  EV_SET(&k, newwd, EVFILT_VNODE, EV_ADD|EV_CLEAR,
      NOTE_WRITE|NOTE_DELETE|NOTE_EXTEND|NOTE_RENAME,
      0, SET_DIR_BIT(dir->path));

  // Our mapping needs to be visible before we add it to the queue,
  // otherwise we can get a wakeup and not know what it is
  pthread_mutex_lock(&state->lock);
  w_ht_replace(state->name_to_fd, w_ht_ptr_val(dir->path), newwd);
  w_ht_replace(state->fd_to_name, newwd, w_ht_ptr_val(dir->path));
  pthread_mutex_unlock(&state->lock);

  if (kevent(state->kq_fd, &k, 1, NULL, 0, 0)) {
    w_log(W_LOG_DBG, "kevent EV_ADD dir %s failed: %s",
        path, strerror(errno));
    close(newwd);

    pthread_mutex_lock(&state->lock);
    w_ht_del(state->name_to_fd, w_ht_ptr_val(dir->path));
    w_ht_del(state->fd_to_name, newwd);
    pthread_mutex_unlock(&state->lock);
  } else {
    w_log(W_LOG_DBG, "kevent dir %s -> %d\n", dir->path->buf, newwd);
  }

  return osdir;
}