bool KQueueWatcher::startWatchFile()

in watchman/watcher/kqueue.cpp [71:157]


bool KQueueWatcher::startWatchFile(struct watchman_file* file) {
  struct kevent k;

  auto full_name = file->parent->getFullPathToChild(file->getName());
  {
    auto rlock = maps_.rlock();
    if (rlock->name_to_fd.find(full_name) != rlock->name_to_fd.end()) {
      // Already watching it
      return true;
    }
  }

  logf(DBG, "watch_file({})\n", full_name);

  int openFlags = O_EVTONLY | O_CLOEXEC;
#if HAVE_DECL_O_SYMLINK
  openFlags |= O_SYMLINK;
#endif
  FileDescriptor fdHolder(
      open(full_name.c_str(), openFlags), FileDescriptor::FDType::Generic);

  auto rawFd = fdHolder.fd();

  if (rawFd == -1) {
    watchman::log(
        watchman::ERR,
        "failed to open ",
        full_name,
        ", O_EVTONLY: ",
        folly::errnoStr(errno),
        "\n");
    return false;
  }

  // When not recursive, watchman is watching the top-level directories as
  // files, make sure that we properly mark these as directory watches.
  bool isDir = false;
  if (!recursive_) {
    struct stat st;
    if (fstat(rawFd, &st) == -1) {
      watchman::log(
          watchman::ERR,
          "failed to stat ",
          full_name,
          ": ",
          folly::errnoStr(errno),
          "\n");
      return false;
    }
    isDir = S_ISDIR(st.st_mode);
  }

  memset(&k, 0, sizeof(k));
  EV_SET(
      &k,
      rawFd,
      EVFILT_VNODE,
      EV_ADD | EV_CLEAR,
      NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_RENAME | NOTE_ATTRIB,
      0,
      make_udata(isDir));

  {
    auto wlock = maps_.wlock();
    wlock->name_to_fd[full_name] = std::move(fdHolder);
    wlock->fd_to_name[rawFd] = full_name;
  }

  if (kevent(kq_fd.fd(), &k, 1, nullptr, 0, 0)) {
    watchman::log(
        watchman::DBG,
        "kevent EV_ADD file ",
        full_name,
        " failed: ",
        full_name.c_str(),
        folly::errnoStr(errno),
        "\n");
    auto wlock = maps_.wlock();
    wlock->name_to_fd.erase(full_name);
    wlock->fd_to_name.erase(rawFd);
  } else {
    watchman::log(
        watchman::DBG, "kevent file ", full_name, " -> ", rawFd, "\n");
  }

  return true;
}