aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2015-09-20 18:44:36 +0200
committerMichael Albinus2015-09-20 18:44:36 +0200
commitf5bdcb3221ba28326b47210773d84c49cc9b4a1e (patch)
treef316feaf1d548b157ef1a3cfcbb831864e50c003
parentab11a1cf27ebe3791df45cccde3c851affd184dd (diff)
downloademacs-f5bdcb3221ba28326b47210773d84c49cc9b4a1e.tar.gz
emacs-f5bdcb3221ba28326b47210773d84c49cc9b4a1e.zip
Improve file notifications, especially for Tramp
* doc/lispref/files.texi (Magic File Names): Mention `file-notify-valid-p'. * doc/lispref/os.texi (File Notifications): Describe `file-notify-valid-p'. * etc/NEWS: Add `file-notify-valid-p'. * lisp/net/tramp-gvfs.el (tramp-gvfs-handle-file-notify-add-watch): Improve implementation. (tramp-gvfs-monitor-file-process-filter): Rename from `tramp-gvfs-file-gvfs-monitor-file-process-filter'. Delete process if appropriate. * lisp/net/tramp-sh.el (tramp-sh-handle-file-notify-add-watch): Improve implementation. (tramp-sh-gvfs-monitor-dir-process-filter): Rename from `tramp-sh-file-gvfs-monitor-dir-process-filter'. Delete process if appropriate. (tramp-sh-inotifywait-process-filter): Rename from `tramp-sh-file-inotifywait-process-filter'. Delete process if appropriate. * lisp/net/tramp.el (tramp-handle-file-notify-rm-watch): Use `delete-process' (tramp-handle-file-notify-valid-p): Check also, that file or directory to be watched still exists. * test/automated/file-notify-tests.el (file-notify--test-timeout): New defun. Use it at all places a timeout is needed. (file-notify--test-cleanup): Delete directories recursively. Cleanup also Tramp connections. (file-notify-test02-events): Add tests for `attribute-change'. (file-notify-test04-file-validity, file-notify-test05-dir-validity): Add tests for `file-notify-rm-watch'.
-rw-r--r--doc/lispref/files.texi2
-rw-r--r--doc/lispref/os.texi11
-rw-r--r--etc/NEWS13
-rw-r--r--lisp/net/tramp-gvfs.el49
-rw-r--r--lisp/net/tramp-sh.el60
-rw-r--r--lisp/net/tramp.el12
-rw-r--r--test/automated/file-notify-tests.el140
7 files changed, 220 insertions, 67 deletions
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index ffc7936107b..db2ecc08f95 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -2854,6 +2854,7 @@ first, before handlers for jobs such as remote file access.
2854@code{file-name-nondirectory}, 2854@code{file-name-nondirectory},
2855@code{file-name-sans-versions}, @code{file-newer-than-file-p}, 2855@code{file-name-sans-versions}, @code{file-newer-than-file-p},
2856@code{file-notify-add-watch}, @code{file-notify-rm-watch}, 2856@code{file-notify-add-watch}, @code{file-notify-rm-watch},
2857@code{file-notify-valid-p},
2857@code{file-ownership-preserved-p}, 2858@code{file-ownership-preserved-p},
2858@code{file-readable-p}, @code{file-regular-p}, 2859@code{file-readable-p}, @code{file-regular-p},
2859@code{file-remote-p}, @code{file-selinux-context}, 2860@code{file-remote-p}, @code{file-selinux-context},
@@ -2907,6 +2908,7 @@ first, before handlers for jobs such as remote file access.
2907@code{file-name-nondirec@discretionary{}{}{}tory}, 2908@code{file-name-nondirec@discretionary{}{}{}tory},
2908@code{file-name-sans-versions}, @code{file-newer-than-file-p}, 2909@code{file-name-sans-versions}, @code{file-newer-than-file-p},
2909@code{file-notify-add-watch}, @code{file-notify-rm-watch}, 2910@code{file-notify-add-watch}, @code{file-notify-rm-watch},
2911@code{file-notify-valid-p},
2910@code{file-ownership-pre@discretionary{}{}{}served-p}, 2912@code{file-ownership-pre@discretionary{}{}{}served-p},
2911@code{file-readable-p}, @code{file-regular-p}, 2913@code{file-readable-p}, @code{file-regular-p},
2912@code{file-remote-p}, @code{file-selinux-context}, 2914@code{file-remote-p}, @code{file-selinux-context},
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index cb583038979..f5eecb2d569 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -2692,6 +2692,17 @@ Removes an existing file watch specified by its @var{descriptor}.
2692@code{file-notify-add-watch}. 2692@code{file-notify-add-watch}.
2693@end defun 2693@end defun
2694 2694
2695@defun file-notify-valid-p descriptor
2696Checks a watch specified by its @var{descriptor} for validity.
2697@var{descriptor} should be an object returned by
2698@code{file-notify-add-watch}.
2699
2700A watch can become invalid if the file or directory it watches is
2701deleted, or if the watcher thread exits abnormally for any other
2702reason. Removing the watch by calling @code{file-notify-rm-watch}
2703also makes it invalid.
2704@end defun
2705
2695@node Dynamic Libraries 2706@node Dynamic Libraries
2696@section Dynamically Loaded Libraries 2707@section Dynamically Loaded Libraries
2697@cindex dynamic libraries 2708@cindex dynamic libraries
diff --git a/etc/NEWS b/etc/NEWS
index b5c52e311ee..01b3ed3f2c1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -412,7 +412,6 @@ the old behavior -- *shell* buffer displays in current window -- use
412(add-to-list 'display-buffer-alist 412(add-to-list 'display-buffer-alist
413 '("^\\*shell\\*$" . (display-buffer-same-window))). 413 '("^\\*shell\\*$" . (display-buffer-same-window))).
414 414
415
416** EIEIO 415** EIEIO
417+++ 416+++
418*** The `:protection' slot option is not obeyed any more. 417*** The `:protection' slot option is not obeyed any more.
@@ -657,11 +656,17 @@ plist will contain a :peer element that has the output of
657 656
658** Tramp 657** Tramp
659 658
659+++
660*** New connection method "nc", which allows to access dumb busyboxes. 660*** New connection method "nc", which allows to access dumb busyboxes.
661 661
662+++
662*** Method-specific parameters can be overwritten now with variable 663*** Method-specific parameters can be overwritten now with variable
663`tramp-connection-properties'. 664`tramp-connection-properties'.
664 665
666---
667*** Handler for `file-notify-valid-p' for remote machines that support
668filesystem notifications.
669
665** SQL mode 670** SQL mode
666 671
667*** New user variable `sql-default-directory' enables remote 672*** New user variable `sql-default-directory' enables remote
@@ -822,9 +827,15 @@ make the new option `eshell-destroy-buffer-when-process-dies' non-nil.
822** tar-mode: new `tar-new-entry' command, allowing for new members to 827** tar-mode: new `tar-new-entry' command, allowing for new members to
823be added to the archive. 828be added to the archive.
824 829
830---
825** Autorevert: dired buffers are also auto-reverted via file 831** Autorevert: dired buffers are also auto-reverted via file
826notifications, if Emacs is compiled with file notification support. 832notifications, if Emacs is compiled with file notification support.
827 833
834+++
835** File Notifications: the new function `file-notify-valid-p' checks,
836whether a file notification descriptor still corresponds to an
837activate watch.
838
828** Obsolete packages 839** Obsolete packages
829 840
830--- 841---
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index cf42b5951f7..b7b0a1c016f 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -1003,27 +1003,48 @@ file names."
1003 v (concat localname filename) 1003 v (concat localname filename)
1004 "file-name-all-completions" result)))))))) 1004 "file-name-all-completions" result))))))))
1005 1005
1006(defun tramp-gvfs-handle-file-notify-add-watch (file-name _flags _callback) 1006(defun tramp-gvfs-handle-file-notify-add-watch (file-name flags _callback)
1007 "Like `file-notify-add-watch' for Tramp files." 1007 "Like `file-notify-add-watch' for Tramp files."
1008 (setq file-name (expand-file-name file-name)) 1008 (setq file-name (expand-file-name file-name))
1009 (with-parsed-tramp-file-name file-name nil 1009 (with-parsed-tramp-file-name file-name nil
1010 (let ((p (start-process 1010 ;; We cannot watch directories, because `gvfs-monitor-dir' is not
1011 "gvfs-monitor-file" (generate-new-buffer " *gvfs-monitor-file*") 1011 ;; supported for gvfs-mounted directories.
1012 "gvfs-monitor-file" (tramp-gvfs-url-file-name file-name)))) 1012 (when (file-directory-p file-name)
1013 (tramp-error
1014 v 'file-notify-error "Monitoring not supported for `%s'" file-name))
1015 (let* ((default-directory (file-name-directory file-name))
1016 (events
1017 (cond
1018 ((and (memq 'change flags) (memq 'attribute-change flags))
1019 '(created changed changes-done-hint moved deleted
1020 attribute-changed))
1021 ((memq 'change flags)
1022 '(created changed changes-done-hint moved deleted))
1023 ((memq 'attribute-change flags) '(attribute-changed))))
1024 (p (start-process
1025 "gvfs-monitor-file" (generate-new-buffer " *gvfs-monitor-file*")
1026 "gvfs-monitor-file" (tramp-gvfs-url-file-name file-name))))
1013 (if (not (processp p)) 1027 (if (not (processp p))
1014 (tramp-error 1028 (tramp-error
1015 v 'file-notify-error "gvfs-monitor-file failed to start") 1029 v 'file-notify-error "Monitoring not supported for `%s'" file-name)
1016 (tramp-message 1030 (tramp-message
1017 v 6 "Run `%s', %S" (mapconcat 'identity (process-command p) " ") p) 1031 v 6 "Run `%s', %S" (mapconcat 'identity (process-command p) " ") p)
1018 (tramp-set-connection-property p "vector" v) 1032 (tramp-set-connection-property p "vector" v)
1033 (tramp-compat-process-put p 'events events)
1034 (tramp-compat-process-put p 'watch-name localname)
1019 (tramp-compat-set-process-query-on-exit-flag p nil) 1035 (tramp-compat-set-process-query-on-exit-flag p nil)
1020 (set-process-filter p 'tramp-gvfs-file-gvfs-monitor-file-process-filter) 1036 (set-process-filter p 'tramp-gvfs-monitor-file-process-filter)
1021 (with-current-buffer (process-buffer p) 1037 ;; There might be an error if the monitor is not supported.
1022 (setq default-directory (file-name-directory file-name))) 1038 ;; Give the filter a chance to read the output.
1039 (tramp-accept-process-output p 1)
1040 (unless (memq (process-status p) '(run open))
1041 (tramp-error
1042 v 'file-notify-error "Monitoring not supported for `%s'" file-name))
1023 p)))) 1043 p))))
1024 1044
1025(defun tramp-gvfs-file-gvfs-monitor-file-process-filter (proc string) 1045(defun tramp-gvfs-monitor-file-process-filter (proc string)
1026 "Read output from \"gvfs-monitor-file\" and add corresponding file-notify events." 1046 "Read output from \"gvfs-monitor-file\" and add corresponding \
1047file-notify events."
1027 (let* ((rest-string (tramp-compat-process-get proc 'rest-string)) 1048 (let* ((rest-string (tramp-compat-process-get proc 'rest-string))
1028 (dd (with-current-buffer (process-buffer proc) default-directory)) 1049 (dd (with-current-buffer (process-buffer proc) default-directory))
1029 (ddu (regexp-quote (tramp-gvfs-url-file-name dd)))) 1050 (ddu (regexp-quote (tramp-gvfs-url-file-name dd))))
@@ -1034,6 +1055,8 @@ file names."
1034 ;; Attribute change is returned in unused wording. 1055 ;; Attribute change is returned in unused wording.
1035 string (tramp-compat-replace-regexp-in-string 1056 string (tramp-compat-replace-regexp-in-string
1036 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string)) 1057 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string))
1058 (when (string-match "Monitoring not supported" string)
1059 (delete-process proc))
1037 1060
1038 (while (string-match 1061 (while (string-match
1039 (concat "^[\n\r]*" 1062 (concat "^[\n\r]*"
@@ -1041,10 +1064,10 @@ file names."
1041 "File = \\([^\n\r]+\\)[\n\r]+" 1064 "File = \\([^\n\r]+\\)[\n\r]+"
1042 "Event = \\([^[:blank:]]+\\)[\n\r]+") 1065 "Event = \\([^[:blank:]]+\\)[\n\r]+")
1043 string) 1066 string)
1044 (let ((action (intern-soft 1067 (let ((file (match-string 1 string))
1068 (action (intern-soft
1045 (tramp-compat-replace-regexp-in-string 1069 (tramp-compat-replace-regexp-in-string
1046 "_" "-" (downcase (match-string 2 string))))) 1070 "_" "-" (downcase (match-string 2 string))))))
1047 (file (match-string 1 string)))
1048 (setq string (replace-match "" nil nil string)) 1071 (setq string (replace-match "" nil nil string))
1049 ;; File names are returned as URL paths. We must convert them. 1072 ;; File names are returned as URL paths. We must convert them.
1050 (when (string-match ddu file) 1073 (when (string-match ddu file)
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 206ddfbfb55..433b2ba09c7 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -3722,12 +3722,12 @@ Fall back to normal file name handler if no Tramp handler exists."
3722 "Like `file-notify-add-watch' for Tramp files." 3722 "Like `file-notify-add-watch' for Tramp files."
3723 (setq file-name (expand-file-name file-name)) 3723 (setq file-name (expand-file-name file-name))
3724 (with-parsed-tramp-file-name file-name nil 3724 (with-parsed-tramp-file-name file-name nil
3725 (let* ((default-directory (file-name-directory file-name)) 3725 (let ((default-directory (file-name-directory file-name))
3726 command events filter p sequence) 3726 command events filter p sequence)
3727 (cond 3727 (cond
3728 ;; gvfs-monitor-dir. 3728 ;; gvfs-monitor-dir.
3729 ((setq command (tramp-get-remote-gvfs-monitor-dir v)) 3729 ((setq command (tramp-get-remote-gvfs-monitor-dir v))
3730 (setq filter 'tramp-sh-file-gvfs-monitor-dir-process-filter 3730 (setq filter 'tramp-sh-gvfs-monitor-dir-process-filter
3731 events 3731 events
3732 (cond 3732 (cond
3733 ((and (memq 'change flags) (memq 'attribute-change flags)) 3733 ((and (memq 'change flags) (memq 'attribute-change flags))
@@ -3739,16 +3739,16 @@ Fall back to normal file name handler if no Tramp handler exists."
3739 sequence `(,command ,localname))) 3739 sequence `(,command ,localname)))
3740 ;; inotifywait. 3740 ;; inotifywait.
3741 ((setq command (tramp-get-remote-inotifywait v)) 3741 ((setq command (tramp-get-remote-inotifywait v))
3742 (setq filter 'tramp-sh-file-inotifywait-process-filter 3742 (setq filter 'tramp-sh-inotifywait-process-filter
3743 events 3743 events
3744 (cond 3744 (cond
3745 ((and (memq 'change flags) (memq 'attribute-change flags)) 3745 ((and (memq 'change flags) (memq 'attribute-change flags))
3746 (concat "create,modify,move,moved_from,moved_to,move_self," 3746 (concat "create,modify,move,moved_from,moved_to,move_self,"
3747 "delete,delete_self,attrib")) 3747 "delete,delete_self,attrib,ignored"))
3748 ((memq 'change flags) 3748 ((memq 'change flags)
3749 (concat "create,modify,move,moved_from,moved_to,move_self," 3749 (concat "create,modify,move,moved_from,moved_to,move_self,"
3750 "delete,delete_self")) 3750 "delete,delete_self,ignored"))
3751 ((memq 'attribute-change flags) "attrib")) 3751 ((memq 'attribute-change flags) "attrib,ignored"))
3752 sequence `(,command "-mq" "-e" ,events ,localname))) 3752 sequence `(,command "-mq" "-e" ,events ,localname)))
3753 ;; None. 3753 ;; None.
3754 (t (tramp-error 3754 (t (tramp-error
@@ -3770,13 +3770,20 @@ Fall back to normal file name handler if no Tramp handler exists."
3770 (mapconcat 'identity sequence " ")) 3770 (mapconcat 'identity sequence " "))
3771 (tramp-message v 6 "Run `%s', %S" (mapconcat 'identity sequence " ") p) 3771 (tramp-message v 6 "Run `%s', %S" (mapconcat 'identity sequence " ") p)
3772 (tramp-set-connection-property p "vector" v) 3772 (tramp-set-connection-property p "vector" v)
3773 ;; Needed for `tramp-sh-file-gvfs-monitor-dir-process-filter'. 3773 ;; Needed for `tramp-sh-gvfs-monitor-dir-process-filter'.
3774 (tramp-compat-process-put p 'events events) 3774 (tramp-compat-process-put p 'events events)
3775 (tramp-compat-process-put p 'watch-name localname)
3775 (tramp-compat-set-process-query-on-exit-flag p nil) 3776 (tramp-compat-set-process-query-on-exit-flag p nil)
3776 (set-process-filter p filter) 3777 (set-process-filter p filter)
3778 ;; There might be an error if the monitor is not supported.
3779 ;; Give the filter a chance to read the output.
3780 (tramp-accept-process-output p 1)
3781 (unless (memq (process-status p) '(run open))
3782 (tramp-error
3783 v 'file-notify-error "Monitoring not supported for `%s'" file-name))
3777 p)))) 3784 p))))
3778 3785
3779(defun tramp-sh-file-gvfs-monitor-dir-process-filter (proc string) 3786(defun tramp-sh-gvfs-monitor-dir-process-filter (proc string)
3780 "Read output from \"gvfs-monitor-dir\" and add corresponding \ 3787 "Read output from \"gvfs-monitor-dir\" and add corresponding \
3781file-notify events." 3788file-notify events."
3782 (let ((remote-prefix 3789 (let ((remote-prefix
@@ -3790,6 +3797,8 @@ file-notify events."
3790 ;; Attribute change is returned in unused wording. 3797 ;; Attribute change is returned in unused wording.
3791 string (tramp-compat-replace-regexp-in-string 3798 string (tramp-compat-replace-regexp-in-string
3792 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string)) 3799 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string))
3800 (when (string-match "Monitoring not supported" string)
3801 (delete-process proc))
3793 3802
3794 (while (string-match 3803 (while (string-match
3795 (concat "^[\n\r]*" 3804 (concat "^[\n\r]*"
@@ -3798,18 +3807,24 @@ file-notify events."
3798 "\\(Other = \\([^\n\r]+\\)[\n\r]+\\)?" 3807 "\\(Other = \\([^\n\r]+\\)[\n\r]+\\)?"
3799 "Event = \\([^[:blank:]]+\\)[\n\r]+") 3808 "Event = \\([^[:blank:]]+\\)[\n\r]+")
3800 string) 3809 string)
3801 (let ((object 3810 (let* ((file (match-string 1 string))
3802 (list 3811 (file1 (match-string 3 string))
3803 proc 3812 (object
3804 (intern-soft 3813 (list
3805 (tramp-compat-replace-regexp-in-string 3814 proc
3806 "_" "-" (downcase (match-string 4 string)))) 3815 (intern-soft
3807 ;; File names are returned as absolute paths. We must 3816 (tramp-compat-replace-regexp-in-string
3808 ;; add the remote prefix. 3817 "_" "-" (downcase (match-string 4 string))))
3809 (concat remote-prefix (match-string 1 string)) 3818 ;; File names are returned as absolute paths. We must
3810 (when (match-string 3 string) 3819 ;; add the remote prefix.
3811 (concat remote-prefix (match-string 3 string)))))) 3820 (concat remote-prefix file)
3821 (when file1 (concat remote-prefix file1)))))
3812 (setq string (replace-match "" nil nil string)) 3822 (setq string (replace-match "" nil nil string))
3823 ;; Remove watch when file or directory to be watched is deleted.
3824 (when (and (member (cadr object) '(moved deleted))
3825 (string-equal
3826 file (tramp-compat-process-get proc 'watch-name)))
3827 (delete-process proc))
3813 ;; Usually, we would add an Emacs event now. Unfortunately, 3828 ;; Usually, we would add an Emacs event now. Unfortunately,
3814 ;; `unread-command-events' does not accept several events at 3829 ;; `unread-command-events' does not accept several events at
3815 ;; once. Therefore, we apply the callback directly. 3830 ;; once. Therefore, we apply the callback directly.
@@ -3821,7 +3836,7 @@ file-notify events."
3821 (when string (tramp-message proc 10 "Rest string:\n%s" string)) 3836 (when string (tramp-message proc 10 "Rest string:\n%s" string))
3822 (tramp-compat-process-put proc 'rest-string string))) 3837 (tramp-compat-process-put proc 'rest-string string)))
3823 3838
3824(defun tramp-sh-file-inotifywait-process-filter (proc string) 3839(defun tramp-sh-inotifywait-process-filter (proc string)
3825 "Read output from \"inotifywait\" and add corresponding file-notify events." 3840 "Read output from \"inotifywait\" and add corresponding file-notify events."
3826 (tramp-message proc 6 "%S\n%s" proc string) 3841 (tramp-message proc 6 "%S\n%s" proc string)
3827 (dolist (line (split-string string "[\n\r]+" 'omit-nulls)) 3842 (dolist (line (split-string string "[\n\r]+" 'omit-nulls))
@@ -3843,6 +3858,9 @@ file-notify events."
3843 (tramp-compat-replace-regexp-in-string "_" "-" (downcase x)))) 3858 (tramp-compat-replace-regexp-in-string "_" "-" (downcase x))))
3844 (split-string (match-string 1 line) "," 'omit-nulls)) 3859 (split-string (match-string 1 line) "," 'omit-nulls))
3845 (match-string 3 line)))) 3860 (match-string 3 line))))
3861 ;; Remove watch when file or directory to be watched is deleted.
3862 (when (equal (cadr object) 'ignored)
3863 (delete-process proc))
3846 ;; Usually, we would add an Emacs event now. Unfortunately, 3864 ;; Usually, we would add an Emacs event now. Unfortunately,
3847 ;; `unread-command-events' does not accept several events at 3865 ;; `unread-command-events' does not accept several events at
3848 ;; once. Therefore, we apply the callback directly. 3866 ;; once. Therefore, we apply the callback directly.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 9ec3226417c..fbb8c8a349e 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3407,7 +3407,7 @@ of."
3407(defun tramp-handle-file-notify-add-watch (filename _flags _callback) 3407(defun tramp-handle-file-notify-add-watch (filename _flags _callback)
3408 "Like `file-notify-add-watch' for Tramp files." 3408 "Like `file-notify-add-watch' for Tramp files."
3409 ;; This is the default handler. tramp-gvfs.el and tramp-sh.el have 3409 ;; This is the default handler. tramp-gvfs.el and tramp-sh.el have
3410 ;; its own one. 3410 ;; their own one.
3411 (setq filename (expand-file-name filename)) 3411 (setq filename (expand-file-name filename))
3412 (with-parsed-tramp-file-name filename nil 3412 (with-parsed-tramp-file-name filename nil
3413 (tramp-error 3413 (tramp-error
@@ -3419,11 +3419,17 @@ of."
3419 (unless (processp proc) 3419 (unless (processp proc)
3420 (tramp-error proc 'file-notify-error "Not a valid descriptor %S" proc)) 3420 (tramp-error proc 'file-notify-error "Not a valid descriptor %S" proc))
3421 (tramp-message proc 6 "Kill %S" proc) 3421 (tramp-message proc 6 "Kill %S" proc)
3422 (kill-process proc)) 3422 (delete-process proc))
3423 3423
3424(defun tramp-handle-file-notify-valid-p (proc) 3424(defun tramp-handle-file-notify-valid-p (proc)
3425 "Like `file-notify-valid-p' for Tramp files." 3425 "Like `file-notify-valid-p' for Tramp files."
3426 (and proc (processp proc) (memq (process-status proc) '(run open)))) 3426 (and proc (processp proc) (memq (process-status proc) '(run open))
3427 ;; Sometimes, the process is still in status `run' when the
3428 ;; file or directory to be watched is deleted already.
3429 (with-current-buffer (process-buffer proc)
3430 (file-exists-p
3431 (concat (file-remote-p default-directory)
3432 (tramp-compat-process-get proc 'watch-name))))))
3427 3433
3428;;; Functions for establishing connection: 3434;;; Functions for establishing connection:
3429 3435
diff --git a/test/automated/file-notify-tests.el b/test/automated/file-notify-tests.el
index dfc32443d17..9d66f03ae0c 100644
--- a/test/automated/file-notify-tests.el
+++ b/test/automated/file-notify-tests.el
@@ -61,6 +61,8 @@
61(defvar file-notify--test-results nil) 61(defvar file-notify--test-results nil)
62(defvar file-notify--test-event nil) 62(defvar file-notify--test-event nil)
63(defvar file-notify--test-events nil) 63(defvar file-notify--test-events nil)
64(defun file-notify--test-timeout ()
65 (if (file-remote-p temporary-file-directory) 6 3))
64 66
65(defun file-notify--test-cleanup () 67(defun file-notify--test-cleanup ()
66 "Cleanup after a test." 68 "Cleanup after a test."
@@ -69,13 +71,16 @@
69 (when (and file-notify--test-tmpfile 71 (when (and file-notify--test-tmpfile
70 (file-exists-p file-notify--test-tmpfile)) 72 (file-exists-p file-notify--test-tmpfile))
71 (if (directory-name-p file-notify--test-tmpfile) 73 (if (directory-name-p file-notify--test-tmpfile)
72 (delete-directory file-notify--test-tmpfile) 74 (delete-directory file-notify--test-tmpfile 'recursive)
73 (delete-file file-notify--test-tmpfile))) 75 (delete-file file-notify--test-tmpfile)))
74 (when (and file-notify--test-tmpfile1 76 (when (and file-notify--test-tmpfile1
75 (file-exists-p file-notify--test-tmpfile1)) 77 (file-exists-p file-notify--test-tmpfile1))
76 (if (directory-name-p file-notify--test-tmpfile1) 78 (if (directory-name-p file-notify--test-tmpfile1)
77 (delete-directory file-notify--test-tmpfile1) 79 (delete-directory file-notify--test-tmpfile1 'recursive)
78 (delete-file file-notify--test-tmpfile1))) 80 (delete-file file-notify--test-tmpfile1)))
81 (when (file-remote-p temporary-file-directory)
82 (tramp-cleanup-connection
83 (tramp-dissect-file-name temporary-file-directory) nil 'keep-password))
79 84
80 (setq file-notify--test-tmpfile nil) 85 (setq file-notify--test-tmpfile nil)
81 (setq file-notify--test-tmpfile1 nil) 86 (setq file-notify--test-tmpfile1 nil)
@@ -150,6 +155,8 @@ being the result.")
150 (should 155 (should
151 (setq file-notify--test-desc 156 (setq file-notify--test-desc
152 (file-notify-add-watch temporary-file-directory '(change) 'ignore))) 157 (file-notify-add-watch temporary-file-directory '(change) 'ignore)))
158
159 ;; Cleanup.
153 (file-notify--test-cleanup)) 160 (file-notify--test-cleanup))
154 161
155(file-notify--deftest-remote file-notify-test00-availability 162(file-notify--deftest-remote file-notify-test00-availability
@@ -190,6 +197,7 @@ being the result.")
190 (file-notify-add-watch temporary-file-directory '(change) 3)) 197 (file-notify-add-watch temporary-file-directory '(change) 3))
191 '(wrong-type-argument 3))) 198 '(wrong-type-argument 3)))
192 199
200 ;; Cleanup.
193 (file-notify--test-cleanup)) 201 (file-notify--test-cleanup))
194 202
195(file-notify--deftest-remote file-notify-test01-add-watch 203(file-notify--deftest-remote file-notify-test01-add-watch
@@ -215,11 +223,11 @@ is bound somewhere."
215 223
216(defun file-notify--test-event-handler (event) 224(defun file-notify--test-event-handler (event)
217 "Run a test over FILE-NOTIFY--TEST-EVENT. 225 "Run a test over FILE-NOTIFY--TEST-EVENT.
218For later analysis, append the test result to 226For later analysis, append the test result to `file-notify--test-results'
219`file-notify--test-results' and the event to 227and the event to `file-notify--test-events'."
220`file-notify--test-events'."
221 (let* ((file-notify--test-event event) 228 (let* ((file-notify--test-event event)
222 (result (ert-run-test (make-ert-test :body 'file-notify--test-event-test)))) 229 (result
230 (ert-run-test (make-ert-test :body 'file-notify--test-event-test))))
223 (setq file-notify--test-events 231 (setq file-notify--test-events
224 (append file-notify--test-events `(,file-notify--test-event))) 232 (append file-notify--test-events `(,file-notify--test-event)))
225 (setq file-notify--test-results 233 (setq file-notify--test-results
@@ -243,7 +251,7 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
243 (declare (indent 3)) 251 (declare (indent 3))
244 (let ((outer (make-symbol "outer"))) 252 (let ((outer (make-symbol "outer")))
245 `(let ((,outer file-notify--test-events)) 253 `(let ((,outer file-notify--test-events))
246 (let ((file-notify--test-events nil)) 254 (let (file-notify--test-events)
247 ,@body 255 ,@body
248 (file-notify--wait-for-events 256 (file-notify--wait-for-events
249 ,timeout (= ,n (length file-notify--test-events))) 257 ,timeout (= ,n (length file-notify--test-events)))
@@ -256,9 +264,7 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
256 (skip-unless (file-notify--test-local-enabled)) 264 (skip-unless (file-notify--test-local-enabled))
257 (unwind-protect 265 (unwind-protect
258 (progn 266 (progn
259 (setq file-notify--test-results nil 267 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
260 file-notify--test-events nil
261 file-notify--test-tmpfile (file-notify--test-make-temp-name)
262 file-notify--test-tmpfile1 (file-notify--test-make-temp-name) 268 file-notify--test-tmpfile1 (file-notify--test-make-temp-name)
263 file-notify--test-desc 269 file-notify--test-desc
264 (file-notify-add-watch 270 (file-notify-add-watch
@@ -268,41 +274,66 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
268 274
269 ;; Check creation, change, and deletion. 275 ;; Check creation, change, and deletion.
270 (file-notify--test-with-events 276 (file-notify--test-with-events
271 3 3 (lambda (events) 277 3 (file-notify--test-timeout)
272 (should (equal '(created changed deleted) 278 (lambda (events)
273 (mapcar #'cadr events)))) 279 (should (equal '(created changed deleted)
280 (mapcar #'cadr events))))
274 (write-region 281 (write-region
275 "any text" nil file-notify--test-tmpfile nil 'no-message) 282 "any text" nil file-notify--test-tmpfile nil 'no-message)
276 (delete-file file-notify--test-tmpfile)) 283 (delete-file file-notify--test-tmpfile))
277 284
278 ;; Check copy. 285 ;; Check copy.
279 (file-notify--test-with-events 286 (file-notify--test-with-events
280 3 3 (lambda (events) 287 3 (file-notify--test-timeout)
281 (should (equal '(created changed deleted) 288 (lambda (events)
282 (mapcar #'cadr events)))) 289 (should (equal '(created changed deleted)
290 (mapcar #'cadr events))))
283 (write-region 291 (write-region
284 "any text" nil file-notify--test-tmpfile nil 'no-message) 292 "any text" nil file-notify--test-tmpfile nil 'no-message)
285 (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1) 293 (copy-file file-notify--test-tmpfile file-notify--test-tmpfile1)
294 ;; The next two events shall not be visible.
295 (set-file-modes file-notify--test-tmpfile 000)
296 (set-file-times file-notify--test-tmpfile '(0 0))
286 (delete-file file-notify--test-tmpfile) 297 (delete-file file-notify--test-tmpfile)
287 (delete-file file-notify--test-tmpfile1)) 298 (delete-file file-notify--test-tmpfile1))
288 299
289 ;; Check rename. 300 ;; Check rename.
290 (file-notify--test-with-events 301 (file-notify--test-with-events
291 3 3 (lambda (events) 302 3 (file-notify--test-timeout)
292 (should (equal '(created changed renamed) 303 (lambda (events)
293 (mapcar #'cadr events)))) 304 (should (equal '(created changed renamed)
305 (mapcar #'cadr events))))
294 (write-region 306 (write-region
295 "any text" nil file-notify--test-tmpfile nil 'no-message) 307 "any text" nil file-notify--test-tmpfile nil 'no-message)
296 (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1) 308 (rename-file file-notify--test-tmpfile file-notify--test-tmpfile1)
297 ;; After the rename, we won't get events anymore. 309 ;; After the rename, we won't get events anymore.
298 (delete-file file-notify--test-tmpfile1)) 310 (delete-file file-notify--test-tmpfile1))
299 311
312 ;; Check attribute change.
313 (file-notify-rm-watch file-notify--test-desc)
314 (setq file-notify--test-desc
315 (file-notify-add-watch
316 file-notify--test-tmpfile
317 '(attribute-change) 'file-notify--test-event-handler))
318 (file-notify--test-with-events
319 2 (file-notify--test-timeout)
320 (lambda (events)
321 (should (equal '(attribute-changed attribute-changed)
322 (mapcar #'cadr events))))
323 (write-region
324 "any text" nil file-notify--test-tmpfile nil 'no-message)
325 (set-file-modes file-notify--test-tmpfile 000)
326 (read-event nil nil 0.1) ; In order to distinguish the events.
327 (set-file-times file-notify--test-tmpfile '(0 0))
328 (delete-file file-notify--test-tmpfile))
329
300 ;; Check the global sequence again just to make sure that 330 ;; Check the global sequence again just to make sure that
301 ;; `file-notify--test-events' has been set correctly. 331 ;; `file-notify--test-events' has been set correctly.
302 (should (equal (mapcar #'cadr file-notify--test-events) 332 (should (equal (mapcar #'cadr file-notify--test-events)
303 '(created changed deleted 333 '(created changed deleted
304 created changed deleted 334 created changed deleted
305 created changed renamed))) 335 created changed renamed
336 attribute-changed attribute-changed)))
306 337
307 (should file-notify--test-results) 338 (should file-notify--test-results)
308 (dolist (result file-notify--test-results) 339 (dolist (result file-notify--test-results)
@@ -310,6 +341,8 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
310 (when (ert-test-failed-p result) 341 (when (ert-test-failed-p result)
311 (ert-fail 342 (ert-fail
312 (cadr (ert-test-result-with-condition-condition result)))))) 343 (cadr (ert-test-result-with-condition-condition result))))))
344
345 ;; Cleanup.
313 (file-notify--test-cleanup))) 346 (file-notify--test-cleanup)))
314 347
315(file-notify--deftest-remote file-notify-test02-events 348(file-notify--deftest-remote file-notify-test02-events
@@ -367,7 +400,7 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
367 (buffer-string)))) 400 (buffer-string))))
368 (should (string-match "another text" (buffer-string))))) 401 (should (string-match "another text" (buffer-string)))))
369 402
370 ;; Exit. 403 ;; Cleanup.
371 (ignore-errors (kill-buffer buf)) 404 (ignore-errors (kill-buffer buf))
372 (file-notify--test-cleanup)))) 405 (file-notify--test-cleanup))))
373 406
@@ -377,6 +410,31 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
377(ert-deftest file-notify-test04-file-validity () 410(ert-deftest file-notify-test04-file-validity ()
378 "Check `file-notify-valid-p' for files." 411 "Check `file-notify-valid-p' for files."
379 (skip-unless (file-notify--test-local-enabled)) 412 (skip-unless (file-notify--test-local-enabled))
413
414 (unwind-protect
415 (progn
416 (setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
417 (setq file-notify--test-desc (file-notify-add-watch
418 file-notify--test-tmpfile
419 '(change)
420 #'file-notify--test-event-handler))
421 (file-notify--test-with-events
422 2 (file-notify--test-timeout)
423 (lambda (events)
424 (should (equal '(created changed)
425 (mapcar #'cadr events))))
426 (should (file-notify-valid-p file-notify--test-desc))
427 (write-region
428 "any text" nil file-notify--test-tmpfile nil 'no-message)
429 (should (file-notify-valid-p file-notify--test-desc)))
430 ;; After removing the watch, the descriptor must not be valid
431 ;; anymore.
432 (file-notify-rm-watch file-notify--test-desc)
433 (should-not (file-notify-valid-p file-notify--test-desc)))
434
435 ;; Cleanup.
436 (file-notify--test-cleanup))
437
380 ;; The batch-mode operation of w32notify is fragile (there's no 438 ;; The batch-mode operation of w32notify is fragile (there's no
381 ;; input threads to send the message to). 439 ;; input threads to send the message to).
382 (skip-unless (not (and noninteractive (eq file-notify--library 'w32notify)))) 440 (skip-unless (not (and noninteractive (eq file-notify--library 'w32notify))))
@@ -389,9 +447,10 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
389 '(change) 447 '(change)
390 #'file-notify--test-event-handler)) 448 #'file-notify--test-event-handler))
391 (file-notify--test-with-events 449 (file-notify--test-with-events
392 2 3 (lambda (events) 450 2 (file-notify--test-timeout)
393 (should (equal '(created changed) 451 (lambda (events)
394 (mapcar #'cadr events)))) 452 (should (equal '(created changed)
453 (mapcar #'cadr events))))
395 (should (file-notify-valid-p file-notify--test-desc)) 454 (should (file-notify-valid-p file-notify--test-desc))
396 (write-region 455 (write-region
397 "any text" nil file-notify--test-tmpfile nil 'no-message) 456 "any text" nil file-notify--test-tmpfile nil 'no-message)
@@ -399,10 +458,12 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
399 ;; After deleting the parent, the descriptor must not be valid 458 ;; After deleting the parent, the descriptor must not be valid
400 ;; anymore. 459 ;; anymore.
401 (delete-directory temporary-file-directory t) 460 (delete-directory temporary-file-directory t)
402 (read-event nil nil 0.5) 461 (file-notify--wait-for-events
462 (file-notify--test-timeout)
463 (not (file-notify-valid-p file-notify--test-desc)))
403 (should-not (file-notify-valid-p file-notify--test-desc))) 464 (should-not (file-notify-valid-p file-notify--test-desc)))
404 465
405 ;; Exit. 466 ;; Cleanup.
406 (file-notify--test-cleanup))) 467 (file-notify--test-cleanup)))
407 468
408(file-notify--deftest-remote file-notify-test04-file-validity 469(file-notify--deftest-remote file-notify-test04-file-validity
@@ -411,6 +472,25 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
411(ert-deftest file-notify-test05-dir-validity () 472(ert-deftest file-notify-test05-dir-validity ()
412 "Check `file-notify-valid-p' for directories." 473 "Check `file-notify-valid-p' for directories."
413 (skip-unless (file-notify--test-local-enabled)) 474 (skip-unless (file-notify--test-local-enabled))
475
476 (unwind-protect
477 (progn
478 (setq file-notify--test-tmpfile (file-name-as-directory
479 (file-notify--test-make-temp-name)))
480 (make-directory file-notify--test-tmpfile)
481 (setq file-notify--test-desc (file-notify-add-watch
482 file-notify--test-tmpfile
483 '(change)
484 #'file-notify--test-event-handler))
485 (should (file-notify-valid-p file-notify--test-desc))
486 ;; After removing the watch, the descriptor must not be valid
487 ;; anymore.
488 (file-notify-rm-watch file-notify--test-desc)
489 (should-not (file-notify-valid-p file-notify--test-desc)))
490
491 ;; Cleanup.
492 (file-notify--test-cleanup))
493
414 ;; The batch-mode operation of w32notify is fragile (there's no 494 ;; The batch-mode operation of w32notify is fragile (there's no
415 ;; input threads to send the message to). 495 ;; input threads to send the message to).
416 (skip-unless (not (and noninteractive (eq file-notify--library 'w32notify)))) 496 (skip-unless (not (and noninteractive (eq file-notify--library 'w32notify))))
@@ -424,13 +504,15 @@ Don't wait longer than TIMEOUT seconds for the events to be delivered."
424 '(change) 504 '(change)
425 #'file-notify--test-event-handler)) 505 #'file-notify--test-event-handler))
426 (should (file-notify-valid-p file-notify--test-desc)) 506 (should (file-notify-valid-p file-notify--test-desc))
427 (delete-directory file-notify--test-tmpfile t)
428 ;; After deleting the directory, the descriptor must not be 507 ;; After deleting the directory, the descriptor must not be
429 ;; valid anymore. 508 ;; valid anymore.
430 (read-event nil nil 0.5) 509 (delete-directory file-notify--test-tmpfile t)
510 (file-notify--wait-for-events
511 (file-notify--test-timeout)
512 (not (file-notify-valid-p file-notify--test-desc)))
431 (should-not (file-notify-valid-p file-notify--test-desc))) 513 (should-not (file-notify-valid-p file-notify--test-desc)))
432 514
433 ;; Exit. 515 ;; Cleanup.
434 (file-notify--test-cleanup))) 516 (file-notify--test-cleanup)))
435 517
436(file-notify--deftest-remote file-notify-test05-dir-validity 518(file-notify--deftest-remote file-notify-test05-dir-validity