package watcher import ( "syscall" "unsafe" "github.com/pkg/errors" ) const CrDelMask uint32 = syscall.IN_CREATE | syscall.IN_DELETE const inotifyCount = 16 type FSWatcher struct { fd int wds []int closed bool } func NewFSWatcher() (fsw *FSWatcher, err error) { fsw = &FSWatcher{closed: false} fsw.fd, err = syscall.InotifyInit() if err != nil { return nil, errors.Wrap(err, "failed to initialise inotify watcher") } fsw.wds = make([]int, 0) return fsw, nil } func (fsw *FSWatcher) AddWatch(path string, mask uint32) error { wd, err := syscall.InotifyAddWatch(fsw.fd, path, mask) if err != nil { return errors.Wrapf(err, "failed to set %s on watch", path) } fsw.wds = append(fsw.wds, wd) return nil } // WatchForMask checking for events from mask and returns inotify mask to channel. func (fsw *FSWatcher) WatchForMask(fired chan uint32, mask uint32) { go func() { for !fsw.closed { buffer := make([]byte, syscall.SizeofInotifyEvent*inotifyCount) n, err := syscall.Read(fsw.fd, buffer) if err != nil { break } if n < syscall.SizeofInotifyEvent { continue } for offset := 0; offset < len(buffer); offset += syscall.SizeofInotifyEvent { event := (*syscall.InotifyEvent)(unsafe.Pointer(&buffer[offset])) if event.Mask&mask > 0 { fired <- event.Mask } } } }() } func (fsw *FSWatcher) Close() error { for _, wd := range fsw.wds { if _, err := syscall.InotifyRmWatch(fsw.fd, uint32(wd)); err != nil { return err } } if err := syscall.Close(fsw.fd); err != nil { return err } fsw.closed = true return nil }