Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support additional event types #519

Open
arp242 opened this issue Oct 13, 2022 · 4 comments
Open

Support additional event types #519

arp242 opened this issue Oct 13, 2022 · 4 comments
Labels

Comments

@arp242
Copy link
Member

arp242 commented Oct 13, 2022

We only have Create, Remove, Rename, Write, and Chmod now, but many watchers support additional events. This has come up a few times:

Instead of creating a bunch of issues for every possible event, track them here.

All of this depends on #7; we don't want to spam people with e.g. Open and Close
events when they're not interested in them (which is most of the time), and some
events aren't supported on all platforms.

@arp242
Copy link
Member Author

arp242 commented Oct 14, 2022

I looked around a bit, and:

  • Linux has OPEN and CLOSE events, FreeBSD has NOTE_OPEN, NOTE_CLOSE, NOTE_CLOSE_WRITE, but none of the other kqueue platforms do; Windows and FEN doesn't have it either.

  • Unmount is available on inotify and FEN, but none of the kqueue platforms or Windows.

  • Read is on FreeBSD, Linux (as ACCESS), FEN (as ACCESS), Windows (LAST_ACCESS), but none of the other kqueue platforms.

As far as I can see, there are no events that are shared by all platforms.

Need to think about how to best deal with this; #67 would be okay for some rare operations, but things like Read is available on quite a few platforms, and using a new .Sys() would be awkward.

One way might be creating a new UnportableOp type:

// UnportableOp are file operations that are not available on all platforms.
type UnportableOp uint32

const (
	Read OP = 1 << iota
	Open
	Close
	// ...
)

type Event struct {
	Name       string
	Op         Op
	Unportable UnportableOp
}

func (e Event) HasUnportable(op UnportableOp) bool {
	return e.Unportable.Has(op)
}

This way it's always clear you're using unportable operations and can't accidentally do e.Has(fsnotify.Read) and expecting it to work on all platforms; I don't trust people to read the documentation because experience has proven many don't (plus, it's easy to forget). On the other hand, having two types is a bit of a pain.

@nickajacks1
Copy link

@arp242 What about leveraging GOOS build tags to limit which events can be used?
You could have a file or package for windows specific events, one for inotify specific events, etc
If each platform's non-portable bits had their own package, their usage limitations would be self documenting (eg inotify.Close, defined in github.com/fsnotify/fsnotify/pkg/inotify)
Would there be a problem with making this seamlessly handled by go build, without any kind of explicit opt-in?

With non-portable events guarded by build flags, if someone tried to build the following code for darwin, they'd get a compilation error:

event := <-watcher.Events
if event.Has(inotify.Close) {
	fmt.Println("File was closed")
}

@arp242
Copy link
Member Author

arp242 commented Apr 28, 2024

The problem with that is that many unportable events are supported by more than one platform. And even for events on one platform it's awkward to have fallbacks – I suppose you could make special handling for every platform, but that somewhat defeats the purpose of this library.

Anyway, proposal at: #629

@arp242
Copy link
Member Author

arp242 commented Apr 28, 2024

Overview of additional event types:

inotify

IN_ACCESS          File was accessed (e.g., read(2), execve(2)).
IN_CLOSE_NOWRITE   File or directory not opened for writing was closed.
IN_CLOSE_WRITE     File opened for writing was closed.
IN_OPEN            File or directory was opened.

fanotify

FAN_ACCESS         file or a directory (but see BUGS) was accessed (read).
FAN_CLOSE_NOWRITE  file or directory that was opened read-only (O_RDONLY) was closed.
FAN_CLOSE_WRITE    file that was opened for writing (O_WRONLY or O_RDWR) was closed.
FAN_FS_ERROR       filesystem error was detected.
FAN_OPEN           file or a directory was opened.
FAN_OPEN_EXEC      file was opened with the intent to be executed.

FreeBSD

NOTE_CLOSE         A file descriptor referencing the monitored file, was closed. The closed file de scriptor did not have write access.
NOTE_CLOSE_WRITE   A file descriptor referencing the monitored file, was closed. The closed file descriptor had write access.
NOTE_EXTEND        For regular file, the file referenced by the descriptor was extended.
NOTE_LINK          The link count on the file changed.
NOTE_OPEN          The file referenced by the descriptor was opened.
NOTE_READ          A read occurred on the file referenced by the descriptor.
NOTE_REVOKE        Access to the file was revoked via revoke(2) or the underlying file system was unmounted.

OpenBSD

NOTE_EXTEND        The file referenced by the descriptor was extended.
NOTE_LINK          The link count on the file changed.
NOTE_TRUNCATE      The file referenced by the descriptor was truncated.

NetBSD

NOTE_EXTEND        The file referenced by the descriptor was extended.
NOTE_LINK          The link count on the file changed.
NOTE_REVOKE        Access to the file was revoked via revoke(2) or the underlying file system was unmounted.

Added in NetBSD 10 (March 2024, needs update to x/sys)

NOTE_CLOSE         A file descriptor without write access referencing the file was closed.
NOTE_CLOSE_WRITE   A file descriptor with write access referencing the file was closed.
NOTE_OPEN          The file referenced by the descriptor was opened.
NOTE_READ          A read occurred on the file referenced by the descriptor.

DragonflyBSD

NOTE_EXTEND        The file referenced by the descriptor was extended.
NOTE_LINK          The link count on the file changed.
NOTE_REVOKE        Access to the file was revoked via revoke(2) or the underlying fileystem was unmounted.

FEN

FILE_ACCESS        fo_atime change
FILE_TRUNC         op that induced the time stamp update also truncated the file
MOUNTEDOVER        /* Monitored file/directory was mounted over */
UNMOUNTED          /* Monitored file system got unmounted */

Windows

CHANGE_LAST_ACCESS     Any change to the last access time
CHANGE_SIZE            Any file-size change in the watched directory or subtree (might reasonably emulate CloseWrite?)

fsevents

?

arp242 added a commit that referenced this issue May 1, 2024
This adds the ability to only listen for some event types. If you're
only interested in Created events and you're getting a lot of Write
events then you're just wasting CPU cycles

This also adds the ability listen on extra unportable event types; since
this is so related I figured I might as well do both. Ideally we want to
1) make it very very obvious you're doing something unportable, and 2)
make it reasonably easy "fallback" for platforms where this isn't
supported.

Unportable events start with "Unportable", which should document their
unportabilitiness. Also add a new Supports(Op) method, which should make
adding fallback logic relatively painless.

For example, to use CloseWrite where supported, but falling back to
Write when it's not:

	var op fsnotify.Op
	if w.Supports(fsnotify.UnportableCloseWrite) {
		op |= fsnotify.UnportableCloseWrite
	} else {
		op |= fsnotify.Create | fsnotify.Write
	}
	w.AddWith("/tmp", fsnotify.WithEvents(op))

And then you can deal with this in the write loop. There's a full
example in cmd/fsnotify/closewrite.go

All of this is unexported for now, until support for other platforms has
been added.

Updates #7
Updates #519
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants