1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
6 Package inotify implements a wrapper for the Linux inotify system.
9 watcher, err := inotify.NewWatcher()
13 err = watcher.Watch("/tmp")
19 case ev := <-watcher.Event:
20 log.Println("event:", ev)
21 case err := <-watcher.Error:
22 log.Println("error:", err)
38 Mask uint32 // Mask of events
39 Cookie uint32 // Unique cookie associating related events (for rename(2))
40 Name string // File name (optional)
44 wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
45 flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
49 fd int // File descriptor (as returned by the inotify_init() syscall)
50 watches map[string]*watch // Map of inotify watches (key: path)
51 paths map[int]string // Map of watched paths (key: watch descriptor)
52 Error chan os.Error // Errors are sent on this channel
53 Event chan *Event // Events are returned on this channel
54 done chan bool // Channel for sending a "quit message" to the reader goroutine
55 isClosed bool // Set to true when Close() is first called
58 // NewWatcher creates and returns a new inotify instance using inotify_init(2)
59 func NewWatcher() (*Watcher, os.Error) {
60 fd, errno := syscall.InotifyInit()
62 return nil, os.NewSyscallError("inotify_init", errno)
66 watches: make(map[string]*watch),
67 paths: make(map[int]string),
68 Event: make(chan *Event),
69 Error: make(chan os.Error),
70 done: make(chan bool, 1),
77 // Close closes an inotify watcher instance
78 // It sends a message to the reader goroutine to quit and removes all watches
79 // associated with the inotify instance
80 func (w *Watcher) Close() os.Error {
86 // Send "quit" message to the reader goroutine
88 for path := range w.watches {
95 // AddWatch adds path to the watched file set.
96 // The flags are interpreted as described in inotify_add_watch(2).
97 func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
99 return os.NewError("inotify instance already closed")
102 watchEntry, found := w.watches[path]
104 watchEntry.flags |= flags
105 flags |= syscall.IN_MASK_ADD
107 wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
109 return &os.PathError{"inotify_add_watch", path, os.Errno(errno)}
113 w.watches[path] = &watch{wd: uint32(wd), flags: flags}
119 // Watch adds path to the watched file set, watching all events.
120 func (w *Watcher) Watch(path string) os.Error {
121 return w.AddWatch(path, IN_ALL_EVENTS)
124 // RemoveWatch removes path from the watched file set.
125 func (w *Watcher) RemoveWatch(path string) os.Error {
126 watch, ok := w.watches[path]
128 return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
130 success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
132 return os.NewSyscallError("inotify_rm_watch", errno)
134 w.watches[path] = nil, false
138 // readEvents reads from the inotify file descriptor, converts the
139 // received events into Event objects and sends them via the Event channel
140 func (w *Watcher) readEvents() {
142 buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
143 n int // Number of bytes read with read()
144 errno int // Syscall errno
148 n, errno = syscall.Read(w.fd, buf[0:])
149 // See if there is a message on the "done" channel
152 case done = <-w.done:
156 // If EOF or a "done" message is received
158 errno := syscall.Close(w.fd)
160 w.Error <- os.NewSyscallError("close", errno)
167 w.Error <- os.NewSyscallError("read", errno)
170 if n < syscall.SizeofInotifyEvent {
171 w.Error <- os.NewError("inotify: short read in readEvents()")
175 var offset uint32 = 0
176 // We don't know how many events we just read into the buffer
177 // While the offset points to at least one whole event...
178 for offset <= uint32(n-syscall.SizeofInotifyEvent) {
179 // Point "raw" to the event in the buffer
180 raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
182 event.Mask = uint32(raw.Mask)
183 event.Cookie = uint32(raw.Cookie)
184 nameLen := uint32(raw.Len)
185 // If the event happened to the watched directory or the watched file, the kernel
186 // doesn't append the filename to the event, but we would like to always fill the
187 // the "Name" field with a valid filename. We retrieve the path of the watch from
189 event.Name = w.paths[int(raw.Wd)]
191 // Point "bytes" at the first byte of the filename
192 bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
193 // The filename is padded with NUL bytes. TrimRight() gets rid of those.
194 event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
196 // Send the event on the events channel
199 // Move to the next event in the buffer
200 offset += syscall.SizeofInotifyEvent + nameLen
205 // String formats the event e in the form
206 // "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
207 func (e *Event) String() string {
208 var events string = ""
211 for _, b := range eventBits {
214 events += "|" + b.Name
219 events += fmt.Sprintf("|%#x", m)
222 events = " == " + events[1:]
225 return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
229 // Options for inotify_init() are not exported
230 // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
231 // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
233 // Options for AddWatch
234 IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
235 IN_ONESHOT uint32 = syscall.IN_ONESHOT
236 IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
238 // The "IN_MASK_ADD" option is not exported, as AddWatch
239 // adds it automatically, if there is already a watch for the given path
240 // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
243 IN_ACCESS uint32 = syscall.IN_ACCESS
244 IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
245 IN_ATTRIB uint32 = syscall.IN_ATTRIB
246 IN_CLOSE uint32 = syscall.IN_CLOSE
247 IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
248 IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
249 IN_CREATE uint32 = syscall.IN_CREATE
250 IN_DELETE uint32 = syscall.IN_DELETE
251 IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
252 IN_MODIFY uint32 = syscall.IN_MODIFY
253 IN_MOVE uint32 = syscall.IN_MOVE
254 IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
255 IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
256 IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
257 IN_OPEN uint32 = syscall.IN_OPEN
260 IN_ISDIR uint32 = syscall.IN_ISDIR
261 IN_IGNORED uint32 = syscall.IN_IGNORED
262 IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
263 IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
266 var eventBits = []struct {
270 {IN_ACCESS, "IN_ACCESS"},
271 {IN_ATTRIB, "IN_ATTRIB"},
272 {IN_CLOSE, "IN_CLOSE"},
273 {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
274 {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
275 {IN_CREATE, "IN_CREATE"},
276 {IN_DELETE, "IN_DELETE"},
277 {IN_DELETE_SELF, "IN_DELETE_SELF"},
278 {IN_MODIFY, "IN_MODIFY"},
279 {IN_MOVE, "IN_MOVE"},
280 {IN_MOVED_FROM, "IN_MOVED_FROM"},
281 {IN_MOVED_TO, "IN_MOVED_TO"},
282 {IN_MOVE_SELF, "IN_MOVE_SELF"},
283 {IN_OPEN, "IN_OPEN"},
284 {IN_ISDIR, "IN_ISDIR"},
285 {IN_IGNORED, "IN_IGNORED"},
286 {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
287 {IN_UNMOUNT, "IN_UNMOUNT"},