From f7185ca29b5086b1b0f32e64b7a5ba0bc21152c8 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Tue, 10 Oct 2023 19:51:22 +0200 Subject: [PATCH] File notifications report unmount events (bug#66381) * doc/lispref/os.texi (File Notifications): Unmounting a watched filesystem is reported now. * etc/NEWS: File notifications report unmount events now. Fix typos. * lisp/filenotify.el (file-notify--callback-inotify) (file-notify--add-watch-inotify): Handle `unmount'. (file-notify--callback-kqueue, file-notify--add-watch-kqueue): Handle `revoke'. (file-notify--callback-gfilenotify): Handle `unmounted'. (file-notify-callback): Handle `unmount' and `unmounted'. (file-notify--add-watch-inotify): * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-notify-add-watch): Handle `unmounted'. * lisp/net/tramp-sh.el (tramp-sh-handle-file-notify-add-watch): Handle `unmount' and `unmounted'. * src/gfilenotify.c (dir_monitor_callback): Handle Qunmounted. * src/inotify.c (symbol_to_inotifymask): Handle IN_IGNORED and IN_UNMOUNT. * src/kqueue.c (kqueue_callback, Fkqueue_add_watch): Handle NOTE_REVOKE. (Fkqueue_add_watch): Adapt docstring. (syms_of_kqueue): Declare `revoke. --- doc/lispref/os.texi | 3 ++- etc/NEWS | 35 ++++++++++++++++++++--------------- lisp/filenotify.el | 14 +++++++++----- lisp/net/tramp-gvfs.el | 6 +++--- lisp/net/tramp-sh.el | 13 +++++++------ src/gfilenotify.c | 8 +++++--- src/inotify.c | 5 +++++ src/kqueue.c | 10 ++++++++-- 8 files changed, 59 insertions(+), 35 deletions(-) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 5400d492f0a..f92709f1f9b 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -3355,7 +3355,8 @@ reliably report file attribute changes when watching a directory. The @code{stopped} event means that watching the file has been discontinued. This could be because @code{file-notify-rm-watch} was called (see below), or because the file being watched was deleted, or -due to another error reported from the underlying library which makes +because the filesystem of the file being watched was unmounted, or due +to another error reported from the underlying library which makes further watching impossible. @var{file} and @var{file1} are the name of the file(s) whose event is diff --git a/etc/NEWS b/etc/NEWS index 70110768c97..ececb7e8459 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -144,9 +144,7 @@ can use this to distinguish between buffers visiting files with the same base name that belong to different projects by using the provided transform function 'project-uniquify-dirname-transform'. -** 'insert-directory-program' is now a defcustom. - -** 'insert-directory-program' prefers "gls" on *BSD and macOS. +** 'insert-directory-program' is now a user option. On *BSD and macOS systems, this user option now defaults to the "gls" executable, if it exists. This should remove the need to change its value when installing GNU coreutils using something like ports or @@ -267,6 +265,7 @@ functions in CJK locales. * Changes in Specialized Modes and Packages in Emacs 30.1 ** gdb-mi + --- *** Variable order and truncation can now be configured in 'gdb-many-windows'. The new user option 'gdb-locals-table-row-config' allows users to @@ -285,7 +284,7 @@ If you want to get back the old behavior, set the user option to the value --- *** New user option 'gdb-display-io-buffer'. -If this is nil, "M-x gdb" will neither create nor display a separate +If this is nil, 'M-x gdb' will neither create nor display a separate buffer for the I/O of the program being debugged, but will instead redirect the program's interaction to the GDB execution buffer. The default is t, to preserve previous behavior. @@ -299,9 +298,9 @@ equivalent to the "--heading" option of some tools such as 'git grep' and 'rg'. The headings are displayed using the new 'grep-heading' face. ---- ** Compilation mode +--- *** The 'omake' matching rule is now disabled by default. This is because it partly acts by modifying other rules which may occasionally be surprising. It can be re-enabled by adding 'omake' to @@ -548,6 +547,11 @@ buffer must either visit a file, or it must run 'dired-mode'. Another method but "sudo" can be configured with user option 'tramp-file-name-with-method'. +** File Notifications + ++++ +*** All backends except w32notify detect unmounting of a watched filesystem now. + ** EWW +++ @@ -809,7 +813,8 @@ You can now configure how a thumbnail is named using this option. ** ERT -*** New macro `skip-when' to skip 'ert-deftest' tests. ++++ +*** New macro 'skip-when' to skip 'ert-deftest' tests. This can help avoid some awkward skip conditions. For example '(skip-unless (not noninteractive))' can be changed to the easier to read '(skip-when noninteractive)'. @@ -831,18 +836,19 @@ neither of which have been supported by Emacs since version 23.1. The user option 'url-gateway-nslookup-program' and the function 'url-gateway-nslookup-host' are consequently also obsolete. -+++ ** Edmacro ++++ *** New command 'edmacro-set-macro-to-region-lines'. Bound to 'C-c C-r', this command replaces the macro text with the lines of the region. If needed, the region is extended to include whole lines. If the region ends at the beginning of a line, that last line is excluded. ++++ *** New user option 'edmacro-reverse-macro-lines'. When this is non-nil, the lines of key sequences are displayed with -the most recent line fist. This is can be useful when working with +the most recent line first. This is can be useful when working with macros with many lines, such as from 'kmacro-edit-lossage'. @@ -861,8 +867,11 @@ A major mode based on the tree-sitter library for editing HEEx files. --- *** New major mode 'elixir-ts-mode'. -A major mode based on the tree-sitter library for editing Elixir -files. +A major mode based on the tree-sitter library for editing Elixir files. + +--- +*** New major mode 'lua-ts-mode'. +A major mode based on the tree-sitter library for editing Lua files. +++ ** New global minor mode 'minibuffer-regexp-mode'. @@ -871,10 +880,6 @@ It highlights parens via ‘show-paren-mode’ and ‘blink-matching-paren’ in a user-friendly way, avoids reporting alleged paren mismatches and makes sexp navigation more intuitive. ---- -*** New major mode 'lua-ts-mode'. -A major mode based on the tree-sitter library for editing Lua files. - --- ** The highly accessible Modus themes collection has eight items. The 'modus-operandi' and 'modus-vivendi' are the main themes that have @@ -913,7 +918,7 @@ the file listing's performance is still optimized. * Incompatible Lisp Changes in Emacs 30.1 -** 'post-gc-hook' runs after updating 'gcs-done' and `'gcs-elapsed'. +** 'post-gc-hook' runs after updating 'gcs-done' and 'gcs-elapsed'. --- ** The escape sequence '\x' not followed by hex digits is now an error. diff --git a/lisp/filenotify.el b/lisp/filenotify.el index e9f8d4e515d..03bd4e51485 100644 --- a/lisp/filenotify.el +++ b/lisp/filenotify.el @@ -138,7 +138,7 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.") ((memq action '(delete delete-self move-self)) 'deleted) ((eq action 'moved-from) 'renamed-from) ((eq action 'moved-to) 'renamed-to) - ((eq action 'ignored) 'stopped))) + ((memq action '(ignored unmount)) 'stopped))) actions)) file file1-or-cookie)) @@ -153,7 +153,8 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.") ((eq action 'write) 'changed) ((memq action '(attrib link)) 'attribute-changed) ((eq action 'delete) 'deleted) - ((eq action 'rename) 'renamed))) + ((eq action 'rename) 'renamed) + ((eq action 'revoke) 'stopped))) actions)) file file1-or-cookie)) @@ -179,7 +180,8 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.") ((memq action '(created changed attribute-changed deleted)) action) - ((eq action 'moved) 'renamed))) + ((eq action 'moved) 'renamed) + ((eq action 'unmounted) 'stopped))) (if (consp actions) actions (list actions)))) file file1-or-cookie)) @@ -195,6 +197,7 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.") ((memq action '(created changed attribute-changed deleted)) action) ((eq action 'moved) 'renamed) + ((eq action 'unmounted) 'stopped) ;; inotify actions: ((eq action 'create) 'created) ((eq action 'modify) 'changed) @@ -202,7 +205,7 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.") ((memq action '(delete delete-self move-self)) 'deleted) ((eq action 'moved-from) 'renamed-from) ((eq action 'moved-to) 'renamed-to) - ((eq action 'ignored) 'stopped))) + ((memq action '(ignored unmount)) 'stopped))) (if (consp actions) actions (list actions)))) file file1-or-cookie)) @@ -339,7 +342,7 @@ DESC is the back-end descriptor. ACTIONS is a list of: "Add a watch for FILE in DIR with FLAGS, using inotify." (inotify-add-watch dir (append - '(dont-follow) + '(dont-follow ignored unmount) (and (memq 'change flags) '(create delete delete-self modify move-self move)) (and (memq 'attribute-change flags) @@ -352,6 +355,7 @@ DESC is the back-end descriptor. ACTIONS is a list of: ;; directories, so we watch each file directly. (kqueue-add-watch file (append + '(revoke) (and (memq 'change flags) '(create delete write extend rename)) (and (memq 'attribute-change flags) diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 577760f806c..227571b148b 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -1490,10 +1490,10 @@ If FILE-SYSTEM is non-nil, return file system attributes." (cond ((and (memq 'change flags) (memq 'attribute-change flags)) '(created changed changes-done-hint moved deleted - attribute-changed)) + attribute-changed unmounted)) ((memq 'change flags) - '(created changed changes-done-hint moved deleted)) - ((memq 'attribute-change flags) '(attribute-changed)))) + '(created changed changes-done-hint moved deleted unmounted)) + ((memq 'attribute-change flags) '(attribute-changed unmounted)))) (p (apply #'start-process "gvfs-monitor" (generate-new-buffer " *gvfs-monitor*") diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 95c27626166..4a5840cca4c 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -3802,11 +3802,12 @@ Fall back to normal file name handler if no Tramp handler exists." (cond ((and (memq 'change flags) (memq 'attribute-change flags)) (concat "create,modify,move,moved_from,moved_to,move_self," - "delete,delete_self,attrib,ignored")) + "delete,delete_self,attrib")) ((memq 'change flags) (concat "create,modify,move,moved_from,moved_to,move_self," - "delete,delete_self,ignored")) - ((memq 'attribute-change flags) "attrib,ignored")) + "delete,delete_self")) + ((memq 'attribute-change flags) "attrib")) + events (concat events ",ignored,unmount") ;; "-P" has been added to version 3.21, so we cannot assume it yet. sequence `(,command "-mq" "-e" ,events ,localname) ;; Make events a list of symbols. @@ -3821,10 +3822,10 @@ Fall back to normal file name handler if no Tramp handler exists." (cond ((and (memq 'change flags) (memq 'attribute-change flags)) '(created changed changes-done-hint moved deleted - attribute-changed)) + attribute-changed unmounted)) ((memq 'change flags) - '(created changed changes-done-hint moved deleted)) - ((memq 'attribute-change flags) '(attribute-changed))) + '(created changed changes-done-hint moved deleted unmounted)) + ((memq 'attribute-change flags) '(attribute-changed unmounted))) sequence `(,command "monitor" ,localname))) ;; None. (t (tramp-error diff --git a/src/gfilenotify.c b/src/gfilenotify.c index de09ffe5fd3..3dd6390db10 100644 --- a/src/gfilenotify.c +++ b/src/gfilenotify.c @@ -88,7 +88,9 @@ dir_monitor_callback (GFileMonitor *monitor, && !NILP (Fmember (symbol, list5 (Qchanged, Qchanges_done_hint, Qdeleted, Qcreated, Qmoved)))) || (!NILP (Fmember (Qattribute_change, flags)) - && EQ (symbol, Qattribute_changed))) + && EQ (symbol, Qattribute_changed)) + || (!NILP (Fmember (Qwatch_mounts, flags)) + && EQ (symbol, Qunmounted))) { /* Construct an event. */ EVENT_INIT (event); @@ -105,8 +107,8 @@ dir_monitor_callback (GFileMonitor *monitor, /* XD_DEBUG_MESSAGE ("%s", XD_OBJECT_TO_STRING (event.arg)); */ } - /* Cancel monitor if file or directory is deleted. */ - if (!NILP (Fmember (symbol, list2 (Qdeleted, Qmoved))) + /* Cancel monitor if file or directory is deleted or unmounted. */ + if (!NILP (Fmember (symbol, list3 (Qdeleted, Qmoved, Qunmounted))) && strcmp (name, SSDATA (XCAR (XCDR (watch_object)))) == 0 && !g_file_monitor_is_cancelled (monitor)) g_file_monitor_cancel (monitor); diff --git a/src/inotify.c b/src/inotify.c index 105ff5a9d8a..247d9f03055 100644 --- a/src/inotify.c +++ b/src/inotify.c @@ -148,6 +148,11 @@ symbol_to_inotifymask (Lisp_Object symb) else if (EQ (symb, Qonlydir)) return IN_ONLYDIR; + else if (EQ (symb, Qignored)) + return IN_IGNORED; + else if (EQ (symb, Qunmount)) + return IN_UNMOUNT; + else if (EQ (symb, Qt) || EQ (symb, Qall_events)) return IN_ALL_EVENTS; else diff --git a/src/kqueue.c b/src/kqueue.c index 22c279b7ce3..43d5f40624b 100644 --- a/src/kqueue.c +++ b/src/kqueue.c @@ -320,13 +320,16 @@ kqueue_callback (int fd, void *data) directory is monitored. */ if (kev.fflags & NOTE_RENAME) actions = Fcons (Qrename, actions); + if (kev.fflags & NOTE_REVOKE) + actions = Fcons (Qrevoke, actions); /* Create the event. */ if (! NILP (actions)) kqueue_generate_event (watch_object, actions, file, Qnil); - /* Cancel monitor if file or directory is deleted or renamed. */ - if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) + /* Cancel monitor if file or directory is deleted or renamed or + the file system is unmounted. */ + if (kev.fflags & (NOTE_DELETE | NOTE_RENAME | NOTE_REVOKE)) Fkqueue_rm_watch (descriptor); } return; @@ -351,6 +354,7 @@ following symbols: `attrib' -- a FILE attribute was changed `link' -- a FILE's link count was changed `rename' -- FILE was moved to FILE1 + `revoke' -- FILE was unmounted When any event happens, Emacs will call the CALLBACK function passing it a single argument EVENT, which is of the form @@ -437,6 +441,7 @@ only when the upper directory of the renamed file is watched. */) if (! NILP (Fmember (Qattrib, flags))) fflags |= NOTE_ATTRIB; if (! NILP (Fmember (Qlink, flags))) fflags |= NOTE_LINK; if (! NILP (Fmember (Qrename, flags))) fflags |= NOTE_RENAME; + if (! NILP (Fmember (Qrevoke, flags))) fflags |= NOTE_REVOKE; /* Register event. */ EV_SET (&kev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, @@ -526,6 +531,7 @@ syms_of_kqueue (void) DEFSYM (Qattrib, "attrib"); /* NOTE_ATTRIB */ DEFSYM (Qlink, "link"); /* NOTE_LINK */ DEFSYM (Qrename, "rename"); /* NOTE_RENAME */ + DEFSYM (Qrevoke, "revoke"); /* NOTE_REVOKE */ staticpro (&watch_list); -- 2.39.2