diff options
| author | Mattias EngdegÄrd | 2019-04-20 10:19:52 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-04-22 17:54:32 +0200 |
| commit | c243aabfa8d280adf75024c8e6c0e68a7932f6cf (patch) | |
| tree | 72bb8683c4ce909d18be2d180a174e86c1927df5 | |
| parent | 4e2ea400cbd78fa791fb897938a6dcb099401a25 (diff) | |
| download | emacs-c243aabfa8d280adf75024c8e6c0e68a7932f6cf.tar.gz emacs-c243aabfa8d280adf75024c8e6c0e68a7932f6cf.zip | |
Make file-notify-rm-watch robust against reentry
Allow file-notify callbacks to call `file-notify-rm-watch', harmlessly,
after receiving a `stopped' event without triggering recursion.
* lisp/filenotify.el (file-notify--watch): Note that `callback' can be nil.
(file-notify--rm-descriptor): Set the `callback' field to nil before
sending `stopped'.
(file-notify-rm-watch): Don't do anything if the `callback' field is nil.
| -rw-r--r-- | lisp/filenotify.el | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/lisp/filenotify.el b/lisp/filenotify.el index 3f9bb960a9b..62dd1cd9117 100644 --- a/lisp/filenotify.el +++ b/lisp/filenotify.el | |||
| @@ -49,7 +49,7 @@ could use another implementation.") | |||
| 49 | directory | 49 | directory |
| 50 | ;; Watched relative filename, nil if watching the directory. | 50 | ;; Watched relative filename, nil if watching the directory. |
| 51 | filename | 51 | filename |
| 52 | ;; Function to propagate events to. | 52 | ;; Function to propagate events to, or nil if watch is being removed. |
| 53 | callback) | 53 | callback) |
| 54 | 54 | ||
| 55 | (defun file-notify--watch-absolute-filename (watch) | 55 | (defun file-notify--watch-absolute-filename (watch) |
| @@ -72,12 +72,15 @@ struct.") | |||
| 72 | DESCRIPTOR should be an object returned by `file-notify-add-watch'. | 72 | DESCRIPTOR should be an object returned by `file-notify-add-watch'. |
| 73 | If it is registered in `file-notify-descriptors', a stopped event is sent." | 73 | If it is registered in `file-notify-descriptors', a stopped event is sent." |
| 74 | (when-let* ((watch (gethash descriptor file-notify-descriptors))) | 74 | (when-let* ((watch (gethash descriptor file-notify-descriptors))) |
| 75 | ;; Send `stopped' event. | 75 | (let ((callback (file-notify--watch-callback watch))) |
| 76 | (unwind-protect | 76 | ;; Make sure this is the last time the callback is invoked. |
| 77 | (funcall | 77 | (setf (file-notify--watch-callback watch) nil) |
| 78 | (file-notify--watch-callback watch) | 78 | ;; Send `stopped' event. |
| 79 | `(,descriptor stopped ,(file-notify--watch-absolute-filename watch))) | 79 | (unwind-protect |
| 80 | (remhash descriptor file-notify-descriptors)))) | 80 | (funcall |
| 81 | callback | ||
| 82 | `(,descriptor stopped ,(file-notify--watch-absolute-filename watch))) | ||
| 83 | (remhash descriptor file-notify-descriptors))))) | ||
| 81 | 84 | ||
| 82 | ;; This function is used by `inotify', `kqueue', `gfilenotify' and | 85 | ;; This function is used by `inotify', `kqueue', `gfilenotify' and |
| 83 | ;; `w32notify' events. | 86 | ;; `w32notify' events. |
| @@ -381,25 +384,27 @@ FILE is the name of the file whose event is being reported." | |||
| 381 | "Remove an existing watch specified by its DESCRIPTOR. | 384 | "Remove an existing watch specified by its DESCRIPTOR. |
| 382 | DESCRIPTOR should be an object returned by `file-notify-add-watch'." | 385 | DESCRIPTOR should be an object returned by `file-notify-add-watch'." |
| 383 | (when-let* ((watch (gethash descriptor file-notify-descriptors))) | 386 | (when-let* ((watch (gethash descriptor file-notify-descriptors))) |
| 384 | (let ((handler (find-file-name-handler | 387 | ;; If we are called from a `stopped' event, do nothing. |
| 385 | (file-notify--watch-directory watch) | 388 | (when (file-notify--watch-callback watch) |
| 386 | 'file-notify-rm-watch))) | 389 | (let ((handler (find-file-name-handler |
| 387 | (condition-case nil | 390 | (file-notify--watch-directory watch) |
| 388 | (if handler | 391 | 'file-notify-rm-watch))) |
| 389 | ;; A file name handler could exist even if there is no | 392 | (condition-case nil |
| 390 | ;; local file notification support. | 393 | (if handler |
| 391 | (funcall handler 'file-notify-rm-watch descriptor) | 394 | ;; A file name handler could exist even if there is no |
| 392 | 395 | ;; local file notification support. | |
| 393 | (funcall | 396 | (funcall handler 'file-notify-rm-watch descriptor) |
| 394 | (cond | 397 | |
| 395 | ((eq file-notify--library 'inotify) 'inotify-rm-watch) | 398 | (funcall |
| 396 | ((eq file-notify--library 'kqueue) 'kqueue-rm-watch) | 399 | (cond |
| 397 | ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch) | 400 | ((eq file-notify--library 'inotify) 'inotify-rm-watch) |
| 398 | ((eq file-notify--library 'w32notify) 'w32notify-rm-watch)) | 401 | ((eq file-notify--library 'kqueue) 'kqueue-rm-watch) |
| 399 | descriptor)) | 402 | ((eq file-notify--library 'gfilenotify) 'gfile-rm-watch) |
| 400 | (file-notify-error nil))) | 403 | ((eq file-notify--library 'w32notify) 'w32notify-rm-watch)) |
| 401 | ;; Modify `file-notify-descriptors'. | 404 | descriptor)) |
| 402 | (file-notify--rm-descriptor descriptor))) | 405 | (file-notify-error nil))) |
| 406 | ;; Modify `file-notify-descriptors' and send a `stopped' event. | ||
| 407 | (file-notify--rm-descriptor descriptor)))) | ||
| 403 | 408 | ||
| 404 | (defun file-notify-valid-p (descriptor) | 409 | (defun file-notify-valid-p (descriptor) |
| 405 | "Check a watch specified by its DESCRIPTOR. | 410 | "Check a watch specified by its DESCRIPTOR. |