package fsnotify
import (
+ "errors"
"fmt"
- "os"
- "syscall"
"io/ioutil"
+ "os"
"path"
+ "syscall"
)
type FileEvent struct {
func (e *FileEvent) IsRename() bool { return (e.mask & NOTE_RENAME) == NOTE_RENAME }
type Watcher struct {
- kq int // File descriptor (as returned by the kqueue() syscall)
- watches map[string]int // Map of watched file diescriptors (key: path)
- paths map[int]string // Map of watched paths (key: watch descriptor)
- finfo map[int]*os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
- Error chan os.Error // Errors are sent on this channel
- Event chan *FileEvent // Events are returned on this channel
- done chan bool // Channel for sending a "quit message" to the reader goroutine
- isClosed bool // Set to true when Close() is first called
- kbuf [1]syscall.Kevent_t // An event buffer for Add/Remove watch
+ kq int // File descriptor (as returned by the kqueue() syscall)
+ watches map[string]int // Map of watched file diescriptors (key: path)
+ paths map[int]string // Map of watched paths (key: watch descriptor)
+ finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
+ Error chan error // Errors are sent on this channel
+ Event chan *FileEvent // Events are returned on this channel
+ done chan bool // Channel for sending a "quit message" to the reader goroutine
+ isClosed bool // Set to true when Close() is first called
+ kbuf [1]syscall.Kevent_t // An event buffer for Add/Remove watch
}
// NewWatcher creates and returns a new kevent instance using kqueue(2)
-func NewWatcher() (*Watcher, os.Error) {
+func NewWatcher() (*Watcher, error) {
fd, errno := syscall.Kqueue()
if fd == -1 {
return nil, os.NewSyscallError("kqueue", errno)
kq: fd,
watches: make(map[string]int),
paths: make(map[int]string),
- finfo: make(map[int]*os.FileInfo),
+ finfo: make(map[int]os.FileInfo),
Event: make(chan *FileEvent),
- Error: make(chan os.Error),
+ Error: make(chan error),
done: make(chan bool, 1),
}
// Close closes a kevent watcher instance
// It sends a message to the reader goroutine to quit and removes all watches
// associated with the kevent instance
-func (w *Watcher) Close() os.Error {
+func (w *Watcher) Close() error {
if w.isClosed {
return nil
}
// 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) os.Error {
+func (w *Watcher) addWatch(path string, flags uint32) error {
if w.isClosed {
- return os.NewError("kevent instance already closed")
+ return errors.New("kevent instance already closed")
}
watchEntry := &w.kbuf[0]
if !found {
fd, errno := syscall.Open(path, syscall.O_NONBLOCK|syscall.O_RDONLY, 0700)
if fd == -1 {
- return &os.PathError{"kevent_add_watch", path, os.Errno(errno)}
+ return errno
}
watchfd = fd
wd, errno := syscall.Kevent(w.kq, w.kbuf[:], nil, nil)
if wd == -1 {
- return &os.PathError{"kevent_add_watch", path, os.Errno(errno)}
+ return errno
} else if (watchEntry.Flags & syscall.EV_ERROR) == syscall.EV_ERROR {
- return &os.PathError{"kevent_add_watch", path, os.Errno(int(watchEntry.Data))}
+ return errors.New("kevent add error")
}
return nil
}
// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) Watch(path string) os.Error {
+func (w *Watcher) Watch(path string) error {
return w.addWatch(path, NOTE_ALLEVENTS)
}
// RemoveWatch removes path from the watched file set.
-func (w *Watcher) RemoveWatch(path string) os.Error {
+func (w *Watcher) RemoveWatch(path string) error {
watchfd, ok := w.watches[path]
if !ok {
- return os.NewError(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
+ return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
}
syscall.Close(watchfd)
watchEntry := &w.kbuf[0]
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", int(watchEntry.Data))
+ return errors.New("kevent rm error")
}
- w.watches[path] = 0, false
+ delete(w.watches, path)
return nil
}
events []syscall.Kevent_t // Received events
twait *syscall.Timespec // Time to block waiting for events
n int // Number of events returned from kevent
- errno int // Syscall errno
+ errno error // Syscall errno
)
events = eventbuf[0:0]
twait = new(syscall.Timespec)
// If "done" message is received
if done {
errno := syscall.Close(w.kq)
- if errno == -1 {
+ if errno != nil {
w.Error <- os.NewSyscallError("close", errno)
}
close(w.Event)
fileEvent.Name = w.paths[int(watchEvent.Ident)]
fileInfo := w.finfo[int(watchEvent.Ident)]
- if fileInfo.IsDirectory() && fileEvent.IsModify() {
+ if fileInfo.IsDir() && fileEvent.IsModify() {
w.sendDirectoryChangeEvents(fileEvent.Name)
} else {
// Send the event on the events channel
// Search for new files
for _, fileInfo := range files {
- if fileInfo.IsRegular() == true {
- filePath := path.Join(dirPath, fileInfo.Name)
+ if fileInfo.IsDir() == false {
+ filePath := path.Join(dirPath, fileInfo.Name())
if w.watches[filePath] == 0 {
// Watch file to mimic linux fsnotify
e := w.addWatch(filePath, NOTE_DELETE|NOTE_WRITE|NOTE_RENAME)
package fsnotify
import (
+ "errors"
"fmt"
"os"
"strings"
fd int // File descriptor (as returned by the inotify_init() syscall)
watches map[string]*watch // Map of inotify watches (key: path)
paths map[int]string // Map of watched paths (key: watch descriptor)
- Error chan os.Error // Errors are sent on this channel
+ Error chan error // Errors are sent on this channel
Event chan *FileEvent // Events are returned on this channel
done chan bool // Channel for sending a "quit message" to the reader goroutine
isClosed bool // Set to true when Close() is first called
}
// NewWatcher creates and returns a new inotify instance using inotify_init(2)
-func NewWatcher() (*Watcher, os.Error) {
+func NewWatcher() (*Watcher, error) {
fd, errno := syscall.InotifyInit()
if fd == -1 {
return nil, os.NewSyscallError("inotify_init", errno)
watches: make(map[string]*watch),
paths: make(map[int]string),
Event: make(chan *FileEvent),
- Error: make(chan os.Error),
+ Error: make(chan error),
done: make(chan bool, 1),
}
// Close closes an inotify watcher instance
// It sends a message to the reader goroutine to quit and removes all watches
// associated with the inotify instance
-func (w *Watcher) Close() os.Error {
+func (w *Watcher) Close() error {
if w.isClosed {
return nil
}
// AddWatch adds path to the watched file set.
// The flags are interpreted as described in inotify_add_watch(2).
-func (w *Watcher) addWatch(path string, flags uint32) os.Error {
+func (w *Watcher) addWatch(path string, flags uint32) error {
if w.isClosed {
- return os.NewError("inotify instance already closed")
+ return errors.New("inotify instance already closed")
}
watchEntry, found := w.watches[path]
}
// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) Watch(path string) os.Error {
+func (w *Watcher) Watch(path string) error {
return w.addWatch(path, OS_AGNOSTIC_EVENTS)
}
// RemoveWatch removes path from the watched file set.
-func (w *Watcher) RemoveWatch(path string) os.Error {
+func (w *Watcher) RemoveWatch(path string) error {
watch, ok := w.watches[path]
if !ok {
- return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
+ return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
}
success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
if success == -1 {
return os.NewSyscallError("inotify_rm_watch", errno)
}
- w.watches[path] = nil, false
+ delete(w.watches, path)
return nil
}
continue
}
if n < syscall.SizeofInotifyEvent {
- w.Error <- os.NewError("inotify: short read in readEvents()")
+ w.Error <- errors.New("inotify: short read in readEvents()")
continue
}