Improve inotify()-based wxFileSystemWatcher to handle creation/deletion.

Handle creation and deletion of directories under the watched path better.

See #14544.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72689 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2012-10-16 14:02:40 +00:00
parent 723a83c94a
commit 20ffcd779a
2 changed files with 85 additions and 0 deletions

View File

@ -26,6 +26,8 @@ public:
virtual ~wxInotifyFileSystemWatcher();
void OnDirDeleted(const wxString& path);
protected:
bool Init();
};

View File

@ -271,6 +271,76 @@ protected:
{
return;
}
// Creation
// We need do something here only if the original watch was recursive;
// we don't watch a child dir itself inside a non-tree watch.
// We watch only dirs explicitly, so we don't want file IN_CREATEs.
// Distinguish by whether nativeFlags contain IN_ISDIR
else if ((nativeFlags & IN_CREATE) &&
(watch.GetType() == wxFSWPath_Tree) && (inevt.mask & IN_ISDIR))
{
wxFileName fn = GetEventPath(watch, inevt);
// Though it's a dir, fn treats it as a file. So:
fn.AssignDir(fn.GetFullPath());
if (m_watcher->AddAny(fn, wxFSW_EVENT_ALL,
wxFSWPath_Tree, watch.GetFilespec()))
{
// Tell the owner, in case it's interested
// If there's a filespec, assume he's not
if (watch.GetFilespec().empty())
{
wxFileSystemWatcherEvent event(flags, fn, fn);
SendEvent(event);
}
}
}
// Deletion
// We watch only dirs explicitly, so we don't want file IN_DELETEs.
// We obviously can't check using DirExists() as the object has been
// deleted; and nativeFlags here doesn't contain IN_ISDIR, even for
// a dir. Fortunately IN_DELETE_SELF doesn't happen for files. We need
// to do something here only inside a tree watch, or if it's the parent
// dir that's deleted. Otherwise let the parent dir cope
else if ((nativeFlags & IN_DELETE_SELF) &&
((watch.GetType() == wxFSWPath_Dir) ||
(watch.GetType() == wxFSWPath_Tree)))
{
// We must remove the deleted directory from the map, so that
// DoRemoveInotify() isn't called on it in the future. Don't assert
// if the wd isn't found: repeated IN_DELETE_SELFs can occur
wxFileName fn = GetEventPath(watch, inevt);
wxString path(fn.GetPathWithSep());
if (m_watchMap.erase(inevt.wd) == 1)
{
// Delete from wxFileSystemWatcher
wxDynamicCast(m_watcher, wxInotifyFileSystemWatcher)->
OnDirDeleted(path);
// Now remove from our local list of watched items
wxFSWatchEntries::iterator wit =
m_watches.find(path);
if (wit != m_watches.end())
{
m_watches.erase(wit);
}
// Cache the wd in case any events arrive late
m_staleDescriptors.Add(inevt.wd);
}
// Tell the owner, in case it's interested
// If there's a filespec, assume he's not
if (watch.GetFilespec().empty())
{
wxFileSystemWatcherEvent event(flags, fn, fn);
SendEvent(event);
}
}
// renames
else if (nativeFlags & IN_MOVE)
{
@ -535,6 +605,19 @@ bool wxInotifyFileSystemWatcher::Init()
return m_service->Init();
}
void wxInotifyFileSystemWatcher::OnDirDeleted(const wxString& path)
{
if (!path.empty())
{
wxFSWatchInfoMap::iterator it = m_watches.find(path);
wxCHECK_RET(it != m_watches.end(),
wxString::Format("Path '%s' is not watched", path));
// path has been deleted, so we must forget it whatever its refcount
m_watches.erase(it);
}
}
#endif // wxHAS_INOTIFY
#endif // wxUSE_FSWATCHER