inotify.go 9.5 KB

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