func (e *FsEvent) IsFileChanged() bool {
	return !e.IsDirEvent() &&
		(CheckMask(CloseWrite, e.RawEvent.Mask) ||
			CheckMask(Modified, e.RawEvent.Mask) ||
			CheckMask(AttrChange, e.RawEvent.Mask))
}
IsFileChanged returns true if the event describes a file that was
closed with write permissions, modified, or its attributes changed
package fsevents
import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"sync/atomic"
	"time"
	"unsafe"
	"golang.org/x/sys/unix"
)
type WatchDescriptor struct {
	Path string
	Mask uint32
	WatchDescriptor int
	Running bool
	InotifyDescriptor *int
}
type FsEvent struct {
	Name string
	Path string
	RawEvent *unix.InotifyEvent
	Descriptor *WatchDescriptor
	ID uint32
	Timestamp time.Time
}
type EventHandler interface {
	Handle(w *Watcher, event *FsEvent) error
	Check(event *FsEvent) bool
	GetMask() uint32
}
type Watcher struct {
	sync.Mutex
	eventHandlers []EventHandler
	eventBuffer [unix.SizeofInotifyEvent + unix.PathMax + 1]byte
	eventBufferLen int
	eventBufferOff int
	InotifyDescriptor int
	Descriptors map[string]*WatchDescriptor
	EventCount uint32
	Events chan *FsEvent
	Errors chan error
}
var (
	ErrWatchNotCreated      = errors.New("watcher could not be created")
	ErrNoRunningDescriptors = errors.New("watcher has no running descriptors")
	ErrNoEventHandles       = errors.New("watcher has no registered event handles")
	ErrDescNotCreated       = errors.New("descriptor could not be created")
	ErrDescNotStart         = errors.New("descriptor could not be started")
	ErrDescRunning          = errors.New("descriptor already running")
	ErrDescNotStopped       = errors.New("descriptor could not be stopped")
	ErrDescAlreadyExists    = errors.New("descriptor for that directory already exists")
	ErrDescNotRunning       = errors.New("descriptor not running")
	ErrDescForEventNotFound = errors.New("descriptor for event not found")
	ErrDescNotFound         = errors.New("descriptor not found")
	ErrNoSuchHandle = errors.New("handle not found")
	ErrHandleError  = errors.New("handle returned error")
	ErrHandleExists = errors.New("a handle for this mask already exists")
	ErrIncompleteRead = errors.New("incomplete event read")
	ErrReadError      = errors.New("error reading an event")
)
var (
	Accessed   uint32 = unix.IN_ACCESS
	Modified   uint32 = unix.IN_MODIFY
	AttrChange uint32 = unix.IN_ATTRIB
	CloseWrite uint32 = unix.IN_CLOSE_WRITE
	CloseRead  uint32 = unix.IN_CLOSE_NOWRITE
	Open       uint32 = unix.IN_OPEN
	MovedFrom  uint32 = unix.IN_MOVED_FROM
	MovedTo    uint32 = unix.IN_MOVED_TO
	Move       uint32 = unix.IN_MOVE
	Create     uint32 = unix.IN_CREATE
	Delete     uint32 = unix.IN_DELETE
	RootDelete uint32 = unix.IN_DELETE_SELF
	RootMove   uint32 = unix.IN_MOVE_SELF
	IsDir      uint32 = unix.IN_ISDIR
	AllEvents = (Accessed | Modified | AttrChange | CloseWrite | CloseRead | Open | MovedFrom |
		MovedTo | MovedTo | Create | Delete | RootDelete | RootMove | IsDir)
	DirRemovedEvent = MovedFrom | Delete | IsDir
	DirCreatedEvent = MovedTo | Create | IsDir
	DirChangedEvent = CloseWrite | Modified | AttrChange | IsDir
	FileRemovedEvent = MovedFrom | Delete
	FileCreatedEvent = MovedTo | Create
	FileChangedEvent = CloseWrite | Modified | AttrChange
	RootEvent = RootDelete | RootMove
)
func CheckMask(check uint32, mask uint32) bool {
	return (mask & check) != 0
}
func (e *FsEvent) IsDirEvent() bool {
	return CheckMask(IsDir, e.RawEvent.Mask)
}
func (e *FsEvent) IsRootDeletion(rootPath string) bool {
	return CheckMask(RootDelete, e.RawEvent.Mask) && (rootPath == e.Path)
}
func (e *FsEvent) IsRootMoved(rootPath string) bool {
	return CheckMask(RootMove, e.RawEvent.Mask) && (rootPath == e.Path)
}
func (e *FsEvent) IsDirChanged() bool {
	return e.IsDirEvent() &&
		(CheckMask(CloseWrite, e.RawEvent.Mask) ||
			CheckMask(Modified, e.RawEvent.Mask) ||
			CheckMask(AttrChange, e.RawEvent.Mask))
}
func (e *FsEvent) IsDirCreated() bool {
	return e.IsDirEvent() &&
		(CheckMask(Create, e.RawEvent.Mask) ||
			CheckMask(MovedTo, e.RawEvent.Mask))
}
func (e *FsEvent) IsDirRemoved() bool {
	return e.IsDirEvent() &&
		(CheckMask(Delete, e.RawEvent.Mask) ||
			CheckMask(MovedFrom, e.RawEvent.Mask))
}
func (e *FsEvent) IsFileCreated() bool {
	return !e.IsDirEvent() &&
		(CheckMask(Create, e.RawEvent.Mask) ||
			CheckMask(MovedTo, e.RawEvent.Mask))
}
func (e *FsEvent) IsFileRemoved() bool {
	return !e.IsDirEvent() &&
		(CheckMask(Delete, e.RawEvent.Mask) ||
			CheckMask(MovedFrom, e.RawEvent.Mask))
}