backend_kqueue.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. //go:build freebsd || openbsd || netbsd || dragonfly || darwin
  2. // +build freebsd openbsd netbsd dragonfly darwin
  3. // Note: the documentation on the Watcher type and methods is generated from
  4. // mkdoc.zsh
  5. package fsnotify
  6. import (
  7. "errors"
  8. "fmt"
  9. "os"
  10. "path/filepath"
  11. "sync"
  12. "golang.org/x/sys/unix"
  13. )
  14. // Watcher watches a set of paths, delivering events on a channel.
  15. //
  16. // A watcher should not be copied (e.g. pass it by pointer, rather than by
  17. // value).
  18. //
  19. // # Linux notes
  20. //
  21. // When a file is removed a Remove event won't be emitted until all file
  22. // descriptors are closed, and deletes will always emit a Chmod. For example:
  23. //
  24. // fp := os.Open("file")
  25. // os.Remove("file") // Triggers Chmod
  26. // fp.Close() // Triggers Remove
  27. //
  28. // This is the event that inotify sends, so not much can be changed about this.
  29. //
  30. // The fs.inotify.max_user_watches sysctl variable specifies the upper limit
  31. // for the number of watches per user, and fs.inotify.max_user_instances
  32. // specifies the maximum number of inotify instances per user. Every Watcher you
  33. // create is an "instance", and every path you add is a "watch".
  34. //
  35. // These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
  36. // /proc/sys/fs/inotify/max_user_instances
  37. //
  38. // To increase them you can use sysctl or write the value to the /proc file:
  39. //
  40. // # Default values on Linux 5.18
  41. // sysctl fs.inotify.max_user_watches=124983
  42. // sysctl fs.inotify.max_user_instances=128
  43. //
  44. // To make the changes persist on reboot edit /etc/sysctl.conf or
  45. // /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
  46. // your distro's documentation):
  47. //
  48. // fs.inotify.max_user_watches=124983
  49. // fs.inotify.max_user_instances=128
  50. //
  51. // Reaching the limit will result in a "no space left on device" or "too many open
  52. // files" error.
  53. //
  54. // # kqueue notes (macOS, BSD)
  55. //
  56. // kqueue requires opening a file descriptor for every file that's being watched;
  57. // so if you're watching a directory with five files then that's six file
  58. // descriptors. You will run in to your system's "max open files" limit faster on
  59. // these platforms.
  60. //
  61. // The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
  62. // control the maximum number of open files, as well as /etc/login.conf on BSD
  63. // systems.
  64. //
  65. // # Windows notes
  66. //
  67. // Paths can be added as "C:\path\to\dir", but forward slashes
  68. // ("C:/path/to/dir") will also work.
  69. //
  70. // When a watched directory is removed it will always send an event for the
  71. // directory itself, but may not send events for all files in that directory.
  72. // Sometimes it will send events for all times, sometimes it will send no
  73. // events, and often only for some files.
  74. //
  75. // The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
  76. // value that is guaranteed to work with SMB filesystems. If you have many
  77. // events in quick succession this may not be enough, and you will have to use
  78. // [WithBufferSize] to increase the value.
  79. type Watcher struct {
  80. // Events sends the filesystem change events.
  81. //
  82. // fsnotify can send the following events; a "path" here can refer to a
  83. // file, directory, symbolic link, or special file like a FIFO.
  84. //
  85. // fsnotify.Create A new path was created; this may be followed by one
  86. // or more Write events if data also gets written to a
  87. // file.
  88. //
  89. // fsnotify.Remove A path was removed.
  90. //
  91. // fsnotify.Rename A path was renamed. A rename is always sent with the
  92. // old path as Event.Name, and a Create event will be
  93. // sent with the new name. Renames are only sent for
  94. // paths that are currently watched; e.g. moving an
  95. // unmonitored file into a monitored directory will
  96. // show up as just a Create. Similarly, renaming a file
  97. // to outside a monitored directory will show up as
  98. // only a Rename.
  99. //
  100. // fsnotify.Write A file or named pipe was written to. A Truncate will
  101. // also trigger a Write. A single "write action"
  102. // initiated by the user may show up as one or multiple
  103. // writes, depending on when the system syncs things to
  104. // disk. For example when compiling a large Go program
  105. // you may get hundreds of Write events, and you may
  106. // want to wait until you've stopped receiving them
  107. // (see the dedup example in cmd/fsnotify).
  108. //
  109. // Some systems may send Write event for directories
  110. // when the directory content changes.
  111. //
  112. // fsnotify.Chmod Attributes were changed. On Linux this is also sent
  113. // when a file is removed (or more accurately, when a
  114. // link to an inode is removed). On kqueue it's sent
  115. // when a file is truncated. On Windows it's never
  116. // sent.
  117. Events chan Event
  118. // Errors sends any errors.
  119. //
  120. // ErrEventOverflow is used to indicate there are too many events:
  121. //
  122. // - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
  123. // - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
  124. // - kqueue, fen: Not used.
  125. Errors chan error
  126. done chan struct{}
  127. kq int // File descriptor (as returned by the kqueue() syscall).
  128. closepipe [2]int // Pipe used for closing.
  129. mu sync.Mutex // Protects access to watcher data
  130. watches map[string]int // Watched file descriptors (key: path).
  131. watchesByDir map[string]map[int]struct{} // Watched file descriptors indexed by the parent directory (key: dirname(path)).
  132. userWatches map[string]struct{} // Watches added with Watcher.Add()
  133. dirFlags map[string]uint32 // Watched directories to fflags used in kqueue.
  134. paths map[int]pathInfo // File descriptors to path names for processing kqueue events.
  135. fileExists map[string]struct{} // Keep track of if we know this file exists (to stop duplicate create events).
  136. isClosed bool // Set to true when Close() is first called
  137. }
  138. type pathInfo struct {
  139. name string
  140. isDir bool
  141. }
  142. // NewWatcher creates a new Watcher.
  143. func NewWatcher() (*Watcher, error) {
  144. return NewBufferedWatcher(0)
  145. }
  146. // NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
  147. // channel.
  148. //
  149. // The main use case for this is situations with a very large number of events
  150. // where the kernel buffer size can't be increased (e.g. due to lack of
  151. // permissions). An unbuffered Watcher will perform better for almost all use
  152. // cases, and whenever possible you will be better off increasing the kernel
  153. // buffers instead of adding a large userspace buffer.
  154. func NewBufferedWatcher(sz uint) (*Watcher, error) {
  155. kq, closepipe, err := newKqueue()
  156. if err != nil {
  157. return nil, err
  158. }
  159. w := &Watcher{
  160. kq: kq,
  161. closepipe: closepipe,
  162. watches: make(map[string]int),
  163. watchesByDir: make(map[string]map[int]struct{}),
  164. dirFlags: make(map[string]uint32),
  165. paths: make(map[int]pathInfo),
  166. fileExists: make(map[string]struct{}),
  167. userWatches: make(map[string]struct{}),
  168. Events: make(chan Event, sz),
  169. Errors: make(chan error),
  170. done: make(chan struct{}),
  171. }
  172. go w.readEvents()
  173. return w, nil
  174. }
  175. // newKqueue creates a new kernel event queue and returns a descriptor.
  176. //
  177. // This registers a new event on closepipe, which will trigger an event when
  178. // it's closed. This way we can use kevent() without timeout/polling; without
  179. // the closepipe, it would block forever and we wouldn't be able to stop it at
  180. // all.
  181. func newKqueue() (kq int, closepipe [2]int, err error) {
  182. kq, err = unix.Kqueue()
  183. if kq == -1 {
  184. return kq, closepipe, err
  185. }
  186. // Register the close pipe.
  187. err = unix.Pipe(closepipe[:])
  188. if err != nil {
  189. unix.Close(kq)
  190. return kq, closepipe, err
  191. }
  192. // Register changes to listen on the closepipe.
  193. changes := make([]unix.Kevent_t, 1)
  194. // SetKevent converts int to the platform-specific types.
  195. unix.SetKevent(&changes[0], closepipe[0], unix.EVFILT_READ,
  196. unix.EV_ADD|unix.EV_ENABLE|unix.EV_ONESHOT)
  197. ok, err := unix.Kevent(kq, changes, nil, nil)
  198. if ok == -1 {
  199. unix.Close(kq)
  200. unix.Close(closepipe[0])
  201. unix.Close(closepipe[1])
  202. return kq, closepipe, err
  203. }
  204. return kq, closepipe, nil
  205. }
  206. // Returns true if the event was sent, or false if watcher is closed.
  207. func (w *Watcher) sendEvent(e Event) bool {
  208. select {
  209. case w.Events <- e:
  210. return true
  211. case <-w.done:
  212. return false
  213. }
  214. }
  215. // Returns true if the error was sent, or false if watcher is closed.
  216. func (w *Watcher) sendError(err error) bool {
  217. select {
  218. case w.Errors <- err:
  219. return true
  220. case <-w.done:
  221. return false
  222. }
  223. }
  224. // Close removes all watches and closes the Events channel.
  225. func (w *Watcher) Close() error {
  226. w.mu.Lock()
  227. if w.isClosed {
  228. w.mu.Unlock()
  229. return nil
  230. }
  231. w.isClosed = true
  232. // copy paths to remove while locked
  233. pathsToRemove := make([]string, 0, len(w.watches))
  234. for name := range w.watches {
  235. pathsToRemove = append(pathsToRemove, name)
  236. }
  237. w.mu.Unlock() // Unlock before calling Remove, which also locks
  238. for _, name := range pathsToRemove {
  239. w.Remove(name)
  240. }
  241. // Send "quit" message to the reader goroutine.
  242. unix.Close(w.closepipe[1])
  243. close(w.done)
  244. return nil
  245. }
  246. // Add starts monitoring the path for changes.
  247. //
  248. // A path can only be watched once; watching it more than once is a no-op and will
  249. // not return an error. Paths that do not yet exist on the filesystem cannot be
  250. // watched.
  251. //
  252. // A watch will be automatically removed if the watched path is deleted or
  253. // renamed. The exception is the Windows backend, which doesn't remove the
  254. // watcher on renames.
  255. //
  256. // Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
  257. // filesystems (/proc, /sys, etc.) generally don't work.
  258. //
  259. // Returns [ErrClosed] if [Watcher.Close] was called.
  260. //
  261. // See [Watcher.AddWith] for a version that allows adding options.
  262. //
  263. // # Watching directories
  264. //
  265. // All files in a directory are monitored, including new files that are created
  266. // after the watcher is started. Subdirectories are not watched (i.e. it's
  267. // non-recursive).
  268. //
  269. // # Watching files
  270. //
  271. // Watching individual files (rather than directories) is generally not
  272. // recommended as many programs (especially editors) update files atomically: it
  273. // will write to a temporary file which is then moved to to destination,
  274. // overwriting the original (or some variant thereof). The watcher on the
  275. // original file is now lost, as that no longer exists.
  276. //
  277. // The upshot of this is that a power failure or crash won't leave a
  278. // half-written file.
  279. //
  280. // Watch the parent directory and use Event.Name to filter out files you're not
  281. // interested in. There is an example of this in cmd/fsnotify/file.go.
  282. func (w *Watcher) Add(name string) error { return w.AddWith(name) }
  283. // AddWith is like [Watcher.Add], but allows adding options. When using Add()
  284. // the defaults described below are used.
  285. //
  286. // Possible options are:
  287. //
  288. // - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
  289. // other platforms. The default is 64K (65536 bytes).
  290. func (w *Watcher) AddWith(name string, opts ...addOpt) error {
  291. _ = getOptions(opts...)
  292. w.mu.Lock()
  293. w.userWatches[name] = struct{}{}
  294. w.mu.Unlock()
  295. _, err := w.addWatch(name, noteAllEvents)
  296. return err
  297. }
  298. // Remove stops monitoring the path for changes.
  299. //
  300. // Directories are always removed non-recursively. For example, if you added
  301. // /tmp/dir and /tmp/dir/subdir then you will need to remove both.
  302. //
  303. // Removing a path that has not yet been added returns [ErrNonExistentWatch].
  304. //
  305. // Returns nil if [Watcher.Close] was called.
  306. func (w *Watcher) Remove(name string) error {
  307. return w.remove(name, true)
  308. }
  309. func (w *Watcher) remove(name string, unwatchFiles bool) error {
  310. name = filepath.Clean(name)
  311. w.mu.Lock()
  312. if w.isClosed {
  313. w.mu.Unlock()
  314. return nil
  315. }
  316. watchfd, ok := w.watches[name]
  317. w.mu.Unlock()
  318. if !ok {
  319. return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
  320. }
  321. err := w.register([]int{watchfd}, unix.EV_DELETE, 0)
  322. if err != nil {
  323. return err
  324. }
  325. unix.Close(watchfd)
  326. w.mu.Lock()
  327. isDir := w.paths[watchfd].isDir
  328. delete(w.watches, name)
  329. delete(w.userWatches, name)
  330. parentName := filepath.Dir(name)
  331. delete(w.watchesByDir[parentName], watchfd)
  332. if len(w.watchesByDir[parentName]) == 0 {
  333. delete(w.watchesByDir, parentName)
  334. }
  335. delete(w.paths, watchfd)
  336. delete(w.dirFlags, name)
  337. delete(w.fileExists, name)
  338. w.mu.Unlock()
  339. // Find all watched paths that are in this directory that are not external.
  340. if unwatchFiles && isDir {
  341. var pathsToRemove []string
  342. w.mu.Lock()
  343. for fd := range w.watchesByDir[name] {
  344. path := w.paths[fd]
  345. if _, ok := w.userWatches[path.name]; !ok {
  346. pathsToRemove = append(pathsToRemove, path.name)
  347. }
  348. }
  349. w.mu.Unlock()
  350. for _, name := range pathsToRemove {
  351. // Since these are internal, not much sense in propagating error to
  352. // the user, as that will just confuse them with an error about a
  353. // path they did not explicitly watch themselves.
  354. w.Remove(name)
  355. }
  356. }
  357. return nil
  358. }
  359. // WatchList returns all paths explicitly added with [Watcher.Add] (and are not
  360. // yet removed).
  361. //
  362. // Returns nil if [Watcher.Close] was called.
  363. func (w *Watcher) WatchList() []string {
  364. w.mu.Lock()
  365. defer w.mu.Unlock()
  366. if w.isClosed {
  367. return nil
  368. }
  369. entries := make([]string, 0, len(w.userWatches))
  370. for pathname := range w.userWatches {
  371. entries = append(entries, pathname)
  372. }
  373. return entries
  374. }
  375. // Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
  376. const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
  377. // addWatch adds name to the watched file set; the flags are interpreted as
  378. // described in kevent(2).
  379. //
  380. // Returns the real path to the file which was added, with symlinks resolved.
  381. func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
  382. var isDir bool
  383. name = filepath.Clean(name)
  384. w.mu.Lock()
  385. if w.isClosed {
  386. w.mu.Unlock()
  387. return "", ErrClosed
  388. }
  389. watchfd, alreadyWatching := w.watches[name]
  390. // We already have a watch, but we can still override flags.
  391. if alreadyWatching {
  392. isDir = w.paths[watchfd].isDir
  393. }
  394. w.mu.Unlock()
  395. if !alreadyWatching {
  396. fi, err := os.Lstat(name)
  397. if err != nil {
  398. return "", err
  399. }
  400. // Don't watch sockets or named pipes
  401. if (fi.Mode()&os.ModeSocket == os.ModeSocket) || (fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe) {
  402. return "", nil
  403. }
  404. // Follow Symlinks.
  405. if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
  406. link, err := os.Readlink(name)
  407. if err != nil {
  408. // Return nil because Linux can add unresolvable symlinks to the
  409. // watch list without problems, so maintain consistency with
  410. // that. There will be no file events for broken symlinks.
  411. // TODO: more specific check; returns os.PathError; ENOENT?
  412. return "", nil
  413. }
  414. w.mu.Lock()
  415. _, alreadyWatching = w.watches[link]
  416. w.mu.Unlock()
  417. if alreadyWatching {
  418. // Add to watches so we don't get spurious Create events later
  419. // on when we diff the directories.
  420. w.watches[name] = 0
  421. w.fileExists[name] = struct{}{}
  422. return link, nil
  423. }
  424. name = link
  425. fi, err = os.Lstat(name)
  426. if err != nil {
  427. return "", nil
  428. }
  429. }
  430. // Retry on EINTR; open() can return EINTR in practice on macOS.
  431. // See #354, and Go issues 11180 and 39237.
  432. for {
  433. watchfd, err = unix.Open(name, openMode, 0)
  434. if err == nil {
  435. break
  436. }
  437. if errors.Is(err, unix.EINTR) {
  438. continue
  439. }
  440. return "", err
  441. }
  442. isDir = fi.IsDir()
  443. }
  444. err := w.register([]int{watchfd}, unix.EV_ADD|unix.EV_CLEAR|unix.EV_ENABLE, flags)
  445. if err != nil {
  446. unix.Close(watchfd)
  447. return "", err
  448. }
  449. if !alreadyWatching {
  450. w.mu.Lock()
  451. parentName := filepath.Dir(name)
  452. w.watches[name] = watchfd
  453. watchesByDir, ok := w.watchesByDir[parentName]
  454. if !ok {
  455. watchesByDir = make(map[int]struct{}, 1)
  456. w.watchesByDir[parentName] = watchesByDir
  457. }
  458. watchesByDir[watchfd] = struct{}{}
  459. w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
  460. w.mu.Unlock()
  461. }
  462. if isDir {
  463. // Watch the directory if it has not been watched before, or if it was
  464. // watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
  465. w.mu.Lock()
  466. watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
  467. (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
  468. // Store flags so this watch can be updated later
  469. w.dirFlags[name] = flags
  470. w.mu.Unlock()
  471. if watchDir {
  472. if err := w.watchDirectoryFiles(name); err != nil {
  473. return "", err
  474. }
  475. }
  476. }
  477. return name, nil
  478. }
  479. // readEvents reads from kqueue and converts the received kevents into
  480. // Event values that it sends down the Events channel.
  481. func (w *Watcher) readEvents() {
  482. defer func() {
  483. close(w.Events)
  484. close(w.Errors)
  485. _ = unix.Close(w.kq)
  486. unix.Close(w.closepipe[0])
  487. }()
  488. eventBuffer := make([]unix.Kevent_t, 10)
  489. for closed := false; !closed; {
  490. kevents, err := w.read(eventBuffer)
  491. // EINTR is okay, the syscall was interrupted before timeout expired.
  492. if err != nil && err != unix.EINTR {
  493. if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) {
  494. closed = true
  495. }
  496. continue
  497. }
  498. // Flush the events we received to the Events channel
  499. for _, kevent := range kevents {
  500. var (
  501. watchfd = int(kevent.Ident)
  502. mask = uint32(kevent.Fflags)
  503. )
  504. // Shut down the loop when the pipe is closed, but only after all
  505. // other events have been processed.
  506. if watchfd == w.closepipe[0] {
  507. closed = true
  508. continue
  509. }
  510. w.mu.Lock()
  511. path := w.paths[watchfd]
  512. w.mu.Unlock()
  513. event := w.newEvent(path.name, mask)
  514. if event.Has(Rename) || event.Has(Remove) {
  515. w.remove(event.Name, false)
  516. w.mu.Lock()
  517. delete(w.fileExists, event.Name)
  518. w.mu.Unlock()
  519. }
  520. if path.isDir && event.Has(Write) && !event.Has(Remove) {
  521. w.sendDirectoryChangeEvents(event.Name)
  522. } else {
  523. if !w.sendEvent(event) {
  524. closed = true
  525. continue
  526. }
  527. }
  528. if event.Has(Remove) {
  529. // Look for a file that may have overwritten this; for example,
  530. // mv f1 f2 will delete f2, then create f2.
  531. if path.isDir {
  532. fileDir := filepath.Clean(event.Name)
  533. w.mu.Lock()
  534. _, found := w.watches[fileDir]
  535. w.mu.Unlock()
  536. if found {
  537. err := w.sendDirectoryChangeEvents(fileDir)
  538. if err != nil {
  539. if !w.sendError(err) {
  540. closed = true
  541. }
  542. }
  543. }
  544. } else {
  545. filePath := filepath.Clean(event.Name)
  546. if fi, err := os.Lstat(filePath); err == nil {
  547. err := w.sendFileCreatedEventIfNew(filePath, fi)
  548. if err != nil {
  549. if !w.sendError(err) {
  550. closed = true
  551. }
  552. }
  553. }
  554. }
  555. }
  556. }
  557. }
  558. }
  559. // newEvent returns an platform-independent Event based on kqueue Fflags.
  560. func (w *Watcher) newEvent(name string, mask uint32) Event {
  561. e := Event{Name: name}
  562. if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
  563. e.Op |= Remove
  564. }
  565. if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
  566. e.Op |= Write
  567. }
  568. if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
  569. e.Op |= Rename
  570. }
  571. if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
  572. e.Op |= Chmod
  573. }
  574. // No point sending a write and delete event at the same time: if it's gone,
  575. // then it's gone.
  576. if e.Op.Has(Write) && e.Op.Has(Remove) {
  577. e.Op &^= Write
  578. }
  579. return e
  580. }
  581. // watchDirectoryFiles to mimic inotify when adding a watch on a directory
  582. func (w *Watcher) watchDirectoryFiles(dirPath string) error {
  583. // Get all files
  584. files, err := os.ReadDir(dirPath)
  585. if err != nil {
  586. return err
  587. }
  588. for _, f := range files {
  589. path := filepath.Join(dirPath, f.Name())
  590. fi, err := f.Info()
  591. if err != nil {
  592. return fmt.Errorf("%q: %w", path, err)
  593. }
  594. cleanPath, err := w.internalWatch(path, fi)
  595. if err != nil {
  596. // No permission to read the file; that's not a problem: just skip.
  597. // But do add it to w.fileExists to prevent it from being picked up
  598. // as a "new" file later (it still shows up in the directory
  599. // listing).
  600. switch {
  601. case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM):
  602. cleanPath = filepath.Clean(path)
  603. default:
  604. return fmt.Errorf("%q: %w", path, err)
  605. }
  606. }
  607. w.mu.Lock()
  608. w.fileExists[cleanPath] = struct{}{}
  609. w.mu.Unlock()
  610. }
  611. return nil
  612. }
  613. // Search the directory for new files and send an event for them.
  614. //
  615. // This functionality is to have the BSD watcher match the inotify, which sends
  616. // a create event for files created in a watched directory.
  617. func (w *Watcher) sendDirectoryChangeEvents(dir string) error {
  618. files, err := os.ReadDir(dir)
  619. if err != nil {
  620. // Directory no longer exists: we can ignore this safely. kqueue will
  621. // still give us the correct events.
  622. if errors.Is(err, os.ErrNotExist) {
  623. return nil
  624. }
  625. return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)
  626. }
  627. for _, f := range files {
  628. fi, err := f.Info()
  629. if err != nil {
  630. return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)
  631. }
  632. err = w.sendFileCreatedEventIfNew(filepath.Join(dir, fi.Name()), fi)
  633. if err != nil {
  634. // Don't need to send an error if this file isn't readable.
  635. if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) {
  636. return nil
  637. }
  638. return fmt.Errorf("fsnotify.sendDirectoryChangeEvents: %w", err)
  639. }
  640. }
  641. return nil
  642. }
  643. // sendFileCreatedEvent sends a create event if the file isn't already being tracked.
  644. func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fi os.FileInfo) (err error) {
  645. w.mu.Lock()
  646. _, doesExist := w.fileExists[filePath]
  647. w.mu.Unlock()
  648. if !doesExist {
  649. if !w.sendEvent(Event{Name: filePath, Op: Create}) {
  650. return
  651. }
  652. }
  653. // like watchDirectoryFiles (but without doing another ReadDir)
  654. filePath, err = w.internalWatch(filePath, fi)
  655. if err != nil {
  656. return err
  657. }
  658. w.mu.Lock()
  659. w.fileExists[filePath] = struct{}{}
  660. w.mu.Unlock()
  661. return nil
  662. }
  663. func (w *Watcher) internalWatch(name string, fi os.FileInfo) (string, error) {
  664. if fi.IsDir() {
  665. // mimic Linux providing delete events for subdirectories, but preserve
  666. // the flags used if currently watching subdirectory
  667. w.mu.Lock()
  668. flags := w.dirFlags[name]
  669. w.mu.Unlock()
  670. flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
  671. return w.addWatch(name, flags)
  672. }
  673. // watch file to mimic Linux inotify
  674. return w.addWatch(name, noteAllEvents)
  675. }
  676. // Register events with the queue.
  677. func (w *Watcher) register(fds []int, flags int, fflags uint32) error {
  678. changes := make([]unix.Kevent_t, len(fds))
  679. for i, fd := range fds {
  680. // SetKevent converts int to the platform-specific types.
  681. unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
  682. changes[i].Fflags = fflags
  683. }
  684. // Register the events.
  685. success, err := unix.Kevent(w.kq, changes, nil, nil)
  686. if success == -1 {
  687. return err
  688. }
  689. return nil
  690. }
  691. // read retrieves pending events, or waits until an event occurs.
  692. func (w *Watcher) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) {
  693. n, err := unix.Kevent(w.kq, nil, events, nil)
  694. if err != nil {
  695. return nil, err
  696. }
  697. return events[0:n], nil
  698. }