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.
19 "golang.org/x/sys/unix"
22 // Watcher watches a set of files, delivering events to a channel.
26 mu sync.Mutex // Map access
29 watches map[string]*watch // Map of inotify watches (key: path)
30 paths map[int]string // Map of watched paths (key: watch descriptor)
31 done chan struct{} // Channel for sending a "quit message" to the reader goroutine
32 doneResp chan struct{} // Channel to respond to Close
35 // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
36 func NewWatcher() (*Watcher, error) {
38 fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
43 poller, err := newFdPoller(fd)
51 watches: make(map[string]*watch),
52 paths: make(map[int]string),
53 Events: make(chan Event),
54 Errors: make(chan error),
55 done: make(chan struct{}),
56 doneResp: make(chan struct{}),
63 func (w *Watcher) isClosed() bool {
72 // Close removes all watches and closes the events channel.
73 func (w *Watcher) Close() error {
78 // Send 'close' signal to goroutine, and set the Watcher to closed.
84 // Wait for goroutine to close
90 // Add starts watching the named file or directory (non-recursively).
91 func (w *Watcher) Add(name string) error {
92 name = filepath.Clean(name)
94 return errors.New("inotify instance already closed")
97 const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
98 unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
99 unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
101 var flags uint32 = agnosticEvents
105 watchEntry := w.watches[name]
106 if watchEntry != nil {
107 flags |= watchEntry.flags | unix.IN_MASK_ADD
109 wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
114 if watchEntry == nil {
115 w.watches[name] = &watch{wd: uint32(wd), flags: flags}
118 watchEntry.wd = uint32(wd)
119 watchEntry.flags = flags
125 // Remove stops watching the named file or directory (non-recursively).
126 func (w *Watcher) Remove(name string) error {
127 name = filepath.Clean(name)
132 watch, ok := w.watches[name]
134 // Remove it from inotify.
136 return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
139 // We successfully removed the watch if InotifyRmWatch doesn't return an
140 // error, we need to clean up our internal state to ensure it matches
141 // inotify's kernel state.
142 delete(w.paths, int(watch.wd))
143 delete(w.watches, name)
145 // inotify_rm_watch will return EINVAL if the file has been deleted;
146 // the inotify will already have been removed.
147 // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
148 // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
149 // so that EINVAL means that the wd is being rm_watch()ed or its file removed
150 // by another thread and we have not received IN_IGNORE event.
151 success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
153 // TODO: Perhaps it's not helpful to return an error here in every case.
154 // the only two possible errors are:
155 // EBADF, which happens when w.fd is not a valid file descriptor of any kind.
156 // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
157 // Watch descriptors are invalidated when they are removed explicitly or implicitly;
158 // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
166 wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
167 flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
170 // readEvents reads from the inotify file descriptor, converts the
171 // received events into Event objects and sends them via the Events channel
172 func (w *Watcher) readEvents() {
174 buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
175 n int // Number of bytes read with read()
176 errno error // Syscall errno
177 ok bool // For poller.wait
180 defer close(w.doneResp)
181 defer close(w.Errors)
182 defer close(w.Events)
183 defer unix.Close(w.fd)
184 defer w.poller.close()
187 // See if we have been closed.
192 ok, errno = w.poller.wait()
195 case w.Errors <- errno:
206 n, errno = unix.Read(w.fd, buf[:])
207 // If a signal interrupted execution, see if we've been asked to close, and try again.
208 // http://man7.org/linux/man-pages/man7/signal.7.html :
209 // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
210 if errno == unix.EINTR {
214 // unix.Read might have been woken up by Close. If so, we're done.
219 if n < unix.SizeofInotifyEvent {
222 // If EOF is received. This should really never happen.
225 // If an error occurred while reading.
228 // Read was too short.
229 err = errors.New("notify: short read in readEvents()")
232 case w.Errors <- err:
240 // We don't know how many events we just read into the buffer
241 // While the offset points to at least one whole event...
242 for offset <= uint32(n-unix.SizeofInotifyEvent) {
243 // Point "raw" to the event in the buffer
244 raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
246 mask := uint32(raw.Mask)
247 nameLen := uint32(raw.Len)
249 if mask&unix.IN_Q_OVERFLOW != 0 {
251 case w.Errors <- ErrEventOverflow:
257 // If the event happened to the watched directory or the watched file, the kernel
258 // doesn't append the filename to the event, but we would like to always fill the
259 // the "Name" field with a valid filename. We retrieve the path of the watch from
262 name, ok := w.paths[int(raw.Wd)]
263 // IN_DELETE_SELF occurs when the file/directory being watched is removed.
264 // This is a sign to clean up the maps, otherwise we are no longer in sync
265 // with the inotify kernel state which has already deleted the watch
267 if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
268 delete(w.paths, int(raw.Wd))
269 delete(w.watches, name)
274 // Point "bytes" at the first byte of the filename
275 bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
276 // The filename is padded with NULL bytes. TrimRight() gets rid of those.
277 name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
280 event := newEvent(name, mask)
282 // Send the events that are not ignored on the events channel
283 if !event.ignoreLinux(mask) {
285 case w.Events <- event:
291 // Move to the next event in the buffer
292 offset += unix.SizeofInotifyEvent + nameLen
297 // Certain types of events can be "ignored" and not sent over the Events
298 // channel. Such as events marked ignore by the kernel, or MODIFY events
299 // against files that do not exist.
300 func (e *Event) ignoreLinux(mask uint32) bool {
301 // Ignore anything the inotify API says to ignore
302 if mask&unix.IN_IGNORED == unix.IN_IGNORED {
306 // If the event is not a DELETE or RENAME, the file must exist.
307 // Otherwise the event is ignored.
308 // *Note*: this was put in place because it was seen that a MODIFY
309 // event was sent after the DELETE. This ignores that MODIFY and
310 // assumes a DELETE will come or has come if the file doesn't exist.
311 if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
312 _, statErr := os.Lstat(e.Name)
313 return os.IsNotExist(statErr)
318 // newEvent returns an platform-independent Event based on an inotify mask.
319 func newEvent(name string, mask uint32) Event {
320 e := Event{Name: name}
321 if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
324 if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
327 if mask&unix.IN_MODIFY == unix.IN_MODIFY {
330 if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
333 if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {