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;
}