1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00

Add file notification handler for Tramp's "smb" method.

* etc/NEWS: Mention new file notification handler for Tramp "smb".

* lisp/filenotify.el (file-notify--expand-file-name): Fix the
remote case.
(file-notify-callback): Extend for "smb-notify".
(file-notify--call-handler): Fix debug message.

* lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-notify-add-watch):
* lisp/net/tramp-sh.el (tramp-sh-gio-monitor-process-filter):
Use connection property "file-monitor".

* lisp/net/tramp-smb.el (tramp-smb-file-name-handler-alist):
Use `tramp-smb-handle-file-notify-add-watch'.
(tramp-smb-handle-delete-directory): Do not error if there is a
pending deletion of a directory under file-watch.
(tramp-smb-handle-file-notify-add-watch)
(tramp-smb-notify-process-filter): New defuns.
(tramp-smb-send-command): New optional argument NOOUTPUT.
(tramp-smb-wait-for-output): Improve debug message.

* lisp/net/tramp.el (tramp-directory-watched): New defun.
(tramp-accept-process-output, tramp-wait-for-regexp):
Improve debug message.

* test/lisp/filenotify-tests.el (top): Filter also for
"smb-notify".  Set some other Tramp related variables.
(file-notify--test-wait-for-events)
(file-notify--test-with-actions-check)
(file-notify--test-with-actions): Add debug message.
(file-notify--test-cleanup, file-notify--deftest-remote):
Keep Tramp debugs buffer.
(file-notify--test-monitor): Check for "smb-notify".
(file-notify--deftest-remote): Call `file-notify-rm-all-watches'.
(file-notify--test-make-temp-name): Use a better name for parent
directory.
(file-notify--test-event-handler): Use `string-match-p'.
(file-notify--test-with-actions): Check also for the `stopped'
event as limit.
(file-notify-test03-events, file-notify-test04-autorevert)
(file-notify-test05-file-validity)
(file-notify-test07-many-events, file-notify-test08-backup)
(file-notify-test09-watched-file-in-watched-dir): Adapt tests for
"smb-notify".
(file-notify-test12-unmount): Skip for "smb-notify".
This commit is contained in:
Michael Albinus 2025-07-05 19:21:48 +02:00
parent 0a1db9b573
commit aa8afabd49
7 changed files with 283 additions and 57 deletions

View file

@ -1526,6 +1526,9 @@ can be used in parallel. Example: on both remote hosts "host1" and
This feature is experimental.
---
*** Implementation of filesystem notifications for connection method "smb".
** Diff
---

View file

@ -123,7 +123,9 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.")
(defun file-notify--expand-file-name (watch file)
"Full file name of FILE reported for WATCH."
(directory-file-name
(expand-file-name file (file-notify--watch-directory watch))))
(if (file-name-absolute-p file)
(concat (file-remote-p (file-notify--watch-directory watch)) file)
(expand-file-name file (file-notify--watch-directory watch)))))
(cl-defun file-notify--callback-inotify ((desc actions file
&optional file1-or-cookie))
@ -189,7 +191,7 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.")
"Notification callback for file name handlers."
(file-notify--handle-event
desc
;; File name handlers use gfilenotify or inotify actions.
;; File name handlers use gfilenotify, inotify or w32notify actions.
(delq nil (mapcar
(lambda (action)
(cond
@ -205,7 +207,12 @@ 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)
((memq action '(ignored unmount)) 'stopped)))
((memq action '(ignored unmount)) 'stopped)
;; w32notify actions:
((eq action 'added) 'created)
((eq action 'modified) 'changed)
((eq action 'removed) 'deleted)
((memq action '(renamed-from renamed-to)) action)))
(if (consp actions) actions (list actions))))
file file1-or-cookie))
@ -237,7 +244,7 @@ It is nil or a `file-notify--rename' defstruct where the cookie can be nil.")
(when (file-notify--watch-callback watch)
(when file-notify-debug
(message
"file-notify-callback %S %S %S %S %S %S %S"
"file-notify--call-handler %S %S %S %S %S %S %S"
desc action file file1 watch
(file-notify--watch-absolute-filename watch)
(file-notify--watch-directory watch)))

View file

@ -1516,6 +1516,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(if (not (processp p))
(tramp-error
v 'file-notify-error "Monitoring not supported for `%s'" file-name)
;; Needed for process filter.
(process-put p 'tramp-events events)
(process-put p 'tramp-watch-name localname)
(set-process-filter p #'tramp-gvfs-monitor-process-filter)
@ -1527,9 +1528,9 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(unless (process-live-p p)
(tramp-error
p 'file-notify-error "Monitoring not supported for `%s'" file-name))
;; Set "gio-file-monitor" property. We believe, that "gio
;; Set "file-monitor" property. We believe, that "gio
;; monitor" uses polling when applied for mounted files.
(tramp-set-connection-property p "gio-file-monitor" 'GPollFileMonitor)
(tramp-set-connection-property p "file-monitor" 'GPollFileMonitor)
p))))
(defun tramp-gvfs-monitor-process-filter (proc string)

View file

@ -3885,9 +3885,9 @@ Fall back to normal file name handler if no Tramp handler exists."
(throw 'doesnt-work nil))
;; Determine monitor name.
(unless (tramp-connection-property-p proc "gio-file-monitor")
(unless (tramp-connection-property-p proc "file-monitor")
(tramp-set-connection-property
proc "gio-file-monitor"
proc "file-monitor"
(cond
;; We have seen this on cygwin gio and on emba. Let's make
;; some assumptions.

View file

@ -127,10 +127,10 @@ this variable \"client min protocol=NT1\"."
"ERRnomem"
"ERRnosuchshare"
;; See /usr/include/samba-4.0/core/ntstatus.h.
;; Windows 4.0 (Windows NT), Windows 5.0 (Windows 2000),
;; Windows 5.1 (Windows XP), Windows 5.2 (Windows Server 2003),
;; Windows 6.0 (Windows Vista), Windows 6.1 (Windows 7),
;; Windows 6.3 (Windows Server 2012, Windows 10).
;; <https://learn.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version>
;; Tested with Windows NT, Windows 2000, Windows XP, Windows
;; Server 2003, Windows Vista, Windows 7, Windows Server 2012,
;; Windows 10, Windows 11.
"NT_STATUS_ACCESS_DENIED"
"NT_STATUS_ACCOUNT_LOCKED_OUT"
"NT_STATUS_BAD_NETWORK_NAME"
@ -261,7 +261,7 @@ See `tramp-actions-before-shell' for more info.")
(file-name-nondirectory . tramp-handle-file-name-nondirectory)
;; `file-name-sans-versions' performed by default handler.
(file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
(file-notify-add-watch . tramp-handle-file-notify-add-watch)
(file-notify-add-watch . tramp-smb-handle-file-notify-add-watch)
(file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
(file-notify-valid-p . tramp-handle-file-notify-valid-p)
(file-ownership-preserved-p . ignore)
@ -686,8 +686,10 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(tramp-error v 'file-error "%s `%s'" (match-string 0) directory)))
;; "rmdir" does not report an error. So we check ourselves.
(when (file-exists-p directory)
(tramp-error v 'file-error "`%s' not removed" directory)))))
;; Deletion of a watched directory could be pending.
(when (and (not (tramp-directory-watched directory))
(file-exists-p directory))
(tramp-error v 'file-error "`%s' not removed" directory)))))
(defun tramp-smb-handle-delete-file (filename &optional trash)
"Like `delete-file' for Tramp files."
@ -964,6 +966,108 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(tramp-error
v 'file-error "Cannot make local copy of file `%s'" filename)))))
;; The "notify" command has been added to smbclient 4.3.0.
(defun tramp-smb-handle-file-notify-add-watch (file-name flags _callback)
"Like `file-notify-add-watch' for Tramp files."
(setq file-name (expand-file-name file-name))
(with-parsed-tramp-file-name file-name nil
(let ((default-directory (file-name-directory file-name))
(command (format "notify %s" (tramp-smb-shell-quote-localname v)))
(events
(cond
((memq 'change flags)
'(added removed modified renamed-from renamed-to))
((memq 'attribute-change flags) '(modified))))
p)
;; Start process.
(with-tramp-saved-connection-properties
v '(" process-name" " process-buffer")
;; Set the new process properties.
(tramp-set-connection-property
v " process-name" (tramp-get-unique-process-name "smb-notify"))
(tramp-set-connection-property
v " process-buffer" (generate-new-buffer " *smb-notify*"))
(tramp-flush-connection-property v " process-exit-status")
(tramp-smb-send-command v command 'nooutput)
(setq p (tramp-get-connection-process v))
;; Return the process object as watch-descriptor.
(if (not (processp p))
(tramp-error
v 'file-notify-error
"`%s' failed to start on remote host" command)
;; Needed for process filter.
(process-put p 'tramp-events events)
(process-put p 'tramp-watch-name localname)
(set-process-filter p #'tramp-smb-notify-process-filter)
(set-process-sentinel p #'tramp-file-notify-process-sentinel)
(tramp-post-process-creation p v)
;; There might be an error if the monitor is not supported.
;; Give the filter a chance to read the output.
(while (tramp-accept-process-output p))
(unless (process-live-p p)
(tramp-error
p 'file-notify-error "Monitoring not supported for `%s'" file-name))
;; Set "file-monitor" property. The existence of the "ADMIN$"
;; share is an indication for a remote MS Windows host.
(tramp-set-connection-property
p "file-monitor"
(if (member
"ADMIN$" (directory-files (tramp-make-tramp-file-name v "/")))
'SMBWindows 'SMBSamba))
p)))))
;; FileChangeNotify subsystem was added to Smaba 4.3.0.
;; <https://www.samba.org/samba/history/samba-4.3.0.html>
(defun tramp-smb-notify-process-filter (proc string)
"Read output from \"notify\" and add corresponding `file-notify' events."
(let ((events (process-get proc 'tramp-events)))
(tramp-message proc 6 "%S\n%s" proc string)
(dolist (line (split-string string (rx (+ (any "\r\n"))) 'omit))
(catch 'next
;; Watched directory is removed.
(when (string-match-p "NT_STATUS_DELETE_PENDING" line)
(setq line (concat "0002 " (process-get proc 'tramp-watch-name))))
;; Stopped.
(when (string-match-p tramp-smb-prompt line)
(throw 'next 'next))
;; Check, whether there is a problem.
(unless (string-match
(rx bol (group (+ digit))
(+ blank) (group (+ (not (any "\r\n")))))
line)
(tramp-error proc 'file-notify-error line))
;; See libsmbclient.h.
;; #define SMBC_NOTIFY_ACTION_ADDED 1
;; #define SMBC_NOTIFY_ACTION_REMOVED 2
;; #define SMBC_NOTIFY_ACTION_MODIFIED 3
;; #define SMBC_NOTIFY_ACTION_OLD_NAME 4
;; #define SMBC_NOTIFY_ACTION_NEW_NAME 5
;; #define SMBC_NOTIFY_ACTION_ADDED_STREAM 6
;; #define SMBC_NOTIFY_ACTION_REMOVED_STREAM 7
;; #define SMBC_NOTIFY_ACTION_MODIFIED_STREAM 8
(let ((object
(list
proc
(pcase (string-to-number (match-string 1 line))
(1 '(added))
(2 '(removed))
(3 '(modified))
(4 '(renamed-from))
(5 '(renamed-to))
;; Ignore stream events.
(_ (throw 'next 'next)))
(string-replace "\\" "/" (match-string 2 line)))))
;; Add an Emacs event now.
;; `insert-special-event' exists since Emacs 31.
(when (member (caadr object) events)
(tramp-compat-funcall
(if (fboundp 'insert-special-event)
'insert-special-event
(lookup-key special-event-map [file-notify]))
`(file-notify ,object file-notify-callback))))))))
;; This function should return "foo/" for directories and "bar" for
;; files.
(defun tramp-smb-handle-file-name-all-completions (filename directory)
@ -1823,13 +1927,14 @@ are listed. Result is the list (LOCALNAME MODE SIZE MTIME)."
;; Connection functions.
(defun tramp-smb-send-command (vec command)
(defun tramp-smb-send-command (vec command &optional nooutput)
"Send the COMMAND to connection VEC.
Returns nil if there has been an error message from smbclient."
Returns nil if there has been an error message from smbclient. The
function waits for output unless NOOUTPUT is set."
(tramp-smb-maybe-open-connection vec)
(tramp-message vec 6 "%s" command)
(tramp-send-string vec command)
(tramp-smb-wait-for-output vec))
(unless nooutput (tramp-smb-wait-for-output vec)))
(defun tramp-smb-maybe-open-connection (vec &optional argument)
"Maybe open a connection to HOST, log in as USER, using `tramp-smb-program'.
@ -2003,7 +2108,7 @@ Removes smb prompt. Returns nil if an error message has appeared."
(while (not (search-forward-regexp tramp-smb-prompt nil t))
(while (tramp-accept-process-output p))
(goto-char (point-min)))
(tramp-message vec 6 "\n%s" (buffer-string))
(tramp-message vec 6 "%S\n%s" p (buffer-string))
;; Remove prompt.
(goto-char (point-min))
@ -2084,4 +2189,6 @@ Removes smb prompt. Returns nil if an error message has appeared."
;;
;; * Keep a permanent connection process for `process-file'.
;; * Implement "scopy" (since Samba 4.3.0).
;;; tramp-smb.el ends here

View file

@ -5743,6 +5743,16 @@ of."
(tramp-message proc 5 "Sentinel called: `%S' `%s'" proc event)
(file-notify-rm-watch proc)))
(defun tramp-directory-watched (directory)
"Check, whether a directory is watched."
(let (result)
(dolist (p (process-list) result)
(setq result
(or result
(and-let* ((dir (process-get p 'tramp-watch-name))
((string-equal
dir (tramp-file-local-name directory))))))))))
;;; Functions for establishing connection:
;; The following functions are actions to be taken when seeing certain
@ -6120,7 +6130,7 @@ If the user quits via `C-g', it is propagated up to `tramp-file-name-handler'."
(if (with-local-quit
(setq result (accept-process-output proc 0 nil t)) t)
(tramp-message
proc 10 "%s %s %s\n%s"
proc 10 "%S %S %s\n%s"
proc (process-status proc) result (buffer-string))
;; Propagate quit.
(keyboard-quit)))
@ -6197,7 +6207,7 @@ nil."
;; timeout of sudo. The process buffer does not exist any longer then.
(ignore-errors
(tramp-message
proc 6 "\n%s" (tramp-get-buffer-string (process-buffer proc))))
proc 6 "%S\n%s" proc (tramp-get-buffer-string (process-buffer proc))))
(unless found
(if timeout
(tramp-error

View file

@ -37,7 +37,7 @@
;; of a respective command. The first command found is used. In
;; order to use a dedicated one, the environment variable
;; $REMOTE_FILE_NOTIFY_LIBRARY shall be set, possible values are
;; "inotifywait", "gio-monitor" and "gvfs-monitor-dir".
;; "inotifywait", "gio-monitor", "gvfs-monitor-dir", and "smb-notify".
;; Local file-notify libraries are auto-detected during Emacs
;; configuration. This can be changed with a respective configuration
@ -58,7 +58,7 @@
;; Filter suppressed remote file-notify libraries.
(when (stringp (getenv "REMOTE_FILE_NOTIFY_LIBRARY"))
(dolist (lib '("inotifywait" "gio-monitor" "gvfs-monitor-dir"))
(dolist (lib '("inotifywait" "gio-monitor" "gvfs-monitor-dir" "smb-notify"))
(unless (string-equal (getenv "REMOTE_FILE_NOTIFY_LIBRARY") lib)
(add-to-list 'tramp-connection-properties `(nil ,lib nil)))))
@ -104,6 +104,9 @@ There are different timeouts for local and remote file notification libraries."
TIMEOUT is the maximum time to wait for, in seconds."
`(with-timeout (,timeout (ignore))
(while (null ,until)
(when file-notify-debug
(message "file-notify--test-wait-for-events received: %s"
(file-notify--test-event-actions)))
(file-notify--test-wait-event))))
(defun file-notify--test-no-descriptors ()
@ -159,7 +162,7 @@ Return nil when any other file notification watch is still active."
(ignore-errors
(when (file-remote-p temporary-file-directory)
(tramp-cleanup-connection
(tramp-dissect-file-name temporary-file-directory) nil 'keep-password)))
(tramp-dissect-file-name temporary-file-directory) t 'keep-password)))
(when (hash-table-p file-notify-descriptors)
(clrhash file-notify-descriptors))
@ -176,9 +179,13 @@ Return nil when any other file notification watch is still active."
file-notify--test-events nil
file-notify--test-monitors nil))
(setq file-notify-debug nil
(setq auth-source-cache-expiry nil
auth-source-save-behavior nil
file-notify-debug nil
password-cache-expiry nil
;; tramp-verbose (if (getenv "EMACS_EMBA_CI") 10 0)
remote-file-name-inhibit-cache nil
tramp-allow-unsafe-temporary-files t
tramp-cache-read-persistent-data t ;; For auth-sources.
tramp-verbose 0
;; When the remote user id is 0, Tramp refuses unsafe temporary files.
tramp-allow-unsafe-temporary-files
@ -241,13 +248,17 @@ watch descriptor."
;; We cache the result, because after `file-notify-rm-watch',
;; `gfile-monitor-name' does not return a proper result anymore.
;; But we still need this information. So far, we know the monitors
;; GFamFileMonitor (gfilenotify on cygwin), GFamDirectoryMonitor
;; (gfilenotify on Solaris), GInotifyFileMonitor (gfilenotify and
;; gio on GNU/Linux), GKqueueFileMonitor (gfilenotify and gio on
;; FreeBSD) and GPollFileMonitor (gio on cygwin).
;; - GFamFileMonitor (gfilenotify on cygwin)
;; - GFamDirectoryMonitor (gfilenotify on Solaris)
;; - GInotifyFileMonitor (gfilenotify and gio on GNU/Linux)
;; - GKqueueFileMonitor (gfilenotify and gio on FreeBSD)
;; - GPollFileMonitor (gio on cygwin)
;; - SMBSamba (smb-notify on Samba server)
;; - SMBWindows (smb-notify on MS Windows).
(when file-notify--test-desc
(or (alist-get file-notify--test-desc file-notify--test-monitors)
(when (member (file-notify--test-library) '("gfilenotify" "gio"))
(when (member
(file-notify--test-library) '("gfilenotify" "gio" "smb-notify"))
(add-to-list
'file-notify--test-monitors
(cons file-notify--test-desc
@ -255,10 +266,10 @@ watch descriptor."
;; `file-notify--test-desc' is the connection process.
(progn
(while (not (tramp-connection-property-p
file-notify--test-desc "gio-file-monitor"))
file-notify--test-desc "file-monitor"))
(accept-process-output file-notify--test-desc 0))
(tramp-get-connection-property
file-notify--test-desc "gio-file-monitor" nil))
file-notify--test-desc "file-monitor" nil))
(and (functionp 'gfile-monitor-name)
(gfile-monitor-name file-notify--test-desc)))))
;; If we don't know the monitor, there are good chances the
@ -282,7 +293,8 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
;; Needs further investigation.
(skip-when (string-equal (file-notify--test-library) "gio"))
(tramp-cleanup-connection
(tramp-dissect-file-name temporary-file-directory) nil 'keep-password)
(tramp-dissect-file-name temporary-file-directory) t 'keep-password)
(file-notify-rm-all-watches)
(funcall (ert-test-body ert-test)))))
(ert-deftest file-notify-test00-availability ()
@ -315,7 +327,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(unless (stringp file-notify--test-tmpdir)
(setq file-notify--test-tmpdir
(expand-file-name
(make-temp-name "file-notify-test") temporary-file-directory)))
(make-temp-name "file-notify-test-parent") temporary-file-directory)))
(unless (file-directory-p file-notify--test-tmpdir)
(make-directory file-notify--test-tmpdir))
(expand-file-name
@ -558,7 +570,7 @@ and the event to `file-notify--test-events'."
(result
(ert-run-test (make-ert-test :body 'file-notify--test-event-test))))
;; Do not add lock files, this would confuse the checks.
(unless (string-match
(unless (string-match-p
(regexp-quote ".#")
(file-notify--test-event-file file-notify--test-event))
(when file-notify-debug
@ -575,6 +587,8 @@ and the event to `file-notify--test-events'."
(defun file-notify--test-with-actions-check (actions)
"Check whether received actions match one of the ACTIONS alternatives."
(when file-notify-debug
(message "file-notify--test-with-actions-check"))
(let (result)
(dolist (elt actions result)
(setq result
@ -632,11 +646,14 @@ delivered."
(not (input-pending-p)))
(setq file-notify--test-events nil
file-notify--test-results nil)
(when file-notify-debug
(message "file-notify--test-with-actions expected: %s" actions))
,@body
(file-notify--test-wait-for-events
;; More actions need more time. Use some fudge factor.
(* (ceiling max-length 100) (file-notify--test-timeout))
(= max-length (length file-notify--test-events)))
(or (= max-length (length file-notify--test-events))
(memq 'stopped (file-notify--test-event-actions))))
;; Check the result sequence just to make sure that all actions
;; are as expected.
(dolist (result file-notify--test-results)
@ -666,6 +683,9 @@ delivered."
'(change) #'file-notify--test-event-handler)))
(file-notify--test-with-actions
(cond
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(created changed changed changed deleted stopped))
;; GFam{File,Directory}Monitor, GKqueueFileMonitor and
;; GPollFileMonitor do not report the `changed' event.
((memq (file-notify--test-monitor)
@ -697,6 +717,9 @@ delivered."
'(change) #'file-notify--test-event-handler)))
(file-notify--test-with-actions
(cond
;; SMBSamba reports four `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(changed changed changed changed deleted stopped))
;; GFam{File,Directory}Monitor and GPollFileMonitor do
;; not detect the `changed' event reliably.
((memq (file-notify--test-monitor)
@ -739,6 +762,9 @@ delivered."
;; events for the watched directory.
((string-equal (file-notify--test-library) "w32notify")
'(created changed deleted))
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(created changed changed changed deleted deleted stopped))
;; On emba, `deleted' and `stopped' events of the
;; directory are not detected.
((getenv "EMACS_EMBA_CI")
@ -789,6 +815,10 @@ delivered."
'(created changed created changed
changed changed changed
deleted deleted))
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(created changed changed changed created changed changed changed
deleted deleted deleted stopped))
;; There are three `deleted' events, for two files and
;; for the directory. Except for
;; GFam{File,Directory}Monitor, GPollFileMonitor and
@ -843,6 +873,10 @@ delivered."
;; events for the watched directory.
((string-equal (file-notify--test-library) "w32notify")
'(created changed renamed deleted))
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(created changed changed changed
renamed changed changed deleted deleted stopped))
;; On emba, `deleted' and `stopped' events of the
;; directory are not detected.
((getenv "EMACS_EMBA_CI")
@ -897,6 +931,14 @@ delivered."
((string-equal (file-notify--test-library) "w32notify")
'((changed changed)
(changed changed changed changed)))
;; SMBWindows does not distinguish between `changed' and
;; `attribute-changed'.
((eq (file-notify--test-monitor) 'SMBWindows)
'(changed changed))
;; SMBSamba does not distinguish between `changed' and
;; `attribute-changed'.
((eq (file-notify--test-monitor) 'SMBSamba)
'(changed changed changed changed))
;; GFam{File,Directory}Monitor, GKqueueFileMonitor and
;; GPollFileMonitor do not report the `attribute-changed'
;; event.
@ -948,6 +990,7 @@ delivered."
(timeout (if (file-remote-p temporary-file-directory)
60 ; FIXME: can this be shortened?
(* auto-revert-interval 2.5)))
(text-quoting-style 'grave)
buf)
(auto-revert-set-timer)
(unwind-protect
@ -995,10 +1038,11 @@ delivered."
;; Check, that the buffer has been reverted.
(file-notify--test-wait-for-events
timeout
(string-match
(format-message "Reverting buffer `%s'." (buffer-name buf))
(string-match-p
(rx bol "Reverting buffer `"
(literal (buffer-name buf)) "'" eol)
captured-messages))
(should (string-match "another text" (buffer-string)))))
(should (string-match-p "another text" (buffer-string)))))
;; Stop file notification. Autorevert shall still work via polling.
(file-notify-rm-watch auto-revert-notify-watch-descriptor)
@ -1020,10 +1064,11 @@ delivered."
;; Check, that the buffer has been reverted.
(file-notify--test-wait-for-events
timeout
(string-match
(format-message "Reverting buffer `%s'." (buffer-name buf))
(string-match-p
(rx bol "Reverting buffer `"
(literal (buffer-name buf)) "'" eol)
captured-messages))
(should (string-match "foo bla" (buffer-string)))))
(should (string-match-p "foo bla" (buffer-string)))))
;; Stop autorevert, in order to cleanup descriptor.
(auto-revert-mode -1))
@ -1077,6 +1122,9 @@ delivered."
(should (file-notify-valid-p file-notify--test-desc))
(file-notify--test-with-actions
(cond
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(changed changed changed changed deleted stopped))
;; GFam{File,Directory}Monitor do not
;; detect the `changed' event reliably.
((memq (file-notify--test-monitor)
@ -1093,6 +1141,7 @@ delivered."
"another text" nil file-notify--test-tmpfile nil 'no-message)
(file-notify--test-wait-event)
(delete-file file-notify--test-tmpfile))
(file-notify--test-wait-event)
;; After deleting the file, the descriptor is not valid anymore.
(should-not (file-notify-valid-p file-notify--test-desc))
(file-notify-rm-watch file-notify--test-desc)
@ -1122,6 +1171,9 @@ delivered."
;; events for the watched directory.
((string-equal (file-notify--test-library) "w32notify")
'(created changed deleted))
;; SMBSamba reports three `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(created changed changed changed deleted deleted stopped))
;; There are two `deleted' events, for the file and for
;; the directory. Except for
;; GFam{File,Directory}Monitor, GPollFileMonitor and
@ -1247,7 +1299,14 @@ delivered."
(push (expand-file-name (format "y%d" i)) target-file-list))
(push (expand-file-name (format "y%d" i)) source-file-list)
(push (expand-file-name (format "x%d" i)) target-file-list)))
(file-notify--test-with-actions (make-list (+ n n) 'created)
(file-notify--test-with-actions
(cond
;; SMBSamba fires both `created' and `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
(let (r)
(dotimes (_i (+ n n) r)
(setq r (append '(created changed) r)))))
(t (make-list (+ n n) 'created)))
(let ((source-file-list source-file-list)
(target-file-list target-file-list))
(while (and source-file-list target-file-list)
@ -1260,18 +1319,26 @@ delivered."
;; w32notify fires both `deleted' and `renamed' events.
((string-equal (file-notify--test-library) "w32notify")
(let (r)
(dotimes (_i n)
(setq r (append '(deleted renamed) r)))
r))
;; GFam{File,Directory}Monitor and GPollFileMonitor fire
(dotimes (_i n r)
(setq r (append '(deleted renamed) r)))))
;; SMBWindows fires both `changed' and `deleted' events.
((eq (file-notify--test-monitor) 'SMBWindows)
(let (r)
(dotimes (_i n r)
(setq r (append '(changed deleted) r)))))
;; SMBSamba fires both `changed' and `deleted' events.
((eq (file-notify--test-monitor) 'SMBSamba)
(let (r)
(dotimes (_i n r)
(setq r (append '(changed changed deleted) r)))))
;; GFam{File,Directory}Monitor and GPollFileMonitor fire
;; `changed' and `deleted' events, sometimes in random
;; order.
((memq (file-notify--test-monitor)
'(GFamFileMonitor GFamDirectoryMonitor GPollFileMonitor))
(let (r)
(dotimes (_i n)
(setq r (append '(changed deleted) r)))
(cons :random r)))
(dotimes (_i n (cons :random r))
(setq r (append '(changed deleted) r)))))
(t (make-list n 'renamed)))
(let ((source-file-list source-file-list)
(target-file-list target-file-list))
@ -1315,6 +1382,9 @@ delivered."
(should (file-notify-valid-p file-notify--test-desc))
(file-notify--test-with-actions
(cond
;; SMBSamba reports four `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(changed changed changed changed))
;; GKqueueFileMonitor does not report the `changed' event.
((eq (file-notify--test-monitor) 'GKqueueFileMonitor) '())
;; There could be one or two `changed' events.
@ -1354,6 +1424,12 @@ delivered."
(should (file-notify-valid-p file-notify--test-desc))
(file-notify--test-with-actions
(cond
;; SMBWindows reports two `changed' events.
((eq (file-notify--test-monitor) 'SMBWindows)
'(changed changed))
;; SMBSamba reports four `changed' events.
((eq (file-notify--test-monitor) 'SMBSamba)
'(changed changed changed changed))
;; GFam{File,Directory}Monitor and GPollFileMonitor
;; report only the `changed' event.
((memq (file-notify--test-monitor)
@ -1438,7 +1514,27 @@ the file watch."
(file-notify--test-with-actions
;; There could be one or two `changed' events.
(list
;; cygwin.
;; SMBSamba. Sometimes, tha last `changed' event is
;; missing, so we add two alternatives.
(append
'(:random)
;; Just the file monitor.
(make-list (* (/ n 2) 5) 'changed)
;; Just the directory monitor. Strange, not all
;; `changed' events do arrive.
(make-list (1- (* (/ n 2) 10)) 'changed)
(make-list (/ n 2) 'created)
(make-list (/ n 2) 'created))
(append
'(:random)
;; Just the file monitor.
(make-list (* (/ n 2) 5) 'changed)
;; Just the directory monitor. This is the alternative
;; with all `changed' events.
(make-list (* (/ n 2) 10) 'changed)
(make-list (/ n 2) 'created)
(make-list (/ n 2) 'created))
;; cygwin.
(append
'(:random)
(make-list (/ n 2) 'changed)
@ -1482,7 +1578,9 @@ the file watch."
;; directory and the file monitor. The `stopped' event is
;; from the file monitor. It's undecided in which order the
;; directory and the file monitor are triggered.
(file-notify--test-with-actions '(:random deleted deleted stopped)
(file-notify--test-with-actions
'((:random deleted deleted stopped)
(:random deleted deleted deleted stopped))
(delete-file file-notify--test-tmpfile1))
(should (file-notify-valid-p file-notify--test-desc1))
(should-not (file-notify-valid-p file-notify--test-desc2))
@ -1715,8 +1813,8 @@ the file watch."
"Check that file notification stop after unmounting the filesystem."
:tags '(:expensive-test)
(skip-unless (file-notify--test-local-enabled))
;; This test does not work for w32notify.
(skip-when (string-equal (file-notify--test-library) "w32notify"))
;; This test does not work for w32notify snd smb-notify.
(skip-when (member (file-notify--test-library) '("w32notify" "smb-notify")))
(unwind-protect
(progn
@ -1789,8 +1887,8 @@ the file watch."
;; the missing directory monitor.
;; * For w32notify, no `deleted' and `stopped' events arrive when a
;; directory is removed.
;; * For cygwin and w32notify, no `attribute-changed' events arrive.
;; They send `changed' events instead.
;; * For cygwin, w32notify, and smb-notify, no `attribute-changed'
;; events arrive. They send `changed' events instead.
;; * cygwin does not send all expected `changed' and `deleted' events.
;; Probably due to timing issues.