Kir Kolyshkin [Thu, 21 Jul 2022 11:32:11 +0000 (04:32 -0700)]
Do not suppress Chmod on non-existent file (#260)
Currently fsnotify suppresses a Chmod event if the file does not exist
when the event is received.
This makes it impossible to use fsnotify to detect when an opened file
is removed. In such case the Linux kernel sends IN_ATTRIB event,
as described in inotify(7) man page:
> IN_ATTRIB (*)
> Metadata changed—for example, permissions (e.g., chmod(2)),
> timestamps (e.g., utimensat(2)), extended attributes (setx‐
> attr(2)), link count (since Linux 2.6.25; e.g., for the tar‐
> get of link(2) and for unlink(2)), and user/group ID (e.g.,
> chown(2)).
(to clarify, in this very case it's link count that changes).
To fix:
* Modify the code to only suppress MODIFY and CREATE events.
* Add a test case to verify Chmod event is delivered.
While at it, fix the comment in ignoreLinux() to use the up-to-date
terminology (event ops).
A test case is added.
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Nick Santos [Thu, 21 Jul 2022 10:20:14 +0000 (11:20 +0100)]
kqueue: Make watcher.Close() O(n) instead of O(n^2) (#233)
In the old implementation watcher.Close() would clone the list of
watches and then run Remove() on that, and every Remove() call would
iterate over the full list of watches.
This stores the watches more efficiently so that Remove() doesn't need
to iterate over the full list: instead of merely a path → fd map, it
also stores a parent-path → list-of-files.
No functional changes, just a performance improvement.
Martin Tournoij [Thu, 21 Jul 2022 03:06:57 +0000 (05:06 +0200)]
Use common error when removing an unwatched file (#460)
The errors returned by the various implementations of the watcher are all different
which makes handling them difficult. This PR follows the suggestion in:
https://github.com/fsnotify/fsnotify/pull/455#issuecomment-1146037157 by @mattn
to create a common error which is wrapped by the implementations.
Replaces: https://github.com/fsnotify/fsnotify/pull/455 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Andrew Thornton <art27@cantab.net>
Robert Fratto [Thu, 21 Jul 2022 03:06:40 +0000 (23:06 -0400)]
windows: protect access to isClosed with mutex (#454)
isClosed may be read and modified concurrently if the Windows Watcher is
closed at the same time as a new entry being added. This change protects
isClosed to prevent race conditions.
The order of fields for the Windows Watcher have been rearranged to
group fields protected by the mutex together.
Tobias Klauser [Tue, 25 Jan 2022 02:13:06 +0000 (03:13 +0100)]
Allow build on unsupported GOOS (#424)
In cases where fsnotify is a transitive dependency of a package, it
might need to be built on platforms not supported (yet), e.g. aix.
Provide an empty implemention for these cases, so depending packages
don't need to add workarounds.
Tobias Klauser [Wed, 19 Jan 2022 14:22:52 +0000 (15:22 +0100)]
Don't set poller.fd twice in newFdPoller (#406)
In newEmptyPoller when creating the poller using newEmptyPoller(fd), the
fd field of the poller instance is already set. There is no need to set
it again.
Aaron L [Wed, 29 Mar 2017 04:21:07 +0000 (21:21 -0700)]
Fix deadlock in Remove (linux/inotify)
Several people have reported this issue where if you are using a
single goroutine to watch for fs events and you call Remove in
that goroutine it can deadlock. The cause for this is that the Remove
was made synchronous by PR #73. The reason for this was to try and
ensure that maps were no longer leaking.
In this PR: IN_IGNORE was used as the event to ensure map cleanup.
This worked fine when Remove() was called and the next event was
IN_IGNORE, but when a different event was received the main goroutine
that's supposed to be reading from the Events channel would be stuck
waiting for the sync.Cond, which would never be hit because the select
would then block waiting for someone to receive the non-IN_IGNORE event
from the channel so it could proceed to process the IN_IGNORE event that
was waiting in the queue. Deadlock :)
Removing the synchronization then created two nasty races where Remove
followed by Remove would error unnecessarily, and one where Remove
followed by an Add could result in the maps being cleaned up AFTER the
Add call which means the inotify watch is active, but our maps don't
have the values anymore. It then becomes impossible to delete the
watches via the fsnotify code since it checks it's local data before
calling InotifyRemove.
This code attempts to use IN_DELETE_SELF as a means to know when a watch
was deleted as part of an unlink(). That means that we didn't delete the
watch via the fsnotify lib and we should clean up our maps since that
watch no longer exists. This allows us to clean up the maps immediately
when calling Remove since we no longer try to synchronize cleanup
using IN_IGNORE as the sync point.
If Watcher.Add is called with the same name from multiple goroutines and
name is not already in the watches map then the last call to complete
wins and the watch created by the first call to complete is lost.
This commit holds the mutex for the full duration of the update to the
watches map.
* avoid clobbering existing flags if inotify_add_watch fails
Previously, the watch entry is the watches map was updated before the
call to InotifyAddWatch. If InotifyAddWatch fails then this left the
watch entry in an inconsistent state.
The syscall package is locked since 1.4[1], all new changes are in x/sys[2]
The fixes for epoll/arm64 are going to be loaded to x/sys/unix. This
commit is straightforward search/replace with a couple of hand edits.
`os.Lstat` does not return `error` when a file/directory exists,
so the code path to check for newly created files after a REMOVE
on BSD was never executed.
Also, if the watched entry is a file, it has been removed from the watcher, so do a new-file-check for them as well.
This commit fixes issues on TextMate on OS X and others that uses `exchangedata` to do atomic saves.