LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 /* | 5 /* |
6 Package inotify implements a wrapper for the Linux inotify system. | 6 Package inotify implements a wrapper for the Linux inotify system. |
7 | 7 |
8 Example: | 8 Example: |
9 watcher, err := inotify.NewWatcher() | 9 watcher, err := inotify.NewWatcher() |
10 if err != nil { | 10 if err != nil { |
(...skipping 16 matching lines...) Expand all Loading... |
27 package inotify | 27 package inotify |
28 | 28 |
29 import ( | 29 import ( |
30 "fmt" | 30 "fmt" |
31 "os" | 31 "os" |
32 "strings" | 32 "strings" |
33 "syscall" | 33 "syscall" |
34 "unsafe" | 34 "unsafe" |
35 ) | 35 ) |
36 | 36 |
37 | |
38 type Event struct { | 37 type Event struct { |
39 Mask uint32 // Mask of events | 38 Mask uint32 // Mask of events |
40 Cookie uint32 // Unique cookie associating related events (for rename(2)
) | 39 Cookie uint32 // Unique cookie associating related events (for rename(2)
) |
41 Name string // File name (optional) | 40 Name string // File name (optional) |
42 } | 41 } |
43 | 42 |
44 type watch struct { | 43 type watch struct { |
45 wd uint32 // Watch descriptor (as returned by the inotify_add_watch()
syscall) | 44 wd uint32 // Watch descriptor (as returned by the inotify_add_watch()
syscall) |
46 flags uint32 // inotify flags of this watch (see inotify(7) for the list
of valid flags) | 45 flags uint32 // inotify flags of this watch (see inotify(7) for the list
of valid flags) |
47 } | 46 } |
48 | 47 |
49 type Watcher struct { | 48 type Watcher struct { |
50 fd int // File descriptor (as returned by the inotif
y_init() syscall) | 49 fd int // File descriptor (as returned by the inotif
y_init() syscall) |
51 watches map[string]*watch // Map of inotify watches (key: path) | 50 watches map[string]*watch // Map of inotify watches (key: path) |
52 paths map[int]string // Map of watched paths (key: watch descripto
r) | 51 paths map[int]string // Map of watched paths (key: watch descripto
r) |
53 Error chan os.Error // Errors are sent on this channel | 52 Error chan os.Error // Errors are sent on this channel |
54 Event chan *Event // Events are returned on this channel | 53 Event chan *Event // Events are returned on this channel |
55 done chan bool // Channel for sending a "quit message" to th
e reader goroutine | 54 done chan bool // Channel for sending a "quit message" to th
e reader goroutine |
56 isClosed bool // Set to true when Close() is first called | 55 isClosed bool // Set to true when Close() is first called |
57 } | 56 } |
58 | 57 |
59 | |
60 // NewWatcher creates and returns a new inotify instance using inotify_init(2) | 58 // NewWatcher creates and returns a new inotify instance using inotify_init(2) |
61 func NewWatcher() (*Watcher, os.Error) { | 59 func NewWatcher() (*Watcher, os.Error) { |
62 fd, errno := syscall.InotifyInit() | 60 fd, errno := syscall.InotifyInit() |
63 if fd == -1 { | 61 if fd == -1 { |
64 return nil, os.NewSyscallError("inotify_init", errno) | 62 return nil, os.NewSyscallError("inotify_init", errno) |
65 } | 63 } |
66 w := &Watcher{ | 64 w := &Watcher{ |
67 fd: fd, | 65 fd: fd, |
68 watches: make(map[string]*watch), | 66 watches: make(map[string]*watch), |
69 paths: make(map[int]string), | 67 paths: make(map[int]string), |
70 Event: make(chan *Event), | 68 Event: make(chan *Event), |
71 Error: make(chan os.Error), | 69 Error: make(chan os.Error), |
72 done: make(chan bool, 1), | 70 done: make(chan bool, 1), |
73 } | 71 } |
74 | 72 |
75 go w.readEvents() | 73 go w.readEvents() |
76 return w, nil | 74 return w, nil |
77 } | 75 } |
78 | 76 |
79 | |
80 // Close closes an inotify watcher instance | 77 // Close closes an inotify watcher instance |
81 // It sends a message to the reader goroutine to quit and removes all watches | 78 // It sends a message to the reader goroutine to quit and removes all watches |
82 // associated with the inotify instance | 79 // associated with the inotify instance |
83 func (w *Watcher) Close() os.Error { | 80 func (w *Watcher) Close() os.Error { |
84 if w.isClosed { | 81 if w.isClosed { |
85 return nil | 82 return nil |
86 } | 83 } |
87 w.isClosed = true | 84 w.isClosed = true |
88 | 85 |
89 // Send "quit" message to the reader goroutine | 86 // Send "quit" message to the reader goroutine |
(...skipping 22 matching lines...) Expand all Loading... |
112 return &os.PathError{"inotify_add_watch", path, os.Errno(errno)} | 109 return &os.PathError{"inotify_add_watch", path, os.Errno(errno)} |
113 } | 110 } |
114 | 111 |
115 if !found { | 112 if !found { |
116 w.watches[path] = &watch{wd: uint32(wd), flags: flags} | 113 w.watches[path] = &watch{wd: uint32(wd), flags: flags} |
117 w.paths[wd] = path | 114 w.paths[wd] = path |
118 } | 115 } |
119 return nil | 116 return nil |
120 } | 117 } |
121 | 118 |
122 | |
123 // Watch adds path to the watched file set, watching all events. | 119 // Watch adds path to the watched file set, watching all events. |
124 func (w *Watcher) Watch(path string) os.Error { | 120 func (w *Watcher) Watch(path string) os.Error { |
125 return w.AddWatch(path, IN_ALL_EVENTS) | 121 return w.AddWatch(path, IN_ALL_EVENTS) |
126 } | 122 } |
127 | |
128 | 123 |
129 // RemoveWatch removes path from the watched file set. | 124 // RemoveWatch removes path from the watched file set. |
130 func (w *Watcher) RemoveWatch(path string) os.Error { | 125 func (w *Watcher) RemoveWatch(path string) os.Error { |
131 watch, ok := w.watches[path] | 126 watch, ok := w.watches[path] |
132 if !ok { | 127 if !ok { |
133 return os.NewError(fmt.Sprintf("can't remove non-existent inotif
y watch for: %s", path)) | 128 return os.NewError(fmt.Sprintf("can't remove non-existent inotif
y watch for: %s", path)) |
134 } | 129 } |
135 success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) | 130 success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) |
136 if success == -1 { | 131 if success == -1 { |
137 return os.NewSyscallError("inotify_rm_watch", errno) | 132 return os.NewSyscallError("inotify_rm_watch", errno) |
138 } | 133 } |
139 w.watches[path] = nil, false | 134 w.watches[path] = nil, false |
140 return nil | 135 return nil |
141 } | 136 } |
142 | |
143 | 137 |
144 // readEvents reads from the inotify file descriptor, converts the | 138 // readEvents reads from the inotify file descriptor, converts the |
145 // received events into Event objects and sends them via the Event channel | 139 // received events into Event objects and sends them via the Event channel |
146 func (w *Watcher) readEvents() { | 140 func (w *Watcher) readEvents() { |
147 var ( | 141 var ( |
148 buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a ma
ximum of 4096 raw events | 142 buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a ma
ximum of 4096 raw events |
149 n int // Number of bytes
read with read() | 143 n int // Number of bytes
read with read() |
150 errno int // Syscall errno | 144 errno int // Syscall errno |
151 ) | 145 ) |
152 | 146 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 } | 195 } |
202 // Send the event on the events channel | 196 // Send the event on the events channel |
203 w.Event <- event | 197 w.Event <- event |
204 | 198 |
205 // Move to the next event in the buffer | 199 // Move to the next event in the buffer |
206 offset += syscall.SizeofInotifyEvent + nameLen | 200 offset += syscall.SizeofInotifyEvent + nameLen |
207 } | 201 } |
208 } | 202 } |
209 } | 203 } |
210 | 204 |
211 | |
212 // String formats the event e in the form | 205 // String formats the event e in the form |
213 // "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..." | 206 // "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..." |
214 func (e *Event) String() string { | 207 func (e *Event) String() string { |
215 var events string = "" | 208 var events string = "" |
216 | 209 |
217 m := e.Mask | 210 m := e.Mask |
218 for _, b := range eventBits { | 211 for _, b := range eventBits { |
219 if m&b.Value != 0 { | 212 if m&b.Value != 0 { |
220 m &^= b.Value | 213 m &^= b.Value |
221 events += "|" + b.Name | 214 events += "|" + b.Name |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 {IN_MOVE, "IN_MOVE"}, | 279 {IN_MOVE, "IN_MOVE"}, |
287 {IN_MOVED_FROM, "IN_MOVED_FROM"}, | 280 {IN_MOVED_FROM, "IN_MOVED_FROM"}, |
288 {IN_MOVED_TO, "IN_MOVED_TO"}, | 281 {IN_MOVED_TO, "IN_MOVED_TO"}, |
289 {IN_MOVE_SELF, "IN_MOVE_SELF"}, | 282 {IN_MOVE_SELF, "IN_MOVE_SELF"}, |
290 {IN_OPEN, "IN_OPEN"}, | 283 {IN_OPEN, "IN_OPEN"}, |
291 {IN_ISDIR, "IN_ISDIR"}, | 284 {IN_ISDIR, "IN_ISDIR"}, |
292 {IN_IGNORED, "IN_IGNORED"}, | 285 {IN_IGNORED, "IN_IGNORED"}, |
293 {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"}, | 286 {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"}, |
294 {IN_UNMOUNT, "IN_UNMOUNT"}, | 287 {IN_UNMOUNT, "IN_UNMOUNT"}, |
295 } | 288 } |
LEFT | RIGHT |