// Package fsnotify provides a cross-platform interface for file system // notifications. // // Currently supported systems: // // Linux 2.6.32+ via inotify // BSD, macOS via kqueue // Windows via ReadDirectoryChangesW // illumos via FEN
package fsnotify import ( ) // Event represents a file system notification. type Event struct { // Path to the file or directory. // // Paths are relative to the input; for example with Add("dir") the Name // will be set to "dir/file" if you create that file, but if you use // Add("/path/to/dir") it will be "/path/to/dir/file". Name string // File operation that triggered the event. // // This is a bitmask and some systems may send multiple operations at once. // Use the Event.Has() method instead of comparing with ==. Op Op } // Op describes a set of file operations. type Op uint32 // The operations fsnotify can trigger; see the documentation on [Watcher] for a // full description, and check them with [Event.Has]. const ( // A new pathname was created. Create Op = 1 << iota // The pathname was written to; this does *not* mean the write has finished, // and a write can be followed by more writes. Write // The path was removed; any watches on it will be removed. Some "remove" // operations may trigger a Rename if the file is actually moved (for // example "remove to trash" is often a rename). Remove // The path was renamed to something else; any watched on it will be // removed. Rename // File attributes were changed. // // It's generally not recommended to take action on this event, as it may // get triggered very frequently by some software. For example, Spotlight // indexing on macOS, anti-virus software, backup software, etc. Chmod ) var ( // ErrNonExistentWatch is used when Remove() is called on a path that's not // added. ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch") // ErrClosed is used when trying to operate on a closed Watcher. ErrClosed = errors.New("fsnotify: watcher already closed") // ErrEventOverflow is reported from the Errors channel when there are too // many events: // // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl) // - windows: The buffer size is too small; WithBufferSize() can be used to increase it. // - kqueue, fen: Not used. ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow") ) func ( Op) () string { var strings.Builder if .Has(Create) { .WriteString("|CREATE") } if .Has(Remove) { .WriteString("|REMOVE") } if .Has(Write) { .WriteString("|WRITE") } if .Has(Rename) { .WriteString("|RENAME") } if .Has(Chmod) { .WriteString("|CHMOD") } if .Len() == 0 { return "[no events]" } return .String()[1:] } // Has reports if this operation has the given operation. func ( Op) ( Op) bool { return & != 0 } // Has reports if this event has the given operation. func ( Event) ( Op) bool { return .Op.Has() } // String returns a string representation of the event with their path. func ( Event) () string { return fmt.Sprintf("%-13s %q", .Op.String(), .Name) } type ( addOpt func(opt *withOpts) withOpts struct { bufsize int } ) var defaultOpts = withOpts{ bufsize: 65536, // 64K } func getOptions( ...addOpt) withOpts { := defaultOpts for , := range { (&) } return } // WithBufferSize sets the [ReadDirectoryChangesW] buffer size. // // This only has effect on Windows systems, and is a no-op for other backends. // // The default value is 64K (65536 bytes) which is the highest value that works // on all filesystems and should be enough for most applications, but if you // have a large burst of events it may not be enough. You can increase it if // you're hitting "queue or buffer overflow" errors ([ErrEventOverflow]). // // [ReadDirectoryChangesW]: https://learn.microsoft.com/en-gb/windows/win32/api/winbase/nf-winbase-readdirectorychangesw func ( int) addOpt { return func( *withOpts) { .bufsize = } } // Check if this path is recursive (ends with "/..." or "\..."), and return the // path with the /... stripped. func recursivePath( string) (string, bool) { if filepath.Base() == "..." { return filepath.Dir(), true } return , false }