コード例 #1
0
ファイル: fsevents_darwin.go プロジェクト: darvik80/monitor
func (this *watcher) doDel(path string) error {
	info, found := this.watchedByPath[path]
	if !found {
		return errors.Newf("can't remove non-existent kevent watch for: %s", path)
	}

	var kbuf [1]syscall.Kevent_t
	watchEntry := &kbuf[0]
	syscall.SetKevent(watchEntry, info.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	entryFlags := watchEntry.Flags
	success, errno := syscall.Kevent(this.kq, kbuf[:], nil, nil)
	if success == sysCallFailed {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if entryFlags&syscall.EV_ERROR == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(info.fd)

	//Remove childs if it's directory
	for _, child := range info.childes {
		this.doDel(child)
	}

	delete(this.watchedByPath, path)
	delete(this.watchedByFD, info.fd)

	return nil
}
コード例 #2
0
ファイル: watcher_kqueue.go プロジェクト: kaocs/notify
// unwatch stops watching p file/directory.
func (k *kqueue) singleunwatch(p string, direct bool) error {
	w := k.pthLkp[p]
	if w == nil {
		return errNotWatched
	}
	if direct {
		w.eDir = 0
	} else {
		w.eNonDir = 0
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	if _, err := syscall.Kevent(k.fd, kevn[:], nil, nil); err != nil {
		return err
	}
	if w.eNonDir&w.eDir != 0 {
		if err := k.singlewatch(p, w.eNonDir|w.eDir, w.eNonDir == 0,
			w.fi); err != nil {
			return err
		}
	} else {
		k.del(*w)
	}
	return nil
}
コード例 #3
0
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
	if w.isClosed {
		return errors.New("kevent instance already closed")
	}

	watchEntry := &w.kbuf[0]
	watchEntry.Fflags = flags

	watchfd, found := w.watches[path]
	if !found {
		fd, errno := syscall.Open(path, syscall.O_NONBLOCK|syscall.O_RDONLY, 0700)
		if fd == -1 {
			return &os.PathError{"kevent_add_watch", path, errno}
		}
		watchfd = fd

		w.watches[path] = watchfd
		w.paths[watchfd] = path

		fi, _ := os.Stat(path)
		w.finfo[watchfd] = &fi
	}
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)

	wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if wd == -1 {
		return &os.PathError{"kevent_add_watch", path, errno}
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return &os.PathError{"kevent_add_watch", path, errors.New(fmt.Sprintf("%v", watchEntry.Data))}
	}

	return nil
}
コード例 #4
0
ファイル: watcher_kqueue.go プロジェクト: Codzart/go-ethereum
// Unwatch implements trigger.
func (k *kq) Unwatch(w *watched) (err error) {
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE, syscall.EV_DELETE)

	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
コード例 #5
0
// RemoveWatch removes path from the watched file set.
func (w *Watcher) removeWatch(path string) error {
	w.wmut.Lock()
	watchfd, ok := w.watches[path]
	w.wmut.Unlock()
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	w.bufmut.Lock()
	defer w.bufmut.Unlock()
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, path)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, path)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	delete(w.finfo, watchfd)
	w.pmut.Unlock()
	return nil
}
コード例 #6
0
ファイル: fd_bsd.go プロジェクト: pkdevboxy/appscale
// First return value is whether the pollServer should be woken up.
// This version always returns false.
func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
	if err != nil {
		return false, os.NewSyscallError("kevent", err)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return false, os.NewSyscallError("kqueue phase error", err)
	}
	if ev.Data != 0 {
		return false, syscall.Errno(int(ev.Data))
	}
	return false, nil
}
コード例 #7
0
ファイル: watcher_kqueue.go プロジェクト: kaocs/notify
// watch starts to watch given p file/directory.
func (k *kqueue) singlewatch(p string, e Event, direct bool,
	fi os.FileInfo) error {
	w, ok := k.pthLkp[p]
	if !ok {
		fd, err := syscall.Open(p, syscall.O_NONBLOCK|syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}
		w = &watched{fd: fd, p: p, fi: fi}
	}
	if direct {
		w.eDir |= e
	} else {
		w.eNonDir |= e
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE,
		syscall.EV_ADD|syscall.EV_CLEAR)
	kevn[0].Fflags = encode(w.eDir | w.eNonDir)
	if _, err := syscall.Kevent(k.fd, kevn[:], nil, nil); err != nil {
		return err
	}
	if !ok {
		k.idLkp[w.fd], k.pthLkp[w.p] = w, w
		return nil
	}
	return errAlreadyWatched
}
コード例 #8
0
ファイル: fd_darwin.go プロジェクト: 8l/go-learn
func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD | syscall.EV_RECEIPT
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, &events, &events, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.ErrorString("kqueue phase error")
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}
コード例 #9
0
ファイル: watcher_kqueue.go プロジェクト: Codzart/go-ethereum
// Watch implements trigger.
func (k *kq) Watch(fi os.FileInfo, w *watched, e int64) (err error) {
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], w.fd, syscall.EVFILT_VNODE,
		syscall.EV_ADD|syscall.EV_CLEAR)
	kevn[0].Fflags = uint32(e)

	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
コード例 #10
0
ファイル: kqueue.go プロジェクト: balagopalraj/clearlinux
// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
	name = filepath.Clean(name)
	w.wmut.Lock()
	watchfd, ok := w.watches[name]
	w.wmut.Unlock()
	if !ok {
		return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
	}
	var kbuf [1]syscall.Kevent_t
	watchEntry := &kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	entryFlags := watchEntry.Flags
	success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, name)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, name)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	fInfo := w.finfo[watchfd]
	delete(w.finfo, watchfd)
	w.pmut.Unlock()

	// Find all watched paths that are in this directory that are not external.
	if fInfo.IsDir() {
		var pathsToRemove []string
		w.pmut.Lock()
		for _, wpath := range w.paths {
			wdir, _ := filepath.Split(wpath)
			if filepath.Clean(wdir) == filepath.Clean(name) {
				w.ewmut.Lock()
				if !w.externalWatches[wpath] {
					pathsToRemove = append(pathsToRemove, wpath)
				}
				w.ewmut.Unlock()
			}
		}
		w.pmut.Unlock()
		for _, name := range pathsToRemove {
			// Since these are internal, not much sense in propagating error
			// to the user, as that will just confuse them with an error about
			// a path they did not explicitly watch themselves.
			w.Remove(name)
		}
	}

	return nil
}
コード例 #11
0
ファイル: fsnotify_bsd.go プロジェクト: JamesDunne/go-util
// RemoveWatch removes path from the watched file set.
func (w *Watcher) removeWatch(path string) error {
	w.wmut.Lock()
	watchfd, ok := w.watches[path]
	w.wmut.Unlock()
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	w.bufmut.Lock()
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	w.bufmut.Unlock()
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent rm error")
	}
	syscall.Close(watchfd)
	w.wmut.Lock()
	delete(w.watches, path)
	w.wmut.Unlock()
	w.enmut.Lock()
	delete(w.enFlags, path)
	w.enmut.Unlock()
	w.pmut.Lock()
	delete(w.paths, watchfd)
	fInfo := w.finfo[watchfd]
	delete(w.finfo, watchfd)
	w.pmut.Unlock()

	// Find all watched paths that are in this directory that are not external.
	if fInfo.IsDir() {
		pathsToRemove := make([]string, 0)
		w.pmut.Lock()
		for _, wpath := range w.paths {
			wdir, _ := filepath.Split(wpath)
			if filepath.Clean(wdir) == filepath.Clean(path) {
				w.ewmut.Lock()
				if _, extern := w.externalWatches[wpath]; !extern {
					pathsToRemove = append(pathsToRemove, wpath)
				}
				w.ewmut.Unlock()
			}
		}
		w.pmut.Unlock()
		for idx := 0; idx < len(pathsToRemove); idx++ {
			// Since these are internal, not much sense in propogating error
			// to the user, as that will just confuse them with an error about
			// a path they did not explicitly watch themselves.
			w.removeWatch(pathsToRemove[idx])
		}
	}

	return nil
}
コード例 #12
0
ファイル: psnotify_bsd.go プロジェクト: ChongFeng/beats
// Initialize Kevent_t fields and propagate changelist for the given pid
func (w *Watcher) kevent(pid int, fflags uint32, flags int) error {
	listener, _ := w.listener.(*kqueueListener)
	event := &listener.buf[0]

	syscall.SetKevent(event, pid, syscall.EVFILT_PROC, flags)
	event.Fflags = fflags

	_, err := syscall.Kevent(listener.kq, listener.buf[:], nil, nil)

	return err
}
コード例 #13
0
ファイル: fd_freebsd.go プロジェクト: rapgamer/golang-china
func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, &events, nil, nil)
}
コード例 #14
0
ファイル: watcher_kqueue.go プロジェクト: kaocs/notify
// init initializes kqueue.
func (k *kqueue) init() (err error) {
	if k.fd, err = syscall.Kqueue(); err != nil {
		return
	}
	// Creates pipe used to stop `Kevent` call by registering it,
	// watching read end and writing to other end of it.
	if err = syscall.Pipe(k.pipefds[:]); err != nil {
		return
	}
	var kevn [1]syscall.Kevent_t
	syscall.SetKevent(&kevn[0], k.pipefds[0], syscall.EVFILT_READ, syscall.EV_ADD)
	_, err = syscall.Kevent(k.fd, kevn[:], nil, nil)
	return
}
コード例 #15
0
ファイル: fd_openbsd.go プロジェクト: aubonbeurre/gcc
func (p *pollster) DelFD(fd int, mode int) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
}
コード例 #16
0
ファイル: fd_darwin.go プロジェクト: 8l/go-learn
func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
	syscall.Kevent(p.kq, &events, &events, nil)
}
コード例 #17
0
ファイル: fd_darwin.go プロジェクト: carriercomm/redis-3
func (p *pollster) DelFD(fd int, mode int) {
	// pollServer is locked.

	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	ev := &p.kbuf[0]
	// EV_DELETE - delete event from kqueue list
	// EV_RECEIPT - generate fake EV_ERROR as result of add,
	//	rather than waiting for real event
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
	syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
}
コード例 #18
0
ファイル: kqueue.go プロジェクト: noonat/runit
// register events with the queue
func register(kq int, fds []int, flags int, fflags uint32) error {
	changes := make([]syscall.Kevent_t, len(fds))

	for i, fd := range fds {
		// SetKevent converts int to the platform-specific types:
		syscall.SetKevent(&changes[i], fd, syscall.EVFILT_VNODE, flags)
		changes[i].Fflags = fflags
	}

	// register the events
	success, err := syscall.Kevent(kq, changes, nil, nil)
	if success == -1 {
		return err
	}
	return nil
}
コード例 #19
0
// RemoveWatch removes path from the watched file set.
func (w *Watcher) RemoveWatch(path string) error {
	watchfd, ok := w.watches[path]
	if !ok {
		return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
	}
	syscall.Close(watchfd)
	watchEntry := &w.kbuf[0]
	syscall.SetKevent(watchEntry, w.watches[path], syscall.EVFILT_VNODE, syscall.EV_DELETE)
	success, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if success == -1 {
		return os.NewSyscallError("kevent_rm_watch", errno)
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return os.NewSyscallError("kevent_rm_watch", errors.New(fmt.Sprintf("%v", watchEntry.Data)))
	}
	delete(w.watches, path)
	return nil
}
コード例 #20
0
ファイル: fsnotify_bsd.go プロジェクト: seacoastboy/fsnotify
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
	if w.isClosed {
		return errors.New("kevent instance already closed")
	}

	watchEntry := &w.kbuf[0]
	watchEntry.Fflags = flags

	watchfd, found := w.watches[path]
	if !found {
		fd, errno := syscall.Open(path, syscall.O_NONBLOCK|syscall.O_RDONLY, 0700)
		if fd == -1 {
			return errno
		}
		watchfd = fd

		w.watches[path] = watchfd
		w.paths[watchfd] = path

		fi, _ := os.Stat(path)
		w.finfo[watchfd] = fi
		if fi.IsDir() {
			w.watchDirectoryFiles(path)
		}
	}
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)

	wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if wd == -1 {
		return errno
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent add error")
	}

	return nil
}
コード例 #21
0
ファイル: fsnotify_bsd.go プロジェクト: polaris1119/GoSublime
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
	if w.isClosed {
		return errors.New("kevent instance already closed")
	}

	watchEntry := &w.kbuf[0]
	watchEntry.Fflags = flags
	watchDir := false

	watchfd, found := w.watches[path]
	if !found {
		fi, errstat := os.Lstat(path)
		if errstat != nil {
			return errstat
		}

		// Follow Symlinks
		// Unfortunately, Linux can add bogus symlinks to watch list without
		// issue, and Windows can't do symlinks period (AFAIK). To  maintain
		// consistency, we will act like everything is fine. There will simply
		// be no file events for broken symlinks.
		// Hence the returns of nil on errors.
		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
			path, err := filepath.EvalSymlinks(path)
			if err != nil {
				return nil
			}

			fi, errstat = os.Lstat(path)
			if errstat != nil {
				return nil
			}
		}

		fd, errno := syscall.Open(path, syscall.O_NONBLOCK|syscall.O_RDONLY, 0700)
		if fd == -1 {
			return errno
		}
		watchfd = fd

		w.watches[path] = watchfd
		w.paths[watchfd] = path

		w.finfo[watchfd] = fi
	}

	if w.finfo[watchfd].IsDir() && (flags&NOTE_WRITE) == NOTE_WRITE {
		watchDir = true
	}

	w.enFlags[path] = watchEntry.Fflags
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)

	wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if wd == -1 {
		return errno
	} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent add error")
	}

	if watchDir {
		errdir := w.watchDirectoryFiles(path)
		if errdir != nil {
			return errdir
		}
	}
	return nil
}
コード例 #22
0
ファイル: fsevents_darwin.go プロジェクト: darvik80/monitor
func (this *watcher) doAdd(path string, flags uint32) error {
	//Check that file exists
	fileInfo, err := os.Lstat(path)
	if err != nil {
		return err
	}

	mode := fileInfo.Mode()

	// don't watch socket
	if mode&os.ModeSocket == os.ModeSocket {
		return nil
	}

	if mode&os.ModeSymlink == os.ModeSymlink {
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return err
		}
		if fileInfo, err = os.Lstat(path); err != nil {
			return err
		}
	}

	fd, err := syscall.Open(path, open_FLAGS, 0700)
	if fd == sysCallFailed {
		return err
	}

	info := &watchInfo{
		fd:       fd,
		flags:    flags,
		realPath: path,
		fInto:    fileInfo,
	}
	this.watchedByFD[fd] = info
	this.watchedByPath[path] = info

	var kbuf [1]syscall.Kevent_t
	watchEntry := &kbuf[0]
	watchEntry.Fflags = flags
	syscall.SetKevent(watchEntry, info.fd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)
	entryFlags := watchEntry.Flags
	if success, err := syscall.Kevent(this.kq, kbuf[:], nil, nil); success == -1 {
		return err
	} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent add error")
	}

	if (true == info.fInto.IsDir()) && (info.flags&Note_WRITE == Note_WRITE) {
		if infos, err := ioutil.ReadDir(path); err != nil {
			return err
		} else {
			for _, fileInfo := range infos {
				childPath := filepath.Join(path, fileInfo.Name())
				if err := this.doAdd(childPath, flags); err != nil {
					return err
				}
				info.childes = append(info.childes, childPath)
			}
		}
	}

	return nil
}
コード例 #23
0
ファイル: fsnotify_bsd.go プロジェクト: dylanpoe/golang.org
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in kevent(2).
func (w *Watcher) addWatch(path string, flags uint32) error {
	w.mu.Lock()
	if w.isClosed {
		w.mu.Unlock()
		return errors.New("kevent instance already closed")
	}
	w.mu.Unlock()

	watchDir := false

	w.wmut.Lock()
	watchfd, found := w.watches[path]
	w.wmut.Unlock()
	if !found {
		fi, errstat := os.Lstat(path)
		if errstat != nil {
			return errstat
		}

		// don't watch socket
		if fi.Mode()&os.ModeSocket == os.ModeSocket {
			return nil
		}

		// Follow Symlinks
		// Unfortunately, Linux can add bogus symlinks to watch list without
		// issue, and Windows can't do symlinks period (AFAIK). To  maintain
		// consistency, we will act like everything is fine. There will simply
		// be no file events for broken symlinks.
		// Hence the returns of nil on errors.
		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
			path, err := filepath.EvalSymlinks(path)
			if err != nil {
				return nil
			}

			fi, errstat = os.Lstat(path)
			if errstat != nil {
				return nil
			}
		}

		fd, errno := syscall.Open(path, open_FLAGS, 0700)
		if fd == -1 {
			return errno
		}
		watchfd = fd

		w.wmut.Lock()
		w.watches[path] = watchfd
		w.wmut.Unlock()

		w.pmut.Lock()
		w.paths[watchfd] = path
		w.finfo[watchfd] = fi
		w.pmut.Unlock()
	}
	// Watch the directory if it has not been watched before.
	w.pmut.Lock()
	w.enmut.Lock()
	if w.finfo[watchfd].IsDir() &&
		(flags&sys_NOTE_WRITE) == sys_NOTE_WRITE &&
		(!found || (w.enFlags[path]&sys_NOTE_WRITE) != sys_NOTE_WRITE) {
		watchDir = true
	}
	w.enmut.Unlock()
	w.pmut.Unlock()

	w.enmut.Lock()
	w.enFlags[path] = flags
	w.enmut.Unlock()

	w.bufmut.Lock()
	watchEntry := &w.kbuf[0]
	watchEntry.Fflags = flags
	syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)
	entryFlags := watchEntry.Flags
	w.bufmut.Unlock()

	wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
	if wd == -1 {
		return errno
	} else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
		return errors.New("kevent add error")
	}

	if watchDir {
		errdir := w.watchDirectoryFiles(path)
		if errdir != nil {
			return errdir
		}
	}
	return nil
}