Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / fsnotify / fsnotify / inotify.go
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.
4
5 // +build linux
6
7 package fsnotify
8
9 import (
10         "errors"
11         "fmt"
12         "io"
13         "os"
14         "path/filepath"
15         "strings"
16         "sync"
17         "syscall"
18         "unsafe"
19 )
20
21 // Watcher watches a set of files, delivering events to a channel.
22 type Watcher struct {
23         Events   chan Event
24         Errors   chan error
25         mu       sync.Mutex // Map access
26         cv       *sync.Cond // sync removing on rm_watch with IN_IGNORE
27         fd       int
28         poller   *fdPoller
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
33 }
34
35 // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
36 func NewWatcher() (*Watcher, error) {
37         // Create inotify fd
38         fd, errno := syscall.InotifyInit()
39         if fd == -1 {
40                 return nil, errno
41         }
42         // Create epoll
43         poller, err := newFdPoller(fd)
44         if err != nil {
45                 syscall.Close(fd)
46                 return nil, err
47         }
48         w := &Watcher{
49                 fd:       fd,
50                 poller:   poller,
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{}),
57         }
58         w.cv = sync.NewCond(&w.mu)
59
60         go w.readEvents()
61         return w, nil
62 }
63
64 func (w *Watcher) isClosed() bool {
65         select {
66         case <-w.done:
67                 return true
68         default:
69                 return false
70         }
71 }
72
73 // Close removes all watches and closes the events channel.
74 func (w *Watcher) Close() error {
75         if w.isClosed() {
76                 return nil
77         }
78
79         // Send 'close' signal to goroutine, and set the Watcher to closed.
80         close(w.done)
81
82         // Wake up goroutine
83         w.poller.wake()
84
85         // Wait for goroutine to close
86         <-w.doneResp
87
88         return nil
89 }
90
91 // Add starts watching the named file or directory (non-recursively).
92 func (w *Watcher) Add(name string) error {
93         name = filepath.Clean(name)
94         if w.isClosed() {
95                 return errors.New("inotify instance already closed")
96         }
97
98         const agnosticEvents = syscall.IN_MOVED_TO | syscall.IN_MOVED_FROM |
99                 syscall.IN_CREATE | syscall.IN_ATTRIB | syscall.IN_MODIFY |
100                 syscall.IN_MOVE_SELF | syscall.IN_DELETE | syscall.IN_DELETE_SELF
101
102         var flags uint32 = agnosticEvents
103
104         w.mu.Lock()
105         watchEntry, found := w.watches[name]
106         w.mu.Unlock()
107         if found {
108                 watchEntry.flags |= flags
109                 flags |= syscall.IN_MASK_ADD
110         }
111         wd, errno := syscall.InotifyAddWatch(w.fd, name, flags)
112         if wd == -1 {
113                 return errno
114         }
115
116         w.mu.Lock()
117         w.watches[name] = &watch{wd: uint32(wd), flags: flags}
118         w.paths[wd] = name
119         w.mu.Unlock()
120
121         return nil
122 }
123
124 // Remove stops watching the named file or directory (non-recursively).
125 func (w *Watcher) Remove(name string) error {
126         name = filepath.Clean(name)
127
128         // Fetch the watch.
129         w.mu.Lock()
130         defer w.mu.Unlock()
131         watch, ok := w.watches[name]
132
133         // Remove it from inotify.
134         if !ok {
135                 return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
136         }
137         // inotify_rm_watch will return EINVAL if the file has been deleted;
138         // the inotify will already have been removed.
139         // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
140         // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
141         // so that EINVAL means that the wd is being rm_watch()ed or its file removed
142         // by another thread and we have not received IN_IGNORE event.
143         success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
144         if success == -1 {
145                 // TODO: Perhaps it's not helpful to return an error here in every case.
146                 // the only two possible errors are:
147                 // EBADF, which happens when w.fd is not a valid file descriptor of any kind.
148                 // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
149                 // Watch descriptors are invalidated when they are removed explicitly or implicitly;
150                 // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
151                 return errno
152         }
153
154         // wait until ignoreLinux() deleting maps
155         exists := true
156         for exists {
157                 w.cv.Wait()
158                 _, exists = w.watches[name]
159         }
160
161         return nil
162 }
163
164 type watch struct {
165         wd    uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
166         flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
167 }
168
169 // readEvents reads from the inotify file descriptor, converts the
170 // received events into Event objects and sends them via the Events channel
171 func (w *Watcher) readEvents() {
172         var (
173                 buf   [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
174                 n     int                                     // Number of bytes read with read()
175                 errno error                                   // Syscall errno
176                 ok    bool                                    // For poller.wait
177         )
178
179         defer close(w.doneResp)
180         defer close(w.Errors)
181         defer close(w.Events)
182         defer syscall.Close(w.fd)
183         defer w.poller.close()
184
185         for {
186                 // See if we have been closed.
187                 if w.isClosed() {
188                         return
189                 }
190
191                 ok, errno = w.poller.wait()
192                 if errno != nil {
193                         select {
194                         case w.Errors <- errno:
195                         case <-w.done:
196                                 return
197                         }
198                         continue
199                 }
200
201                 if !ok {
202                         continue
203                 }
204
205                 n, errno = syscall.Read(w.fd, buf[:])
206                 // If a signal interrupted execution, see if we've been asked to close, and try again.
207                 // http://man7.org/linux/man-pages/man7/signal.7.html :
208                 // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
209                 if errno == syscall.EINTR {
210                         continue
211                 }
212
213                 // syscall.Read might have been woken up by Close. If so, we're done.
214                 if w.isClosed() {
215                         return
216                 }
217
218                 if n < syscall.SizeofInotifyEvent {
219                         var err error
220                         if n == 0 {
221                                 // If EOF is received. This should really never happen.
222                                 err = io.EOF
223                         } else if n < 0 {
224                                 // If an error occurred while reading.
225                                 err = errno
226                         } else {
227                                 // Read was too short.
228                                 err = errors.New("notify: short read in readEvents()")
229                         }
230                         select {
231                         case w.Errors <- err:
232                         case <-w.done:
233                                 return
234                         }
235                         continue
236                 }
237
238                 var offset uint32
239                 // We don't know how many events we just read into the buffer
240                 // While the offset points to at least one whole event...
241                 for offset <= uint32(n-syscall.SizeofInotifyEvent) {
242                         // Point "raw" to the event in the buffer
243                         raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
244
245                         mask := uint32(raw.Mask)
246                         nameLen := uint32(raw.Len)
247                         // If the event happened to the watched directory or the watched file, the kernel
248                         // doesn't append the filename to the event, but we would like to always fill the
249                         // the "Name" field with a valid filename. We retrieve the path of the watch from
250                         // the "paths" map.
251                         w.mu.Lock()
252                         name := w.paths[int(raw.Wd)]
253                         w.mu.Unlock()
254                         if nameLen > 0 {
255                                 // Point "bytes" at the first byte of the filename
256                                 bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
257                                 // The filename is padded with NULL bytes. TrimRight() gets rid of those.
258                                 name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
259                         }
260
261                         event := newEvent(name, mask)
262
263                         // Send the events that are not ignored on the events channel
264                         if !event.ignoreLinux(w, raw.Wd, mask) {
265                                 select {
266                                 case w.Events <- event:
267                                 case <-w.done:
268                                         return
269                                 }
270                         }
271
272                         // Move to the next event in the buffer
273                         offset += syscall.SizeofInotifyEvent + nameLen
274                 }
275         }
276 }
277
278 // Certain types of events can be "ignored" and not sent over the Events
279 // channel. Such as events marked ignore by the kernel, or MODIFY events
280 // against files that do not exist.
281 func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool {
282         // Ignore anything the inotify API says to ignore
283         if mask&syscall.IN_IGNORED == syscall.IN_IGNORED {
284                 w.mu.Lock()
285                 defer w.mu.Unlock()
286                 name := w.paths[int(wd)]
287                 delete(w.paths, int(wd))
288                 delete(w.watches, name)
289                 w.cv.Broadcast()
290                 return true
291         }
292
293         // If the event is not a DELETE or RENAME, the file must exist.
294         // Otherwise the event is ignored.
295         // *Note*: this was put in place because it was seen that a MODIFY
296         // event was sent after the DELETE. This ignores that MODIFY and
297         // assumes a DELETE will come or has come if the file doesn't exist.
298         if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
299                 _, statErr := os.Lstat(e.Name)
300                 return os.IsNotExist(statErr)
301         }
302         return false
303 }
304
305 // newEvent returns an platform-independent Event based on an inotify mask.
306 func newEvent(name string, mask uint32) Event {
307         e := Event{Name: name}
308         if mask&syscall.IN_CREATE == syscall.IN_CREATE || mask&syscall.IN_MOVED_TO == syscall.IN_MOVED_TO {
309                 e.Op |= Create
310         }
311         if mask&syscall.IN_DELETE_SELF == syscall.IN_DELETE_SELF || mask&syscall.IN_DELETE == syscall.IN_DELETE {
312                 e.Op |= Remove
313         }
314         if mask&syscall.IN_MODIFY == syscall.IN_MODIFY {
315                 e.Op |= Write
316         }
317         if mask&syscall.IN_MOVE_SELF == syscall.IN_MOVE_SELF || mask&syscall.IN_MOVED_FROM == syscall.IN_MOVED_FROM {
318                 e.Op |= Rename
319         }
320         if mask&syscall.IN_ATTRIB == syscall.IN_ATTRIB {
321                 e.Op |= Chmod
322         }
323         return e
324 }