in watchman/watcher/fsevents.cpp [679:802]
Watcher::ConsumeNotifyRet FSEventsWatcher::consumeNotify(
const std::shared_ptr<Root>& root,
PendingChanges& coll) {
char flags_label[128];
std::vector<std::vector<watchman_fsevent>> items;
std::vector<folly::Promise<folly::Unit>> syncs;
bool cancelSelf = false;
{
auto wlock = items_.lock();
std::swap(items, wlock->items);
std::swap(syncs, wlock->syncs);
}
auto now = std::chrono::system_clock::now();
for (auto& vec : items) {
for (auto& item : vec) {
w_expand_flags(kflags, item.flags, flags_label, sizeof(flags_label));
logf(
DBG,
"fsevents: got {} {:x} {}\n",
item.path,
item.flags,
flags_label);
if (item.flags &
(kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped)) {
if (!subdir) {
root->scheduleRecrawl(flags_label);
break;
} else {
w_assert(
item.flags & kFSEventStreamEventFlagMustScanSubDirs,
"dropped events should specify kFSEventStreamEventFlagMustScanSubDirs");
auto reason = fmt::format("{}: {}", *subdir, flags_label);
root->recrawlTriggered(reason.c_str());
}
}
if (item.flags & kFSEventStreamEventFlagUnmount) {
logf(
ERR,
"kFSEventStreamEventFlagUnmount {}, cancel watch\n",
item.path);
cancelSelf = true;
break;
}
if ((item.flags & kFSEventStreamEventFlagItemRemoved) &&
isRootRemoved(item.path, root->root_path, subdir)) {
log(ERR, "Root directory removed, cancel watch\n");
cancelSelf = true;
break;
}
if (item.flags & kFSEventStreamEventFlagRootChanged) {
logf(
ERR,
"kFSEventStreamEventFlagRootChanged {}, cancel watch\n",
item.path);
cancelSelf = true;
break;
}
if (!hasFileWatching_ && item.path.size() < root->root_path.size()) {
// The test_watch_del_all appear to trigger this?
log(ERR,
"Got an event on a directory parent to the root directory: {}?\n",
item.path);
continue;
}
PendingFlags flags = W_PENDING_VIA_NOTIFY;
if (item.flags &
(kFSEventStreamEventFlagMustScanSubDirs |
kFSEventStreamEventFlagItemRenamed)) {
flags.set(W_PENDING_RECURSIVE);
} else if (item.flags & kFSEventStreamEventFlagItemRenamed) {
// FSEvents does not reliably report the individual files renamed in the
// hierarchy.
flags.set(W_PENDING_NONRECURSIVE_SCAN);
} else if (!hasFileWatching_) {
flags.set(W_PENDING_NONRECURSIVE_SCAN);
}
if (item.flags &
(kFSEventStreamEventFlagUserDropped |
kFSEventStreamEventFlagKernelDropped)) {
flags.set(W_PENDING_IS_DESYNCED);
}
coll.add(item.path, now, flags);
if (hasFileWatching_ && item.path.size() > root->root_path.size() &&
(item.flags &
(kFSEventStreamEventFlagItemRenamed |
kFSEventStreamEventFlagItemCreated |
kFSEventStreamEventFlagItemRemoved))) {
// When the list of directory entries is modified, we hear
// about the modification, but perhaps not the directory
// change itself. Its mtime probably changed, so synthesize
// an event to consider it for examination.
//
// Note these two issues:
// - https://github.com/facebook/watchman/issues/305
// - https://github.com/facebook/watchman/issues/307
//
// Watchman does not guarantee minimal notifications, but limiting
// the event types above should avoid unnecessary results in
// queries.
coll.add(item.path.dirName(), now, W_PENDING_VIA_NOTIFY);
}
}
}
for (auto& sync : syncs) {
coll.addSync(std::move(sync));
}
return {cancelSelf};
}