void FileSystemWatcher::pathsRemoved(const Set<Path>& paths) { for (const Path& path : paths) { //printf("really removed %s\n", path.constData()); mRemoved(path); } }
void FileSystemWatcher::pathsRemoved(const Set<Path>& paths) { for (const Path& path : paths) { mRemoved(path); } }
void FileSystemWatcher::notifyReadyRead() { FSUserData data; { enum { MaxEvents = 5 }; struct kevent events[MaxEvents]; struct timespec nullts = { 0, 0 }; int ret; for (;;) { ret = ::kevent(mFd, 0, 0, events, MaxEvents, &nullts); if (ret == 0) { break; } else if (ret == -1) { error("FileSystemWatcher::notifyReadyRead() kevent failed (%d) %s", errno, Rct::strerror().constData()); break; } assert(ret > 0 && ret <= MaxEvents); for (int i = 0; i < ret; ++i) { std::unique_lock<std::mutex> lock(mMutex); const struct kevent& event = events[i]; const Path p = mWatchedById.value(event.ident); if (event.flags & EV_ERROR) { error("FileSystemWatcher::notifyReadyRead() kevent element failed for '%s' (%ld) %s", p.constData(), event.data, Rct::strerror(event.data).constData()); continue; } if (p.isEmpty()) { warning() << "FileSystemWatcher::notifyReadyRead() We don't seem to be watching " << p; continue; } if (event.fflags & (NOTE_DELETE|NOTE_REVOKE|NOTE_RENAME)) { // our path has been removed const int wd = event.ident; mWatchedById.remove(wd); mWatchedByPath.remove(p); data.all.clear(); Map<Path, uint64_t>::iterator it = mTimes.lower_bound(p); while (it != mTimes.end() && it->first.startsWith(p)) { data.all.insert(it->first); mTimes.erase(it++); } struct kevent change; struct timespec nullts = { 0, 0 }; EV_SET(&change, wd, EVFILT_VNODE, EV_DELETE, 0, 0, 0); ::kevent(mFd, &change, 1, 0, 0, &nullts); ::close(wd); } else if (p.exists()) { // Figure out what has been changed data.watcher = this; data.added.clear(); data.modified.clear(); data.all.clear(); Map<Path, uint64_t>::iterator it = mTimes.lower_bound(p); while (it != mTimes.end() && it->first.startsWith(p)) { data.all.insert(it->first); ++it; } //printf("before updateFiles, path %s, all %d\n", p.nullTerminated(), data.all.size()); p.visit([&data](const Path &p) { return updateFiles(p, &data); }); //printf("after updateFiles, added %d, modified %d, removed %d\n", // data.added.size(), data.modified.size(), data.all.size()); lock.unlock(); struct { Signal<std::function<void(const Path&)> > &signal; const Set<Path> &paths; } signals[] = { { mModified, data.modified }, { mAdded, data.added } }; const unsigned int count = sizeof(signals) / sizeof(signals[0]); for (unsigned i=0; i<count; ++i) { for (Set<Path>::const_iterator it = signals[i].paths.begin(); it != signals[i].paths.end(); ++it) { signals[i].signal(*it); } } } if (lock.owns_lock()) lock.unlock(); for (Set<Path>::const_iterator it = data.all.begin(); it != data.all.end(); ++it) { mRemoved(*it); } } } } }