Example #1
0
    void ProcessRenames()
    {
        wxInotifyCookies::iterator it = m_cookies.begin();
        while ( it != m_cookies.end() )
        {
            inotify_event& inevt = *(it->second);

            wxLogTrace(wxTRACE_FSWATCHER, "Processing pending rename events");
            wxLogTrace(wxTRACE_FSWATCHER, InotifyEventToString(inevt));

            // get watch entry for this event
            wxFSWatchEntryDescriptors::iterator wit = m_watchMap.find(inevt.wd);
            wxCHECK_RET(wit != m_watchMap.end(),
                             "Watch descriptor not present in the watch map!");

            wxFSWatchEntry& watch = *(wit->second);
            int flags = Native2WatcherFlags(inevt.mask);
            wxFileName path = GetEventPath(watch, inevt);
            wxFileSystemWatcherEvent event(flags, path, path);
            SendEvent(event);

            m_cookies.erase(it);
            delete &inevt;
            it = m_cookies.begin();
        }
    }
Example #2
0
void wxIOCPThread::ProcessNativeEvents(wxVector<wxEventProcessingData>& events)
{
    wxVector<wxEventProcessingData>::iterator it = events.begin();
    for ( ; it != events.end(); ++it )
    {
        const FILE_NOTIFY_INFORMATION& e = *(it->nativeEvent);
        const wxFSWatchEntryMSW* watch = it->watch;

        wxLogTrace( wxTRACE_FSWATCHER, "[iocp] %s",
                    FileNotifyInformationToString(e));

        int nativeFlags = e.Action;
        int flags = Native2WatcherFlags(nativeFlags);
        if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR)
        {
            wxFileSystemWatcherEvent
                event(flags,
                      flags & wxFSW_EVENT_ERROR ? wxFSW_WARNING_NONE
                                                : wxFSW_WARNING_GENERAL);
            SendEvent(event);
        }
        // filter out ignored events and those not asked for.
        // we never filter out warnings or exceptions
        else if ((flags == 0) || !(flags & watch->GetFlags()))
        {
            return;
        }
        // rename case
        else if (nativeFlags == FILE_ACTION_RENAMED_OLD_NAME)
        {
            wxFileName oldpath = GetEventPath(*watch, e);
            wxFileName newpath;

            // newpath should be in the next entry. what if there isn't?
            ++it;
            if ( it != events.end() )
            {
                newpath = GetEventPath(*(it->watch), *(it->nativeEvent));
            }
            wxFileSystemWatcherEvent event(flags, oldpath, newpath);
            SendEvent(event);
        }
        // all other events
        else
        {
            // CHECK I heard that returned path can be either in short on long
            // form...need to account for that!
            wxFileName path = GetEventPath(*watch, e);
            // For files, check that it matches any filespec
            if ( m_service->MatchesFilespec(path, watch->GetFilespec()) )
            {
                wxFileSystemWatcherEvent event(flags, path, path);
                SendEvent(event);
            }
        }
    }
}
    void ProcessRenames()
    {
        // After all of a batch of events has been processed, this deals with
        // any still-unpaired IN_MOVED_FROM or IN_MOVED_TO events.
        wxInotifyCookies::iterator it = m_cookies.begin();
        while ( it != m_cookies.end() )
        {
            inotify_event& inevt = *(it->second);

            wxLogTrace(wxTRACE_FSWATCHER, "Processing pending rename events");
            wxLogTrace(wxTRACE_FSWATCHER, InotifyEventToString(inevt));

            // get watch entry for this event
            wxFSWatchEntryDescriptors::iterator wit = m_watchMap.find(inevt.wd);
            if (wit == m_watchMap.end())
            {
                wxLogTrace(wxTRACE_FSWATCHER,
                            "Watch descriptor not present in the watch map!");
            }
            else
            {
                // Tell the owner, in case it's interested
                // If there's a filespec, assume he's not
                wxFSWatchEntry& watch = *(wit->second);
                if ( watch.GetFilespec().empty() )
                {
                    int flags = Native2WatcherFlags(inevt.mask);
                    wxFileName path = GetEventPath(watch, inevt);
                    {
                        wxFileSystemWatcherEvent event(flags, path, path);
                        SendEvent(event);
                    }
                }
            }

            m_cookies.erase(it);
            delete &inevt;
            it = m_cookies.begin();
        }
    }
Example #4
0
    void ProcessNativeEvent(const inotify_event& inevt)
    {
        wxLogTrace(wxTRACE_FSWATCHER, InotifyEventToString(inevt));

        // after removing inotify watch we get IN_IGNORED for it, but the watch
        // will be already removed from our list at that time
        if (inevt.mask & IN_IGNORED)
        {
            return;
        }

        // get watch entry for this event
        wxFSWatchEntryDescriptors::iterator it = m_watchMap.find(inevt.wd);
        wxCHECK_RET(it != m_watchMap.end(),
                             "Watch descriptor not present in the watch map!");

        wxFSWatchEntry& watch = *(it->second);
        int nativeFlags = inevt.mask;
        int flags = Native2WatcherFlags(nativeFlags);

        // check out for error/warning condition
        if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR)
        {
            wxString errMsg = GetErrorDescription(Watcher2NativeFlags(flags));
            wxFileSystemWatcherEvent event(flags, errMsg);
            SendEvent(event);
        }
        // filter out ignored events and those not asked for.
        // we never filter out warnings or exceptions
        else if ((flags == 0) || !(flags & watch.GetFlags()))
        {
            return;
        }
        // renames
        else if (nativeFlags & IN_MOVE)
        {
            wxInotifyCookies::iterator it = m_cookies.find(inevt.cookie);
            if ( it == m_cookies.end() )
            {
                int size = sizeof(inevt) + inevt.len;
                inotify_event* e = (inotify_event*) operator new (size);
                memcpy(e, &inevt, size);

                wxInotifyCookies::value_type val(e->cookie, e);
                m_cookies.insert(val);
            }
            else
            {
                inotify_event& oldinevt = *(it->second);

                wxFileSystemWatcherEvent event(flags);
                if ( inevt.mask & IN_MOVED_FROM )
                {
                    event.SetPath(GetEventPath(watch, inevt));
                    event.SetNewPath(GetEventPath(watch, oldinevt));
                }
                else
                {
                    event.SetPath(GetEventPath(watch, oldinevt));
                    event.SetNewPath(GetEventPath(watch, inevt));
                }
                SendEvent(event);

                m_cookies.erase(it);
                delete &oldinevt;
            }
        }
        // every other kind of event
        else
        {
            wxFileName path = GetEventPath(watch, inevt);
            wxFileSystemWatcherEvent event(flags, path, path);
            SendEvent(event);
        }
    }
Example #5
0
    void ProcessNativeEvent(const inotify_event& inevt)
    {
        wxLogTrace(wxTRACE_FSWATCHER, InotifyEventToString(inevt));

        // after removing inotify watch we get IN_IGNORED for it, but the watch
        // will be already removed from our list at that time
        if (inevt.mask & IN_IGNORED)
        {
            // It is now safe to remove it from the stale descriptors too, we
            // won't get any more events for it.
            // However if we're here because a dir that we're still watching
            // has just been deleted, its wd won't be on this list
            const int pos = m_staleDescriptors.Index(inevt.wd);
            if ( pos != wxNOT_FOUND )
            {
                m_staleDescriptors.RemoveAt(static_cast<size_t>(pos));
                wxLogTrace(wxTRACE_FSWATCHER,
                       "Removed wd %i from the stale-wd cache", inevt.wd);
            }
            return;
        }

        // get watch entry for this event
        wxFSWatchEntryDescriptors::iterator it = m_watchMap.find(inevt.wd);
        if (it == m_watchMap.end())
        {
            // It's not in the map; check if was recently removed from it.
            if (m_staleDescriptors.Index(inevt.wd) != wxNOT_FOUND)
            {
                wxLogTrace(wxTRACE_FSWATCHER,
                           "Got an event for stale wd %i", inevt.wd);
            }
            else
            {
                wxFAIL_MSG("Event for unknown watch descriptor.");
            }

            // In any case, don't process this event: it's either for an
            // already removed entry, or for a completely unknown one.
            return;
        }

        wxFSWatchEntry& watch = *(it->second);
        int nativeFlags = inevt.mask;
        int flags = Native2WatcherFlags(nativeFlags);

        // check out for error/warning condition
        if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR)
        {
            wxString errMsg = GetErrorDescription(Watcher2NativeFlags(flags));
            wxFileSystemWatcherEvent event(flags, errMsg);
            SendEvent(event);
        }
        // filter out ignored events and those not asked for.
        // we never filter out warnings or exceptions
        else if ((flags == 0) || !(flags & watch.GetFlags()))
        {
            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)
        {
            wxInotifyCookies::iterator it2 = m_cookies.find(inevt.cookie);
            if ( it2 == m_cookies.end() )
            {
                int size = sizeof(inevt) + inevt.len;
                inotify_event* e = (inotify_event*) operator new (size);
                memcpy(e, &inevt, size);

                wxInotifyCookies::value_type val(e->cookie, e);
                m_cookies.insert(val);
            }
            else
            {
                inotify_event& oldinevt = *(it2->second);

                // Tell the owner, in case it's interested
                // If there's a filespec, assume he's not
                if ( watch.GetFilespec().empty() )
                {
                    wxFileSystemWatcherEvent event(flags);
                    if ( inevt.mask & IN_MOVED_FROM )
                    {
                        event.SetPath(GetEventPath(watch, inevt));
                        event.SetNewPath(GetEventPath(watch, oldinevt));
                    }
                    else
                    {
                        event.SetPath(GetEventPath(watch, oldinevt));
                        event.SetNewPath(GetEventPath(watch, inevt));
                    }
                    SendEvent(event);
                }

                m_cookies.erase(it2);
                delete &oldinevt;
            }
        }
        // every other kind of event
        else
        {
            wxFileName path = GetEventPath(watch, inevt);
            // For files, check that it matches any filespec
            if ( MatchesFilespec(path, watch.GetFilespec()) )
            {
                wxFileSystemWatcherEvent event(flags, path, path);
                SendEvent(event);
            }
        }
    }
    void ProcessNativeEvent(const inotify_event& inevt)
    {
        wxLogTrace(wxTRACE_FSWATCHER, InotifyEventToString(inevt));

        // after removing inotify watch we get IN_IGNORED for it, but the watch
        // will be already removed from our list at that time
        if (inevt.mask & IN_IGNORED)
        {
            // It is now safe to remove it from the stale descriptors too, we
            // won't get any more events for it.
            // However if we're here because a dir that we're still watching
            // has just been deleted, its wd won't be on this list
            const int pos = m_staleDescriptors.Index(inevt.wd);
            if ( pos != wxNOT_FOUND )
            {
                m_staleDescriptors.RemoveAt(static_cast<size_t>(pos));
                wxLogTrace(wxTRACE_FSWATCHER,
                       "Removed wd %i from the stale-wd cache", inevt.wd);
            }
            return;
        }

        // get watch entry for this event
        wxFSWatchEntryDescriptors::iterator it = m_watchMap.find(inevt.wd);

        // wd will be -1 for IN_Q_OVERFLOW, which would trigger the wxFAIL_MSG
        if (inevt.wd != -1)
        {
            if (it == m_watchMap.end())
            {
                // It's not in the map; check if was recently removed from it.
                if (m_staleDescriptors.Index(inevt.wd) != wxNOT_FOUND)
                {
                    wxLogTrace(wxTRACE_FSWATCHER,
                               "Got an event for stale wd %i", inevt.wd);
                }
                else
                {
                    // In theory we shouldn't reach here. In practice, some
                    // events, e.g. IN_MODIFY, arrive just after the IN_IGNORED
                    // so their wd has already been discarded. Warn about them.
                    wxFileSystemWatcherEvent
                        event
                        (
                            wxFSW_EVENT_WARNING,
                            wxFSW_WARNING_GENERAL,
                            wxString::Format
                            (
                             _("Unexpected event for \"%s\": no "
                               "matching watch descriptor."),
                             inevt.len ? inevt.name : ""
                            )
                        );
                    SendEvent(event);

                }

                // In any case, don't process this event: it's either for an
                // already removed entry, or for an unknown one.
                return;
            }
        }

        int nativeFlags = inevt.mask;
        int flags = Native2WatcherFlags(nativeFlags);

        // check out for error/warning condition
        if (flags & wxFSW_EVENT_WARNING || flags & wxFSW_EVENT_ERROR)
        {
            wxFSWWarningType warningType;
            if ( flags & wxFSW_EVENT_WARNING )
            {
                warningType = nativeFlags & IN_Q_OVERFLOW
                                ? wxFSW_WARNING_OVERFLOW
                                : wxFSW_WARNING_GENERAL;
            }
            else // It's an error, not a warning.
            {
                warningType = wxFSW_WARNING_NONE;
            }

            wxFileSystemWatcherEvent event(flags, warningType);
            SendEvent(event);
            return;
        }

        if (inevt.wd == -1)
        {
            // Although this is not supposed to happen, we seem to be getting
            // occasional IN_ACCESS/IN_MODIFY events without valid watch value.
            wxFileSystemWatcherEvent
                event
                (
                    wxFSW_EVENT_WARNING,
                    wxFSW_WARNING_GENERAL,
                    wxString::Format
                    (
                        _("Invalid inotify event for \"%s\""),
                        inevt.len ? inevt.name : ""
                    )
                );
            SendEvent(event);
            return;
        }

        wxFSWatchEntry& watch = *(it->second);

        // Now IN_UNMOUNT. We must do so here, as it's not in the watch flags
        if (nativeFlags & IN_UNMOUNT)
        {
            wxFileName path = GetEventPath(watch, inevt);
            wxFileSystemWatcherEvent event(wxFSW_EVENT_UNMOUNT, path, path);
            SendEvent(event);
        }
        // filter out ignored events and those not asked for.
        // we never filter out warnings or exceptions
        else if ((flags == 0) || !(flags & watch.GetFlags()))
        {
            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());
            const wxString filespec(watch.GetFilespec());

            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 (filespec.empty())
            {
                wxFileSystemWatcherEvent event(flags, fn, fn);
                SendEvent(event);
            }
        }

        // renames
        else if (nativeFlags & IN_MOVE)
        {
            // IN_MOVE events are produced in the following circumstances:
            // * A move within a dir (what the user sees as a rename) gives an
            //   IN_MOVED_FROM and IN_MOVED_TO pair, each with the same path.
            // * A move within watched dir foo/ e.g. from foo/bar1/ to foo/bar2/
            //   will also produce such a pair, but with different paths.
            // * A move to baz/ will give only an IN_MOVED_FROM for foo/bar1;
            //   if baz/ is inside a different watch, that gets the IN_MOVED_TO.

            // The first event to arrive, usually the IN_MOVED_FROM, is
            // cached to await a matching IN_MOVED_TO; should none arrive, the
            // unpaired event will be processed later in ProcessRenames().
            wxInotifyCookies::iterator it2 = m_cookies.find(inevt.cookie);
            if ( it2 == m_cookies.end() )
            {
                int size = sizeof(inevt) + inevt.len;
                inotify_event* e = (inotify_event*) operator new (size);
                memcpy(e, &inevt, size);

                wxInotifyCookies::value_type val(e->cookie, e);
                m_cookies.insert(val);
            }
            else
            {
                inotify_event& oldinevt = *(it2->second);

                // Tell the owner, in case it's interested
                // If there's a filespec, assume he's not
                if ( watch.GetFilespec().empty() )
                {
                    // The only way to know the path for the first event,
                    // normally the IN_MOVED_FROM, is to retrieve the watch
                    // corresponding to oldinevt. This is needed for a move
                    // within a watch.
                    wxFSWatchEntry* oldwatch;
                    wxFSWatchEntryDescriptors::iterator oldwatch_it =
                                                m_watchMap.find(oldinevt.wd);
                    if (oldwatch_it != m_watchMap.end())
                    {
                        oldwatch = oldwatch_it->second;
                    }
                    else
                    {
                        wxLogTrace(wxTRACE_FSWATCHER,
                            "oldinevt's watch descriptor not in the watch map");
                        // For want of a better alternative, use 'watch'. That
                        // will work fine for renames, though not for moves
                        oldwatch = &watch;
                    }

                    wxFileSystemWatcherEvent event(flags);
                    if ( inevt.mask & IN_MOVED_FROM )
                    {
                        event.SetPath(GetEventPath(watch, inevt));
                        event.SetNewPath(GetEventPath(*oldwatch, oldinevt));
                    }
                    else
                    {
                        event.SetPath(GetEventPath(*oldwatch, oldinevt));
                        event.SetNewPath(GetEventPath(watch, inevt));
                    }
                    SendEvent(event);
                }

                m_cookies.erase(it2);
                delete &oldinevt;
            }
        }
        // every other kind of event
        else
        {
            wxFileName path = GetEventPath(watch, inevt);
            // For files, check that it matches any filespec
            if ( MatchesFilespec(path, watch.GetFilespec()) )
            {
                wxFileSystemWatcherEvent event(flags, path, path);
                SendEvent(event);
            }
        }
    }