aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2022-08-03 17:30:09 +0200
committerMichael Albinus2022-08-03 17:30:09 +0200
commit21afc26d4df6bae35ba032d4b6b03fb7fb2bf1b3 (patch)
treed9144d4fc404365fcdc431293d8358a067a909b5
parent3ec6b806b246c147ae30408a1d659083619883af (diff)
downloademacs-21afc26d4df6bae35ba032d4b6b03fb7fb2bf1b3.tar.gz
emacs-21afc26d4df6bae35ba032d4b6b03fb7fb2bf1b3.zip
Reorganize Tramp
* lisp/net/tramp-adb.el (tramp-adb-handle-write-region): Handle special case that START is "". (tramp-adb-handle-set-file-modes) (tramp-adb-handle-set-file-times): Use `tramp-skeleton-set-file-modes-times-uid-gid'. (tramp-adb-handle-make-process): Use `with-tramp-saved-connection-properties'. * lisp/net/tramp-archive.el (tramp-archive-file-name-handler-alist): Use `tramp-archive-handle-file-exists-p'. (tramp-archive-handle-file-exists-p): New defun. (tramp-archive-file-name-handler): Add ;;;###tramp-autoload cookie. * lisp/net/tramp-cache.el (tramp-compat, tramp-loaddefs) (time-stamp): Require. (tramp-get-file-property, tramp-set-file-property) (tramp-flush-file-property, tramp-flush-file-upper-properties) (tramp-flush-file-properties): Use `tramp-file-name-unify'. Adapt message. (tramp-flush-directory-properties): Simplify. (tramp-flush-file-function): Add ;;;###tramp-autoload cookie. Don't use `with-parsed-tramp-file-name', it isn't exposed. (with-tramp-file-property, with-tramp-connection-property) (with-tramp-saved-connection-property): Macros moved from tramp.el. (with-tramp-saved-file-property) (with-tramp-saved-file-properties) (with-tramp-saved-connection-properties): New defmacros. * lisp/net/tramp-cmds.el (tramp-cleanup-connection): Flush "/". * lisp/net/tramp-crypt.el (tramp-crypt-handle-set-file-modes) (tramp-crypt-handle-set-file-times) (tramp-crypt-handle-set-file-uid-gid): Use `tramp-skeleton-set-file-modes-times-uid-gid'. * lisp/net/tramp-ftp.el (tramp-archive-file-name-handler): Don't declare. * lisp/net/tramp-gvfs.el (tramp-gvfs-info): New defun. (tramp-gvfs-do-copy-or-rename-file) (tramp-gvfs-handle-delete-directory) (tramp-gvfs-handle-delete-file, tramp-gvfs-get-root-attributes) (tramp-gvfs-handle-make-directory): Use it. (tramp-gvfs-handle-set-file-modes) (tramp-gvfs-handle-set-file-times) (tramp-gvfs-handle-set-file-uid-gid): Use `tramp-skeleton-set-file-modes-times-uid-gid'. * lisp/net/tramp-sh.el (tramp-sh-handle-make-symbolic-link): Expand TARGET when flushing file properties. (tramp-sh-handle-set-file-modes, tramp-sh-handle-set-file-times) (tramp-sh-handle-set-file-uid-gid): Use `tramp-skeleton-set-file-modes-times-uid-gid'. (tramp-sh-handle-file-name-all-completions): Protect, when connection is not established yet. (tramp-do-copy-or-rename-file-directly): Flush file properties of NEWNAME when constructing a new remote file name. (tramp-do-copy-or-rename-file-out-of-band, tramp-sh-handle-make-process): Use `with-tramp-saved-connection-properties'. (tramp-sh-handle-delete-file): Flush file properties only after deleting, otherwise we get a false alarm. (tramp-sh-handle-process-file): Flush "/". (tramp-sh-handle-write-region): Handle special case that START is "". * lisp/net/tramp-smb.el (tramp-smb-handle-copy-directory) (tramp-smb-handle-file-acl, tramp-smb-handle-process-file) (tramp-smb-handle-set-file-acl) (tramp-smb-handle-start-file-process): Use `with-tramp-saved-connection-properties'. (tramp-smb-remote-acl-p): New defun. (tramp-smb-handle-file-acl, tramp-smb-handle-set-file-acl): Use it. (tramp-smb-handle-set-file-modes): Use `tramp-skeleton-set-file-modes-times-uid-gid'. (tramp-smb-handle-process-file, tramp-smb-maybe-open-connection): Flush "/". * lisp/net/tramp-sshfs.el (tramp-sshfs-handle-process-file): Flush "/". (tramp-sshfs-handle-set-file-modes) (tramp-sshfs-handle-set-file-times): Use `tramp-skeleton-set-file-modes-times-uid-gid'. * lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-set-file-modes) (tramp-sudoedit-handle-set-file-times) (tramp-sudoedit-handle-set-file-uid-gid): Use `tramp-skeleton-set-file-modes-times-uid-gid'. * lisp/net/tramp.el (tramp-archive-file-name-handler): Don't declare. (tramp-verbose, tramp-file-name-unify, tramp-tramp-file-p) (tramp-file-local-name, tramp-dissect-file-name) (tramp-make-tramp-file-name, tramp-get-connection-buffer) (tramp-get-buffer-string, tramp-debug-message) (tramp-inhibit-progress-reporter, tramp-message): Add ;;;###tramp-autoload cookie. (tramp-file-name): Expose defstruct to tramp-loaddefs.el (tramp-file-name-unify): New optional arg FILE. (tramp-get-default-directory, tramp-get-buffer-string) (tramp-message, tramp-backtrace, tramp-error-with-buffer) (tramp-with-demoted-errors, tramp-barf-if-file-missing) (tramp-skeleton-copy-directory, tramp-skeleton-delete-directory) (tramp-skeleton-directory-files) (tramp-skeleton-directory-files-and-attributes) (tramp-skeleton-file-local-copy, tramp-skeleton-write-region): Remove `tramp-suppress-trace' property, it isn't needed for defmacros and defsubsts. (with-tramp-file-property, with-tramp-connection-property) (with-tramp-saved-connection-property): Move macros to tramp-cache.el. (tramp-skeleton-directory-files-and-attributes): Fix implementation. (tramp-skeleton-file-local-copy): Fix docstring. (tramp-skeleton-set-file-modes-times-uid-gid): New defmacro. (tramp-skeleton-write-region): Set "file-exists-p" cache property. (tramp-handle-file-exists-p): Use cached value. (tramp-process-sentinel): Flush "/". (tramp-make-tramp-temp-file): Suppress also `tramp-smb-remote-acl-p'. (tramp-get-connection-buffer): * test/lisp/net/tramp-tests.el (tramp-test10-write-region) (tramp-test20-file-modes, tramp-test22-file-times): Extend tests.
-rw-r--r--lisp/net/tramp-adb.el236
-rw-r--r--lisp/net/tramp-archive.el12
-rw-r--r--lisp/net/tramp-cache.el164
-rw-r--r--lisp/net/tramp-cmds.el2
-rw-r--r--lisp/net/tramp-crypt.el9
-rw-r--r--lisp/net/tramp-ftp.el1
-rw-r--r--lisp/net/tramp-gvfs.el47
-rw-r--r--lisp/net/tramp-sh.el701
-rw-r--r--lisp/net/tramp-smb.el346
-rw-r--r--lisp/net/tramp-sshfs.el13
-rw-r--r--lisp/net/tramp-sudoedit.el24
-rw-r--r--lisp/net/tramp.el127
-rw-r--r--test/lisp/net/tramp-tests.el23
13 files changed, 905 insertions, 800 deletions
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 3e780aa1a18..1d35f2b2ff7 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -517,34 +517,39 @@ Emacs dired can't find files."
517 (start end filename &optional append visit lockname mustbenew) 517 (start end filename &optional append visit lockname mustbenew)
518 "Like `write-region' for Tramp files." 518 "Like `write-region' for Tramp files."
519 (tramp-skeleton-write-region start end filename append visit lockname mustbenew 519 (tramp-skeleton-write-region start end filename append visit lockname mustbenew
520 (let ((tmpfile (tramp-compat-make-temp-file filename))) 520 ;; If `start' is the empty string, it is likely that a temporary
521 (when (and append (file-exists-p filename)) 521 ;; file is created. Do it directly.
522 (copy-file filename tmpfile 'ok) 522 (if (and (stringp start) (string-empty-p start))
523 (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600))) 523 (tramp-adb-send-command-and-check
524 (let (create-lockfiles) 524 v (format "echo -n \"\">%s" (tramp-shell-quote-argument localname)))
525 (write-region start end tmpfile append 'no-message)) 525
526 (with-tramp-progress-reporter 526 (let ((tmpfile (tramp-compat-make-temp-file filename)))
527 v 3 (format-message 527 (when (and append (file-exists-p filename))
528 "Moving tmp file `%s' to `%s'" tmpfile filename) 528 (copy-file filename tmpfile 'ok)
529 (unwind-protect 529 (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600)))
530 (unless (tramp-adb-execute-adb-command 530 (let (create-lockfiles)
531 v "push" tmpfile (tramp-compat-file-name-unquote localname)) 531 (write-region start end tmpfile append 'no-message))
532 (tramp-error v 'file-error "Cannot write: `%s'" filename)) 532 (with-tramp-progress-reporter
533 (delete-file tmpfile)))))) 533 v 3 (format-message
534 "Moving tmp file `%s' to `%s'" tmpfile filename)
535 (unwind-protect
536 (unless (tramp-adb-execute-adb-command
537 v "push" tmpfile
538 (tramp-compat-file-name-unquote localname))
539 (tramp-error v 'file-error "Cannot write: `%s'" filename))
540 (delete-file tmpfile)))))))
534 541
535(defun tramp-adb-handle-set-file-modes (filename mode &optional flag) 542(defun tramp-adb-handle-set-file-modes (filename mode &optional flag)
536 "Like `set-file-modes' for Tramp files." 543 "Like `set-file-modes' for Tramp files."
537 (with-parsed-tramp-file-name filename nil 544 ;; ADB shell does not support "chmod -h".
538 ;; ADB shell does not support "chmod -h". 545 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
539 (unless (and (eq flag 'nofollow) (file-symlink-p filename)) 546 (tramp-skeleton-set-file-modes-times-uid-gid filename
540 (tramp-flush-file-properties v localname)
541 (tramp-adb-send-command-and-check 547 (tramp-adb-send-command-and-check
542 v (format "chmod %o %s" mode (tramp-shell-quote-argument localname)))))) 548 v (format "chmod %o %s" mode (tramp-shell-quote-argument localname))))))
543 549
544(defun tramp-adb-handle-set-file-times (filename &optional time flag) 550(defun tramp-adb-handle-set-file-times (filename &optional time flag)
545 "Like `set-file-times' for Tramp files." 551 "Like `set-file-times' for Tramp files."
546 (with-parsed-tramp-file-name filename nil 552 (tramp-skeleton-set-file-modes-times-uid-gid filename
547 (tramp-flush-file-properties v localname)
548 (let ((time (if (or (null time) 553 (let ((time (if (or (null time)
549 (tramp-compat-time-equal-p time tramp-time-doesnt-exist) 554 (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
550 (tramp-compat-time-equal-p time tramp-time-dont-know)) 555 (tramp-compat-time-equal-p time tramp-time-dont-know))
@@ -827,7 +832,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
827 ;; because the remote process could have changed them. 832 ;; because the remote process could have changed them.
828 (when tmpinput (delete-file tmpinput)) 833 (when tmpinput (delete-file tmpinput))
829 (when process-file-side-effects 834 (when process-file-side-effects
830 (tramp-flush-directory-properties v "")) 835 (tramp-flush-directory-properties v "/"))
831 836
832 ;; Return exit status. 837 ;; Return exit status.
833 (if (equal ret -1) 838 (if (equal ret -1)
@@ -923,102 +928,99 @@ implementation will be used."
923 name1 (format "%s<%d>" name i))) 928 name1 (format "%s<%d>" name i)))
924 (setq name name1) 929 (setq name name1)
925 930
926 (with-tramp-saved-connection-property v "process-name" 931 (with-tramp-saved-connection-properties
927 (with-tramp-saved-connection-property v "process-buffer" 932 v '("process-name" "process-buffer")
928 ;; Set the new process properties. 933 ;; Set the new process properties.
929 (tramp-set-connection-property v "process-name" name) 934 (tramp-set-connection-property v "process-name" name)
930 (tramp-set-connection-property v "process-buffer" buffer) 935 (tramp-set-connection-property v "process-buffer" buffer)
931 (with-current-buffer (tramp-get-connection-buffer v) 936 (with-current-buffer (tramp-get-connection-buffer v)
932 (unwind-protect 937 (unwind-protect
933 ;; We catch this event. Otherwise, 938 ;; We catch this event. Otherwise, `make-process'
934 ;; `make-process' could be called on the local 939 ;; could be called on the local host.
935 ;; host. 940 (save-excursion
936 (save-excursion 941 (save-restriction
937 (save-restriction 942 ;; Activate narrowing in order to save BUFFER
938 ;; Activate narrowing in order to save 943 ;; contents. Clear also the modification
939 ;; BUFFER contents. Clear also the 944 ;; time; otherwise we might be interrupted by
940 ;; modification time; otherwise we might be 945 ;; `verify-visited-file-modtime'.
941 ;; interrupted by `verify-visited-file-modtime'. 946 (let ((buffer-undo-list t)
942 (let ((buffer-undo-list t) 947 (inhibit-read-only t)
943 (inhibit-read-only t) 948 (coding-system-for-write
944 (coding-system-for-write 949 (if (symbolp coding) coding (car coding)))
945 (if (symbolp coding) coding (car coding))) 950 (coding-system-for-read
946 (coding-system-for-read 951 (if (symbolp coding) coding (cdr coding))))
947 (if (symbolp coding) coding (cdr coding)))) 952 (clear-visited-file-modtime)
948 (clear-visited-file-modtime) 953 (narrow-to-region (point-max) (point-max))
949 (narrow-to-region (point-max) (point-max)) 954 ;; We call `tramp-adb-maybe-open-connection',
950 ;; We call `tramp-adb-maybe-open-connection', 955 ;; in order to cleanup the prompt afterwards.
951 ;; in order to cleanup the prompt afterwards. 956 (tramp-adb-maybe-open-connection v)
952 (tramp-adb-maybe-open-connection v) 957 (delete-region (point-min) (point-max))
953 (delete-region (point-min) (point-max)) 958 ;; Send the command.
954 ;; Send the command. 959 (setq p (tramp-get-connection-process v))
955 (setq p (tramp-get-connection-process v)) 960 (tramp-adb-send-command v command nil t) ; nooutput
956 (tramp-adb-send-command v command nil t) ; nooutput 961 ;; Set sentinel and filter.
957 ;; Set sentinel and filter. 962 (when sentinel
958 (when sentinel 963 (set-process-sentinel p sentinel))
959 (set-process-sentinel p sentinel)) 964 (when filter
960 (when filter 965 (set-process-filter p filter))
961 (set-process-filter p filter)) 966 (process-put p 'remote-command orig-command)
962 (process-put p 'remote-command orig-command) 967 (tramp-set-connection-property
963 (tramp-set-connection-property 968 p "remote-command" orig-command)
964 p "remote-command" orig-command) 969 ;; Set query flag and process marker for
965 ;; Set query flag and process marker for 970 ;; this process. We ignore errors, because
966 ;; this process. We ignore errors, 971 ;; the process could have finished already.
967 ;; because the process could have finished 972 (ignore-errors
968 ;; already. 973 (set-process-query-on-exit-flag p (null noquery))
969 (ignore-errors 974 (set-marker (process-mark p) (point))
970 (set-process-query-on-exit-flag p (null noquery)) 975 ;; We must flush them here already;
971 (set-marker (process-mark p) (point)) 976 ;; otherwise `rename-file', `delete-file'
972 ;; We must flush them here already; 977 ;; or `insert-file-contents' will fail.
973 ;; otherwise `rename-file', `delete-file' or 978 (tramp-flush-connection-property v "process-name")
974 ;; `insert-file-contents' will fail. 979 (tramp-flush-connection-property
975 (tramp-flush-connection-property v "process-name") 980 v "process-buffer")
976 (tramp-flush-connection-property 981 ;; Copy tmpstderr file.
977 v "process-buffer") 982 (when (and (stringp stderr)
978 ;; Copy tmpstderr file. 983 (not (tramp-tramp-file-p stderr)))
979 (when (and (stringp stderr) 984 (add-function
980 (not (tramp-tramp-file-p stderr))) 985 :after (process-sentinel p)
981 (add-function 986 (lambda (_proc _msg)
982 :after (process-sentinel p) 987 (rename-file remote-tmpstderr stderr))))
983 (lambda (_proc _msg) 988 ;; Read initial output. Remove the first
984 (rename-file remote-tmpstderr stderr)))) 989 ;; line, which is the command echo.
985 ;; Read initial output. Remove the 990 (unless (eq filter t)
986 ;; first line, which is the command 991 (while
987 ;; echo. 992 (progn
988 (unless (eq filter t) 993 (goto-char (point-min))
989 (while 994 (not (re-search-forward "[\n]" nil t)))
990 (progn 995 (tramp-accept-process-output p 0))
991 (goto-char (point-min)) 996 (delete-region (point-min) (point)))
992 (not (re-search-forward "[\n]" nil t))) 997 ;; Provide error buffer. This shows only
993 (tramp-accept-process-output p 0)) 998 ;; initial error messages; messages
994 (delete-region (point-min) (point))) 999 ;; arriving later on will be inserted when
995 ;; Provide error buffer. This shows 1000 ;; the process is deleted. The temporary
996 ;; only initial error messages; messages 1001 ;; file will exist until the process is
997 ;; arriving later on will be inserted 1002 ;; deleted.
998 ;; when the process is deleted. The 1003 (when (bufferp stderr)
999 ;; temporary file will exist until the 1004 (with-current-buffer stderr
1000 ;; process is deleted. 1005 (insert-file-contents-literally
1001 (when (bufferp stderr) 1006 remote-tmpstderr 'visit))
1002 (with-current-buffer stderr 1007 ;; Delete tmpstderr file.
1003 (insert-file-contents-literally 1008 (add-function
1004 remote-tmpstderr 'visit)) 1009 :after (process-sentinel p)
1005 ;; Delete tmpstderr file. 1010 (lambda (_proc _msg)
1006 (add-function 1011 (with-current-buffer stderr
1007 :after (process-sentinel p) 1012 (insert-file-contents-literally
1008 (lambda (_proc _msg) 1013 remote-tmpstderr 'visit nil nil 'replace))
1009 (with-current-buffer stderr 1014 (delete-file remote-tmpstderr))))
1010 (insert-file-contents-literally 1015 ;; Return process.
1011 remote-tmpstderr 'visit nil nil 'replace)) 1016 p))))
1012 (delete-file remote-tmpstderr)))) 1017
1013 ;; Return process. 1018 ;; Save exit.
1014 p)))) 1019 (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
1015 1020 (ignore-errors
1016 ;; Save exit. 1021 (set-process-buffer p nil)
1017 (if (string-prefix-p tramp-temp-buffer-name (buffer-name)) 1022 (kill-buffer (current-buffer)))
1018 (ignore-errors 1023 (set-buffer-modified-p bmp)))))))))))
1019 (set-process-buffer p nil)
1020 (kill-buffer (current-buffer)))
1021 (set-buffer-modified-p bmp))))))))))))
1022 1024
1023(defun tramp-adb-handle-exec-path () 1025(defun tramp-adb-handle-exec-path ()
1024 "Like `exec-path' for Tramp files." 1026 "Like `exec-path' for Tramp files."
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index b2244941102..fda1441615e 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -240,7 +240,7 @@ It must be supported by libarchive(3).")
240 (file-directory-p . tramp-handle-file-directory-p) 240 (file-directory-p . tramp-handle-file-directory-p)
241 (file-equal-p . tramp-handle-file-equal-p) 241 (file-equal-p . tramp-handle-file-equal-p)
242 (file-executable-p . tramp-archive-handle-file-executable-p) 242 (file-executable-p . tramp-archive-handle-file-executable-p)
243 (file-exists-p . tramp-handle-file-exists-p) 243 (file-exists-p . tramp-archive-handle-file-exists-p)
244 (file-in-directory-p . tramp-handle-file-in-directory-p) 244 (file-in-directory-p . tramp-handle-file-in-directory-p)
245 (file-local-copy . tramp-archive-handle-file-local-copy) 245 (file-local-copy . tramp-archive-handle-file-local-copy)
246 (file-locked-p . ignore) 246 (file-locked-p . ignore)
@@ -322,7 +322,11 @@ arguments to pass to the OPERATION."
322 (inhibit-file-name-operation operation)) 322 (inhibit-file-name-operation operation))
323 (apply operation args)))) 323 (apply operation args))))
324 324
325;;;###autoload 325;; Starting with Emacs 29, `tramp-archive-file-name-handler' is
326;; autoloaded. But it must still be in tramp-loaddefs.el for older
327;; Emacsen.
328;;;###autoload(autoload 'tramp-archive-file-name-handler "tramp-archine")
329;;;###tramp-autoload
326(defun tramp-archive-file-name-handler (operation &rest args) 330(defun tramp-archive-file-name-handler (operation &rest args)
327 "Invoke the file archive related OPERATION. 331 "Invoke the file archive related OPERATION.
328First arg specifies the OPERATION, second arg ARGS is a list of 332First arg specifies the OPERATION, second arg ARGS is a list of
@@ -645,6 +649,10 @@ offered."
645 "Like `file-executable-p' for file archives." 649 "Like `file-executable-p' for file archives."
646 (file-executable-p (tramp-archive-gvfs-file-name filename))) 650 (file-executable-p (tramp-archive-gvfs-file-name filename)))
647 651
652(defun tramp-archive-handle-file-exists-p (filename)
653 "Like `file-exists-p' for file archives."
654 (file-exists-p (tramp-archive-gvfs-file-name filename)))
655
648(defun tramp-archive-handle-file-local-copy (filename) 656(defun tramp-archive-handle-file-local-copy (filename)
649 "Like `file-local-copy' for file archives." 657 "Like `file-local-copy' for file archives."
650 (file-local-copy (tramp-archive-gvfs-file-name filename))) 658 (file-local-copy (tramp-archive-gvfs-file-name filename)))
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index 68f4fda4756..289df2f9aad 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -48,7 +48,7 @@
48;; - The key is a process. These are temporary properties related to 48;; - The key is a process. These are temporary properties related to
49;; an open connection. Examples: "scripts" keeps shell script 49;; an open connection. Examples: "scripts" keeps shell script
50;; definitions already sent to the remote shell, "last-cmd-time" is 50;; definitions already sent to the remote shell, "last-cmd-time" is
51;; the time stamp a command has been sent to the remote process. 51;; the timestamp a command has been sent to the remote process.
52;; 52;;
53;; - The key is nil. These are temporary properties related to the 53;; - The key is nil. These are temporary properties related to the
54;; local machine. Examples: "parse-passwd" and "parse-group" keep 54;; local machine. Examples: "parse-passwd" and "parse-group" keep
@@ -75,8 +75,9 @@
75 75
76;;; Code: 76;;; Code:
77 77
78(require 'tramp) 78(require 'tramp-compat)
79(autoload 'time-stamp-string "time-stamp") 79(require 'tramp-loaddefs)
80(require 'time-stamp)
80 81
81;;; -- Cache -- 82;;; -- Cache --
82 83
@@ -133,11 +134,7 @@ If KEY is `tramp-cache-undefined', don't create anything, and return nil."
133 "Get the PROPERTY of FILE from the cache context of KEY. 134 "Get the PROPERTY of FILE from the cache context of KEY.
134Return DEFAULT if not set." 135Return DEFAULT if not set."
135 ;; Unify localname. Remove hop from `tramp-file-name' structure. 136 ;; Unify localname. Remove hop from `tramp-file-name' structure.
136 (setq file (tramp-compat-file-name-unquote file) 137 (setq key (tramp-file-name-unify key file))
137 key (copy-tramp-file-name key))
138 (setf (tramp-file-name-localname key)
139 (tramp-run-real-handler #'directory-file-name (list file))
140 (tramp-file-name-hop key) nil)
141 (let* ((hash (tramp-get-hash-table key)) 138 (let* ((hash (tramp-get-hash-table key))
142 (cached (and (hash-table-p hash) (gethash property hash))) 139 (cached (and (hash-table-p hash) (gethash property hash)))
143 (cached-at (and (consp cached) (format-time-string "%T" (car cached)))) 140 (cached-at (and (consp cached) (format-time-string "%T" (car cached))))
@@ -161,7 +158,8 @@ Return DEFAULT if not set."
161 158
162 (tramp-message 159 (tramp-message
163 key 8 "%s %s %s; inhibit: %s; cache used: %s; cached at: %s" 160 key 8 "%s %s %s; inhibit: %s; cache used: %s; cached at: %s"
164 file property value remote-file-name-inhibit-cache cache-used cached-at) 161 (tramp-file-name-localname key)
162 property value remote-file-name-inhibit-cache cache-used cached-at)
165 ;; For analysis purposes, count the number of getting this file attribute. 163 ;; For analysis purposes, count the number of getting this file attribute.
166 (when (>= tramp-verbose 10) 164 (when (>= tramp-verbose 10)
167 (let* ((var (intern (concat "tramp-cache-get-count-" property))) 165 (let* ((var (intern (concat "tramp-cache-get-count-" property)))
@@ -181,15 +179,12 @@ Return DEFAULT if not set."
181 "Set the PROPERTY of FILE to VALUE, in the cache context of KEY. 179 "Set the PROPERTY of FILE to VALUE, in the cache context of KEY.
182Return VALUE." 180Return VALUE."
183 ;; Unify localname. Remove hop from `tramp-file-name' structure. 181 ;; Unify localname. Remove hop from `tramp-file-name' structure.
184 (setq file (tramp-compat-file-name-unquote file) 182 (setq key (tramp-file-name-unify key file))
185 key (copy-tramp-file-name key))
186 (setf (tramp-file-name-localname key)
187 (tramp-run-real-handler #'directory-file-name (list file))
188 (tramp-file-name-hop key) nil)
189 (let ((hash (tramp-get-hash-table key))) 183 (let ((hash (tramp-get-hash-table key)))
190 ;; We put the timestamp there. 184 ;; We put the timestamp there.
191 (puthash property (cons (current-time) value) hash) 185 (puthash property (cons (current-time) value) hash)
192 (tramp-message key 8 "%s %s %s" file property value) 186 (tramp-message
187 key 8 "%s %s %s" (tramp-file-name-localname key) property value)
193 ;; For analysis purposes, count the number of setting this file attribute. 188 ;; For analysis purposes, count the number of setting this file attribute.
194 (when (>= tramp-verbose 10) 189 (when (>= tramp-verbose 10)
195 (let* ((var (intern (concat "tramp-cache-set-count-" property))) 190 (let* ((var (intern (concat "tramp-cache-set-count-" property)))
@@ -214,13 +209,9 @@ Return VALUE."
214(defun tramp-flush-file-property (key file property) 209(defun tramp-flush-file-property (key file property)
215 "Remove PROPERTY of FILE in the cache context of KEY." 210 "Remove PROPERTY of FILE in the cache context of KEY."
216 ;; Unify localname. Remove hop from `tramp-file-name' structure. 211 ;; Unify localname. Remove hop from `tramp-file-name' structure.
217 (setq file (tramp-compat-file-name-unquote file) 212 (setq key (tramp-file-name-unify key file))
218 key (copy-tramp-file-name key))
219 (setf (tramp-file-name-localname key)
220 (tramp-run-real-handler #'directory-file-name (list file))
221 (tramp-file-name-hop key) nil)
222 (remhash property (tramp-get-hash-table key)) 213 (remhash property (tramp-get-hash-table key))
223 (tramp-message key 8 "%s %s" file property) 214 (tramp-message key 8 "%s %s" (tramp-file-name-localname key) property)
224 (when (>= tramp-verbose 10) 215 (when (>= tramp-verbose 10)
225 (let ((var (intern (concat "tramp-cache-set-count-" property)))) 216 (let ((var (intern (concat "tramp-cache-set-count-" property))))
226 (makunbound var)))) 217 (makunbound var))))
@@ -232,10 +223,7 @@ Return VALUE."
232 (when-let ((file (file-name-directory file)) 223 (when-let ((file (file-name-directory file))
233 (file (directory-file-name file))) 224 (file (directory-file-name file)))
234 ;; Unify localname. Remove hop from `tramp-file-name' structure. 225 ;; Unify localname. Remove hop from `tramp-file-name' structure.
235 (setq file (tramp-compat-file-name-unquote file) 226 (setq key (tramp-file-name-unify key file))
236 key (copy-tramp-file-name key))
237 (setf (tramp-file-name-localname key) file
238 (tramp-file-name-hop key) nil)
239 (dolist (property (hash-table-keys (tramp-get-hash-table key))) 227 (dolist (property (hash-table-keys (tramp-get-hash-table key)))
240 (when (string-match-p 228 (when (string-match-p
241 "^\\(directory-\\|file-name-all-completions\\|file-entries\\)" 229 "^\\(directory-\\|file-name-all-completions\\|file-entries\\)"
@@ -245,14 +233,10 @@ Return VALUE."
245;;;###tramp-autoload 233;;;###tramp-autoload
246(defun tramp-flush-file-properties (key file) 234(defun tramp-flush-file-properties (key file)
247 "Remove all properties of FILE in the cache context of KEY." 235 "Remove all properties of FILE in the cache context of KEY."
248 (let* ((file (tramp-run-real-handler #'directory-file-name (list file))) 236 (let ((truename (tramp-get-file-property key file "file-truename")))
249 (truename (tramp-get-file-property key file "file-truename")))
250 ;; Unify localname. Remove hop from `tramp-file-name' structure. 237 ;; Unify localname. Remove hop from `tramp-file-name' structure.
251 (setq file (tramp-compat-file-name-unquote file) 238 (setq key (tramp-file-name-unify key file))
252 key (copy-tramp-file-name key)) 239 (tramp-message key 8 "%s" (tramp-file-name-localname key))
253 (setf (tramp-file-name-localname key) file
254 (tramp-file-name-hop key) nil)
255 (tramp-message key 8 "%s" file)
256 (remhash key tramp-cache-data) 240 (remhash key tramp-cache-data)
257 ;; Remove file properties of symlinks. 241 ;; Remove file properties of symlinks.
258 (when (and (stringp truename) 242 (when (and (stringp truename)
@@ -265,9 +249,8 @@ Return VALUE."
265(defun tramp-flush-directory-properties (key directory) 249(defun tramp-flush-directory-properties (key directory)
266 "Remove all properties of DIRECTORY in the cache context of KEY. 250 "Remove all properties of DIRECTORY in the cache context of KEY.
267Remove also properties of all files in subdirectories." 251Remove also properties of all files in subdirectories."
268 (setq directory (tramp-compat-file-name-unquote directory)) 252 (let* ((directory
269 (let* ((directory (tramp-run-real-handler 253 (directory-file-name (tramp-compat-file-name-unquote directory)))
270 #'directory-file-name (list directory)))
271 (truename (tramp-get-file-property key directory "file-truename"))) 254 (truename (tramp-get-file-property key directory "file-truename")))
272 (tramp-message key 8 "%s" directory) 255 (tramp-message key 8 "%s" directory)
273 (dolist (key (hash-table-keys tramp-cache-data)) 256 (dolist (key (hash-table-keys tramp-cache-data))
@@ -288,6 +271,7 @@ Remove also properties of all files in subdirectories."
288;; not show proper directory contents when a file has been copied or 271;; not show proper directory contents when a file has been copied or
289;; deleted before. We must apply `save-match-data', because it would 272;; deleted before. We must apply `save-match-data', because it would
290;; corrupt other packages otherwise (reported from org). 273;; corrupt other packages otherwise (reported from org).
274;;;###tramp-autoload
291(defun tramp-flush-file-function () 275(defun tramp-flush-file-function ()
292 "Flush all Tramp cache properties from `buffer-file-name'. 276 "Flush all Tramp cache properties from `buffer-file-name'.
293This is suppressed for temporary buffers." 277This is suppressed for temporary buffers."
@@ -299,8 +283,8 @@ This is suppressed for temporary buffers."
299 default-directory)) 283 default-directory))
300 (tramp-verbose 0)) 284 (tramp-verbose 0))
301 (when (tramp-tramp-file-p bfn) 285 (when (tramp-tramp-file-p bfn)
302 (with-parsed-tramp-file-name bfn nil 286 (tramp-flush-file-properties
303 (tramp-flush-file-properties v localname))))))) 287 (tramp-dissect-file-name bfn) (tramp-file-local-name bfn)))))))
304 288
305(add-hook 'before-revert-hook #'tramp-flush-file-function) 289(add-hook 'before-revert-hook #'tramp-flush-file-function)
306(add-hook 'eshell-pre-command-hook #'tramp-flush-file-function) 290(add-hook 'eshell-pre-command-hook #'tramp-flush-file-function)
@@ -314,6 +298,61 @@ This is suppressed for temporary buffers."
314 (remove-hook 'kill-buffer-hook 298 (remove-hook 'kill-buffer-hook
315 #'tramp-flush-file-function))) 299 #'tramp-flush-file-function)))
316 300
301;;;###tramp-autoload
302(defmacro with-tramp-file-property (key file property &rest body)
303 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
304FILE must be a local file name on a connection identified via KEY."
305 (declare (indent 3) (debug t))
306 `(let ((value (tramp-get-file-property
307 ,key ,file ,property tramp-cache-undefined)))
308 (when (eq value tramp-cache-undefined)
309 ;; We cannot pass @body as parameter to
310 ;; `tramp-set-file-property' because it mangles our debug
311 ;; messages.
312 (setq value (progn ,@body))
313 (tramp-set-file-property ,key ,file ,property value))
314 value))
315
316;;;###tramp-autoload
317(defmacro with-tramp-saved-file-property (key file property &rest body)
318 "Save PROPERTY, run BODY, reset PROPERTY.
319Preserve timestamps."
320 (declare (indent 3) (debug t))
321 `(progn
322 ;; Unify localname. Remove hop from `tramp-file-name' structure.
323 (setq ,key (tramp-file-name-unify ,key ,file))
324 (let* ((hash (tramp-get-hash-table ,key))
325 (cached (and (hash-table-p hash) (gethash ,property hash))))
326 (unwind-protect (progn ,@body)
327 ;; Reset PROPERTY. Recompute hash, it could have been flushed.
328 (setq hash (tramp-get-hash-table ,key))
329 (if (consp cached)
330 (puthash ,property cached hash)
331 (remhash ,property hash))))))
332
333;;;###tramp-autoload
334(defmacro with-tramp-saved-file-properties (key file properties &rest body)
335 "Save PROPERTIES, run BODY, reset PROPERTIES.
336PROPERTIES is a list of file properties (strings).
337Preserve timestamps."
338 (declare (indent 3) (debug t))
339 `(progn
340 ;; Unify localname. Remove hop from `tramp-file-name' structure.
341 (setq ,key (tramp-file-name-unify ,key ,file))
342 (let* ((hash (tramp-get-hash-table ,key))
343 (values
344 (and (hash-table-p hash)
345 (mapcar
346 (lambda (property) (cons property (gethash property hash)))
347 ,properties))))
348 (unwind-protect (progn ,@body)
349 ;; Reset PROPERTIES. Recompute hash, it could have been flushed.
350 (setq hash (tramp-get-hash-table ,key))
351 (dolist (value values)
352 (if (consp (cdr value))
353 (puthash (car value) (cdr value) hash)
354 (remhash (car value) hash)))))))
355
317;;; -- Properties -- 356;;; -- Properties --
318 357
319;;;###tramp-autoload 358;;;###tramp-autoload
@@ -397,6 +436,57 @@ used to cache connection properties of the local machine."
397 (remhash key tramp-cache-data)) 436 (remhash key tramp-cache-data))
398 437
399;;;###tramp-autoload 438;;;###tramp-autoload
439(defmacro with-tramp-connection-property (key property &rest body)
440 "Check in Tramp for property PROPERTY, otherwise execute BODY and set."
441 (declare (indent 2) (debug t))
442 `(let ((value (tramp-get-connection-property
443 ,key ,property tramp-cache-undefined)))
444 (when (eq value tramp-cache-undefined)
445 ;; We cannot pass ,@body as parameter to
446 ;; `tramp-set-connection-property' because it mangles our debug
447 ;; messages.
448 (setq value (progn ,@body))
449 (tramp-set-connection-property ,key ,property value))
450 value))
451
452;;;###tramp-autoload
453(defmacro with-tramp-saved-connection-property (key property &rest body)
454 "Save PROPERTY, run BODY, reset PROPERTY."
455 (declare (indent 2) (debug t))
456 `(progn
457 (setq ,key (tramp-file-name-unify ,key))
458 (let* ((hash (tramp-get-hash-table ,key))
459 (cached (and (hash-table-p hash)
460 (gethash ,property hash tramp-cache-undefined))))
461 (unwind-protect (progn ,@body)
462 ;; Reset PROPERTY. Recompute hash, it could have been flushed.
463 (setq hash (tramp-get-hash-table ,key))
464 (if (not (eq cached tramp-cache-undefined))
465 (puthash ,property cached hash)
466 (remhash ,property hash))))))
467
468;;;###tramp-autoload
469(defmacro with-tramp-saved-connection-properties (key properties &rest body)
470 "Save PROPERTIES, run BODY, reset PROPERTIES.
471PROPERTIES is a list of file properties (strings)."
472 (declare (indent 2) (debug t))
473 `(progn
474 (setq ,key (tramp-file-name-unify ,key))
475 (let* ((hash (tramp-get-hash-table ,key))
476 (values
477 (mapcar
478 (lambda (property)
479 (cons property (gethash property hash tramp-cache-undefined)))
480 ,properties)))
481 (unwind-protect (progn ,@body)
482 ;; Reset PROPERTIES. Recompute hash, it could have been flushed.
483 (setq hash (tramp-get-hash-table ,key))
484 (dolist (value values)
485 (if (not (eq (cdr value) tramp-cache-undefined))
486 (puthash (car value) (cdr value) hash)
487 (remhash (car value) hash)))))))
488
489;;;###tramp-autoload
400(defun tramp-cache-print (table) 490(defun tramp-cache-print (table)
401 "Print hash table TABLE." 491 "Print hash table TABLE."
402 (when (hash-table-p table) 492 (when (hash-table-p table)
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el
index 5c8012e553b..f7704864ec6 100644
--- a/lisp/net/tramp-cmds.el
+++ b/lisp/net/tramp-cmds.el
@@ -139,7 +139,7 @@ When called interactively, a Tramp connection has to be selected."
139 (when (bufferp buf) (kill-buffer buf))) 139 (when (bufferp buf) (kill-buffer buf)))
140 140
141 ;; Flush file cache. 141 ;; Flush file cache.
142 (tramp-flush-directory-properties vec "") 142 (tramp-flush-directory-properties vec "/")
143 143
144 ;; Flush connection cache. 144 ;; Flush connection cache.
145 (tramp-flush-connection-properties vec) 145 (tramp-flush-connection-properties vec)
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 4fcd132ab0a..7f385292626 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -824,24 +824,21 @@ WILDCARD is not supported."
824 824
825(defun tramp-crypt-handle-set-file-modes (filename mode &optional flag) 825(defun tramp-crypt-handle-set-file-modes (filename mode &optional flag)
826 "Like `set-file-modes' for Tramp files." 826 "Like `set-file-modes' for Tramp files."
827 (with-parsed-tramp-file-name filename nil 827 (tramp-skeleton-set-file-modes-times-uid-gid filename
828 (tramp-flush-file-properties v localname)
829 (let (tramp-crypt-enabled) 828 (let (tramp-crypt-enabled)
830 (tramp-compat-set-file-modes 829 (tramp-compat-set-file-modes
831 (tramp-crypt-encrypt-file-name filename) mode flag)))) 830 (tramp-crypt-encrypt-file-name filename) mode flag))))
832 831
833(defun tramp-crypt-handle-set-file-times (filename &optional time flag) 832(defun tramp-crypt-handle-set-file-times (filename &optional time flag)
834 "Like `set-file-times' for Tramp files." 833 "Like `set-file-times' for Tramp files."
835 (with-parsed-tramp-file-name filename nil 834 (tramp-skeleton-set-file-modes-times-uid-gid filename
836 (tramp-flush-file-properties v localname)
837 (let (tramp-crypt-enabled) 835 (let (tramp-crypt-enabled)
838 (tramp-compat-set-file-times 836 (tramp-compat-set-file-times
839 (tramp-crypt-encrypt-file-name filename) time flag)))) 837 (tramp-crypt-encrypt-file-name filename) time flag))))
840 838
841(defun tramp-crypt-handle-set-file-uid-gid (filename &optional uid gid) 839(defun tramp-crypt-handle-set-file-uid-gid (filename &optional uid gid)
842 "Like `tramp-set-file-uid-gid' for Tramp files." 840 "Like `tramp-set-file-uid-gid' for Tramp files."
843 (with-parsed-tramp-file-name filename nil 841 (tramp-skeleton-set-file-modes-times-uid-gid filename
844 (tramp-flush-file-properties v localname)
845 (let (tramp-crypt-enabled) 842 (let (tramp-crypt-enabled)
846 (tramp-set-file-uid-gid 843 (tramp-set-file-uid-gid
847 (tramp-crypt-encrypt-file-name filename) uid gid)))) 844 (tramp-crypt-encrypt-file-name filename) uid gid))))
diff --git a/lisp/net/tramp-ftp.el b/lisp/net/tramp-ftp.el
index d4bbb944793..dd7e0f9f342 100644
--- a/lisp/net/tramp-ftp.el
+++ b/lisp/net/tramp-ftp.el
@@ -31,7 +31,6 @@
31(require 'tramp) 31(require 'tramp)
32 32
33;; Pacify byte-compiler. 33;; Pacify byte-compiler.
34(declare-function tramp-archive-file-name-handler "tramp-archive")
35(defvar ange-ftp-ftp-name-arg) 34(defvar ange-ftp-ftp-name-arg)
36(defvar ange-ftp-ftp-name-res) 35(defvar ange-ftp-ftp-name-res)
37(defvar ange-ftp-name-format) 36(defvar ange-ftp-name-format)
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 2f97b2cb916..0b40ff867f2 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -960,6 +960,15 @@ The global value will always be nil; it is bound where needed.")
960 960
961;; File name primitives. 961;; File name primitives.
962 962
963(defun tramp-gvfs-info (filename &optional arg)
964 "Check FILENAME via `gvfs-info'.
965Set file property \"file-exists-p\" with the result."
966 (with-parsed-tramp-file-name filename nil
967 (tramp-set-file-property
968 v localname "file-exists-p"
969 (tramp-gvfs-send-command
970 v "gvfs-info" arg (tramp-gvfs-url-file-name filename)))))
971
963(defun tramp-gvfs-do-copy-or-rename-file 972(defun tramp-gvfs-do-copy-or-rename-file
964 (op filename newname &optional ok-if-already-exists keep-date 973 (op filename newname &optional ok-if-already-exists keep-date
965 preserve-uid-gid preserve-extended-attributes) 974 preserve-uid-gid preserve-extended-attributes)
@@ -1046,12 +1055,9 @@ file names."
1046 ;; code in case of direct copy/move. Apply 1055 ;; code in case of direct copy/move. Apply
1047 ;; sanity checks. 1056 ;; sanity checks.
1048 (or (not equal-remote) 1057 (or (not equal-remote)
1049 (tramp-gvfs-send-command 1058 (tramp-gvfs-info newname)
1050 v "gvfs-info" (tramp-gvfs-url-file-name newname))
1051 (eq op 'copy) 1059 (eq op 'copy)
1052 (not (tramp-gvfs-send-command 1060 (not (tramp-gvfs-info filename))))
1053 v "gvfs-info"
1054 (tramp-gvfs-url-file-name filename)))))
1055 1061
1056 (if (or (not equal-remote) 1062 (if (or (not equal-remote)
1057 (and equal-remote 1063 (and equal-remote
@@ -1111,8 +1117,9 @@ file names."
1111 (tramp-error 1117 (tramp-error
1112 v 'file-error "Couldn't delete non-empty %s" directory))) 1118 v 'file-error "Couldn't delete non-empty %s" directory)))
1113 1119
1114 (unless (tramp-gvfs-send-command 1120 (unless (and (tramp-gvfs-send-command
1115 v "gvfs-rm" (tramp-gvfs-url-file-name directory)) 1121 v "gvfs-rm" (tramp-gvfs-url-file-name directory))
1122 (not (tramp-gvfs-info directory)))
1116 ;; Propagate the error. 1123 ;; Propagate the error.
1117 (with-current-buffer (tramp-get-connection-buffer v) 1124 (with-current-buffer (tramp-get-connection-buffer v)
1118 (goto-char (point-min)) 1125 (goto-char (point-min))
@@ -1125,8 +1132,9 @@ file names."
1125 (tramp-flush-file-properties v localname) 1132 (tramp-flush-file-properties v localname)
1126 (if (and delete-by-moving-to-trash trash) 1133 (if (and delete-by-moving-to-trash trash)
1127 (move-file-to-trash filename) 1134 (move-file-to-trash filename)
1128 (unless (tramp-gvfs-send-command 1135 (unless (and (tramp-gvfs-send-command
1129 v "gvfs-rm" (tramp-gvfs-url-file-name filename)) 1136 v "gvfs-rm" (tramp-gvfs-url-file-name filename))
1137 (not (tramp-gvfs-info filename)))
1130 ;; Propagate the error. 1138 ;; Propagate the error.
1131 (with-current-buffer (tramp-get-connection-buffer v) 1139 (with-current-buffer (tramp-get-connection-buffer v)
1132 (goto-char (point-min)) 1140 (goto-char (point-min))
@@ -1239,10 +1247,8 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1239 (if file-system " system" "") localname) 1247 (if file-system " system" "") localname)
1240 ;; Send command. 1248 ;; Send command.
1241 (if file-system 1249 (if file-system
1242 (tramp-gvfs-send-command 1250 (tramp-gvfs-info filename "--filesystem")
1243 v "gvfs-info" "--filesystem" (tramp-gvfs-url-file-name filename)) 1251 (tramp-gvfs-info filename))
1244 (tramp-gvfs-send-command
1245 v "gvfs-info" (tramp-gvfs-url-file-name filename)))
1246 ;; Parse output. 1252 ;; Parse output.
1247 (with-current-buffer (tramp-get-connection-buffer v) 1253 (with-current-buffer (tramp-get-connection-buffer v)
1248 (goto-char (point-min)) 1254 (goto-char (point-min))
@@ -1547,8 +1553,10 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1547 (make-directory ldir parents)) 1553 (make-directory ldir parents))
1548 ;; Just do it. 1554 ;; Just do it.
1549 (or (when-let ((mkdir-succeeded 1555 (or (when-let ((mkdir-succeeded
1550 (tramp-gvfs-send-command 1556 (and
1551 v "gvfs-mkdir" (tramp-gvfs-url-file-name dir)))) 1557 (tramp-gvfs-send-command
1558 v "gvfs-mkdir" (tramp-gvfs-url-file-name dir))
1559 (tramp-gvfs-info dir))))
1552 (set-file-modes dir (default-file-modes)) 1560 (set-file-modes dir (default-file-modes))
1553 mkdir-succeeded) 1561 mkdir-succeeded)
1554 (and parents (file-directory-p dir)) 1562 (and parents (file-directory-p dir))
@@ -1582,16 +1590,14 @@ If FILE-SYSTEM is non-nil, return file system attributes."
1582 1590
1583(defun tramp-gvfs-handle-set-file-modes (filename mode &optional flag) 1591(defun tramp-gvfs-handle-set-file-modes (filename mode &optional flag)
1584 "Like `set-file-modes' for Tramp files." 1592 "Like `set-file-modes' for Tramp files."
1585 (with-parsed-tramp-file-name filename nil 1593 (tramp-skeleton-set-file-modes-times-uid-gid filename
1586 (tramp-flush-file-properties v localname)
1587 (tramp-gvfs-set-attribute 1594 (tramp-gvfs-set-attribute
1588 v (if (eq flag 'nofollow) "-nt" "-t") "uint32" 1595 v (if (eq flag 'nofollow) "-nt" "-t") "uint32"
1589 (tramp-gvfs-url-file-name filename) "unix::mode" (number-to-string mode)))) 1596 (tramp-gvfs-url-file-name filename) "unix::mode" (number-to-string mode))))
1590 1597
1591(defun tramp-gvfs-handle-set-file-times (filename &optional time flag) 1598(defun tramp-gvfs-handle-set-file-times (filename &optional time flag)
1592 "Like `set-file-times' for Tramp files." 1599 "Like `set-file-times' for Tramp files."
1593 (with-parsed-tramp-file-name filename nil 1600 (tramp-skeleton-set-file-modes-times-uid-gid filename
1594 (tramp-flush-file-properties v localname)
1595 (tramp-gvfs-set-attribute 1601 (tramp-gvfs-set-attribute
1596 v (if (eq flag 'nofollow) "-nt" "-t") "uint64" 1602 v (if (eq flag 'nofollow) "-nt" "-t") "uint64"
1597 (tramp-gvfs-url-file-name filename) "time::modified" 1603 (tramp-gvfs-url-file-name filename) "time::modified"
@@ -1644,8 +1650,7 @@ ID-FORMAT valid values are `string' and `integer'."
1644 1650
1645(defun tramp-gvfs-handle-set-file-uid-gid (filename &optional uid gid) 1651(defun tramp-gvfs-handle-set-file-uid-gid (filename &optional uid gid)
1646 "Like `tramp-set-file-uid-gid' for Tramp files." 1652 "Like `tramp-set-file-uid-gid' for Tramp files."
1647 (with-parsed-tramp-file-name filename nil 1653 (tramp-skeleton-set-file-modes-times-uid-gid filename
1648 (tramp-flush-file-properties v localname)
1649 (when (natnump uid) 1654 (when (natnump uid)
1650 (tramp-gvfs-set-attribute 1655 (tramp-gvfs-set-attribute
1651 v "-t" "uint32" 1656 v "-t" "uint32"
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 172933859c1..d88e388cd56 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1113,7 +1113,8 @@ component is used as the target of the symlink."
1113 (tramp-file-name-equal-p v (tramp-dissect-file-name target))) 1113 (tramp-file-name-equal-p v (tramp-dissect-file-name target)))
1114 (setq target (tramp-file-local-name (expand-file-name target)))) 1114 (setq target (tramp-file-local-name (expand-file-name target))))
1115 ;; There could be a cyclic link. 1115 ;; There could be a cyclic link.
1116 (tramp-flush-file-properties v target)) 1116 (tramp-flush-file-properties
1117 v (expand-file-name target (tramp-file-local-name default-directory))))
1117 1118
1118 ;; If TARGET is still remote, quote it. 1119 ;; If TARGET is still remote, quote it.
1119 (if (tramp-tramp-file-p target) 1120 (if (tramp-tramp-file-p target)
@@ -1465,12 +1466,11 @@ of."
1465 1466
1466(defun tramp-sh-handle-set-file-modes (filename mode &optional flag) 1467(defun tramp-sh-handle-set-file-modes (filename mode &optional flag)
1467 "Like `set-file-modes' for Tramp files." 1468 "Like `set-file-modes' for Tramp files."
1468 (with-parsed-tramp-file-name filename nil 1469 ;; We need "chmod -h" when the flag is set.
1469 ;; We need "chmod -h" when the flag is set. 1470 (when (or (not (eq flag 'nofollow))
1470 (when (or (not (eq flag 'nofollow)) 1471 (not (file-symlink-p filename))
1471 (not (file-symlink-p filename)) 1472 (tramp-get-remote-chmod-h (tramp-dissect-file-name filename)))
1472 (tramp-get-remote-chmod-h v)) 1473 (tramp-skeleton-set-file-modes-times-uid-gid filename
1473 (tramp-flush-file-properties v localname)
1474 ;; FIXME: extract the proper text from chmod's stderr. 1474 ;; FIXME: extract the proper text from chmod's stderr.
1475 (tramp-barf-unless-okay 1475 (tramp-barf-unless-okay
1476 v 1476 v
@@ -1482,9 +1482,8 @@ of."
1482 1482
1483(defun tramp-sh-handle-set-file-times (filename &optional time flag) 1483(defun tramp-sh-handle-set-file-times (filename &optional time flag)
1484 "Like `set-file-times' for Tramp files." 1484 "Like `set-file-times' for Tramp files."
1485 (with-parsed-tramp-file-name filename nil 1485 (tramp-skeleton-set-file-modes-times-uid-gid filename
1486 (when (tramp-get-remote-touch v) 1486 (when (tramp-get-remote-touch v)
1487 (tramp-flush-file-properties v localname)
1488 (let ((time 1487 (let ((time
1489 (if (or (null time) 1488 (if (or (null time)
1490 (tramp-compat-time-equal-p time tramp-time-doesnt-exist) 1489 (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
@@ -1543,9 +1542,9 @@ ID-FORMAT valid values are `string' and `integer'."
1543 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly 1542 ;; another implementation, see `dired-do-chown'. OTOH, it is mostly
1544 ;; working with su(do)? when it is needed, so it shall succeed in 1543 ;; working with su(do)? when it is needed, so it shall succeed in
1545 ;; the majority of cases. 1544 ;; the majority of cases.
1546 ;; Don't modify `last-coding-system-used' by accident. 1545 (tramp-skeleton-set-file-modes-times-uid-gid filename
1547 (let ((last-coding-system-used last-coding-system-used)) 1546 ;; Don't modify `last-coding-system-used' by accident.
1548 (with-parsed-tramp-file-name filename nil 1547 (let ((last-coding-system-used last-coding-system-used))
1549 (if (and (zerop (user-uid)) (tramp-local-host-p v)) 1548 (if (and (zerop (user-uid)) (tramp-local-host-p v))
1550 ;; If we are root on the local host, we can do it directly. 1549 ;; If we are root on the local host, we can do it directly.
1551 (tramp-set-file-uid-gid localname uid gid) 1550 (tramp-set-file-uid-gid localname uid gid)
@@ -1767,10 +1766,11 @@ ID-FORMAT valid values are `string' and `integer'."
1767;; files. 1766;; files.
1768(defun tramp-sh-handle-file-name-all-completions (filename directory) 1767(defun tramp-sh-handle-file-name-all-completions (filename directory)
1769 "Like `file-name-all-completions' for Tramp files." 1768 "Like `file-name-all-completions' for Tramp files."
1770 (unless (tramp-compat-string-search "/" filename) 1769 (with-parsed-tramp-file-name (expand-file-name directory) nil
1771 (all-completions 1770 (when (and (not (tramp-compat-string-search "/" filename))
1772 filename 1771 (tramp-connectable-p v))
1773 (with-parsed-tramp-file-name (expand-file-name directory) nil 1772 (all-completions
1773 filename
1774 (with-tramp-file-property v localname "file-name-all-completions" 1774 (with-tramp-file-property v localname "file-name-all-completions"
1775 (let (result) 1775 (let (result)
1776 ;; Get a list of directories and files, including reliably 1776 ;; Get a list of directories and files, including reliably
@@ -2197,6 +2197,8 @@ the uid and gid from FILENAME."
2197 (file-name-directory (concat prefix localname2))) 2197 (file-name-directory (concat prefix localname2)))
2198 (or (file-directory-p (concat prefix localname2)) 2198 (or (file-directory-p (concat prefix localname2))
2199 (file-writable-p (concat prefix localname2)))) 2199 (file-writable-p (concat prefix localname2))))
2200 (with-parsed-tramp-file-name prefix nil
2201 (tramp-flush-file-properties v localname2))
2200 (tramp-do-copy-or-rename-file-directly 2202 (tramp-do-copy-or-rename-file-directly
2201 op (concat prefix localname1) (concat prefix localname2) 2203 op (concat prefix localname1) (concat prefix localname2)
2202 ok-if-already-exists keep-date preserve-uid-gid) 2204 ok-if-already-exists keep-date preserve-uid-gid)
@@ -2406,52 +2408,52 @@ The method used must be an out-of-band method."
2406 2408
2407 (with-temp-buffer 2409 (with-temp-buffer
2408 (unwind-protect 2410 (unwind-protect
2409 (with-tramp-saved-connection-property v "process-name" 2411 (with-tramp-saved-connection-properties
2410 (with-tramp-saved-connection-property v "process-buffer" 2412 v '("process-name" "process-buffer")
2411 ;; The default directory must be remote. 2413 ;; The default directory must be remote.
2412 (let ((default-directory 2414 (let ((default-directory
2413 (file-name-directory (if v1 filename newname))) 2415 (file-name-directory (if v1 filename newname)))
2414 (process-environment (copy-sequence process-environment))) 2416 (process-environment (copy-sequence process-environment)))
2415 ;; Set the transfer process properties. 2417 ;; Set the transfer process properties.
2416 (tramp-set-connection-property 2418 (tramp-set-connection-property
2417 v "process-name" (buffer-name (current-buffer))) 2419 v "process-name" (buffer-name (current-buffer)))
2418 (tramp-set-connection-property 2420 (tramp-set-connection-property
2419 v "process-buffer" (current-buffer)) 2421 v "process-buffer" (current-buffer))
2420 (when copy-env 2422 (when copy-env
2421 (tramp-message 2423 (tramp-message
2422 v 6 "%s=\"%s\"" 2424 v 6 "%s=\"%s\""
2423 (car copy-env) (string-join (cdr copy-env) " ")) 2425 (car copy-env) (string-join (cdr copy-env) " "))
2424 (setenv (car copy-env) (string-join (cdr copy-env) " "))) 2426 (setenv (car copy-env) (string-join (cdr copy-env) " ")))
2425 (setq 2427 (setq
2426 copy-args 2428 copy-args
2427 (append 2429 (append
2428 copy-args 2430 copy-args
2429 (if remote-copy-program 2431 (if remote-copy-program
2430 (list (if v1 (concat ">" target) (concat "<" source))) 2432 (list (if v1 (concat ">" target) (concat "<" source)))
2431 (list source target))) 2433 (list source target)))
2432 ;; Use an asynchronous process. By this, password 2434 ;; Use an asynchronous process. By this, password
2433 ;; can be handled. We don't set a timeout, because 2435 ;; can be handled. We don't set a timeout, because
2434 ;; the copying of large files can last longer than 2436 ;; the copying of large files can last longer than 60
2435 ;; 60 secs. 2437 ;; secs.
2436 p (let ((default-directory 2438 p (let ((default-directory
2437 tramp-compat-temporary-file-directory)) 2439 tramp-compat-temporary-file-directory))
2438 (apply 2440 (apply
2439 #'start-process 2441 #'start-process
2440 (tramp-get-connection-name v) 2442 (tramp-get-connection-name v)
2441 (tramp-get-connection-buffer v) 2443 (tramp-get-connection-buffer v)
2442 copy-program copy-args))) 2444 copy-program copy-args)))
2443 (tramp-message v 6 "%s" (string-join (process-command p) " ")) 2445 (tramp-message v 6 "%s" (string-join (process-command p) " "))
2444 (process-put p 'vector v) 2446 (process-put p 'vector v)
2445 (process-put p 'adjust-window-size-function #'ignore) 2447 (process-put p 'adjust-window-size-function #'ignore)
2446 (set-process-query-on-exit-flag p nil) 2448 (set-process-query-on-exit-flag p nil)
2447 2449
2448 ;; We must adapt `tramp-local-end-of-line' for sending 2450 ;; We must adapt `tramp-local-end-of-line' for sending
2449 ;; the password. Also, we indicate that perhaps several 2451 ;; the password. Also, we indicate that perhaps
2450 ;; password prompts might appear. 2452 ;; several password prompts might appear.
2451 (let ((tramp-local-end-of-line tramp-rsh-end-of-line) 2453 (let ((tramp-local-end-of-line tramp-rsh-end-of-line)
2452 (tramp-password-prompt-not-unique (and v1 v2))) 2454 (tramp-password-prompt-not-unique (and v1 v2)))
2453 (tramp-process-actions 2455 (tramp-process-actions
2454 p v nil tramp-actions-copy-out-of-band))))) 2456 p v nil tramp-actions-copy-out-of-band))))
2455 2457
2456 ;; Clear the remote prompt. 2458 ;; Clear the remote prompt.
2457 (when (and remote-copy-program 2459 (when (and remote-copy-program
@@ -2510,12 +2512,12 @@ The method used must be an out-of-band method."
2510 "Like `delete-file' for Tramp files." 2512 "Like `delete-file' for Tramp files."
2511 (setq filename (expand-file-name filename)) 2513 (setq filename (expand-file-name filename))
2512 (with-parsed-tramp-file-name filename nil 2514 (with-parsed-tramp-file-name filename nil
2513 (tramp-flush-file-properties v localname)
2514 (if (and delete-by-moving-to-trash trash) 2515 (if (and delete-by-moving-to-trash trash)
2515 (move-file-to-trash filename) 2516 (move-file-to-trash filename)
2516 (tramp-barf-unless-okay 2517 (tramp-barf-unless-okay
2517 v (format "rm -f %s" (tramp-shell-quote-argument localname)) 2518 v (format "rm -f %s" (tramp-shell-quote-argument localname))
2518 "Couldn't delete %s" filename)))) 2519 "Couldn't delete %s" filename))
2520 (tramp-flush-file-properties v localname)))
2519 2521
2520;; Dired. 2522;; Dired.
2521 2523
@@ -2966,102 +2968,102 @@ implementation will be used."
2966 name1 (format "%s<%d>" name i))) 2968 name1 (format "%s<%d>" name i)))
2967 (setq name name1) 2969 (setq name name1)
2968 2970
2969 (with-tramp-saved-connection-property v "process-name" 2971 (with-tramp-saved-connection-properties
2970 (with-tramp-saved-connection-property v "process-buffer" 2972 v '("process-name" "process-buffer")
2971 ;; Set the new process properties. 2973 ;; Set the new process properties.
2972 (tramp-set-connection-property v "process-name" name) 2974 (tramp-set-connection-property v "process-name" name)
2973 (tramp-set-connection-property v "process-buffer" buffer) 2975 (tramp-set-connection-property v "process-buffer" buffer)
2974 (with-current-buffer (tramp-get-connection-buffer v) 2976 (with-current-buffer (tramp-get-connection-buffer v)
2975 (unwind-protect 2977 (unwind-protect
2976 ;; We catch this event. Otherwise, 2978 ;; We catch this event. Otherwise, `make-process'
2977 ;; `make-process' could be called on the local 2979 ;; could be called on the local host.
2978 ;; host. 2980 (save-excursion
2979 (save-excursion 2981 (save-restriction
2980 (save-restriction 2982 ;; Activate narrowing in order to save BUFFER
2981 ;; Activate narrowing in order to save 2983 ;; contents. Clear also the modification
2982 ;; BUFFER contents. Clear also the 2984 ;; time; otherwise we might be interrupted by
2983 ;; modification time; otherwise we might be 2985 ;; `verify-visited-file-modtime'.
2984 ;; interrupted by `verify-visited-file-modtime'. 2986 (let ((buffer-undo-list t)
2985 (let ((buffer-undo-list t) 2987 (inhibit-read-only t)
2986 (inhibit-read-only t) 2988 (mark (point-max))
2987 (mark (point-max)) 2989 (coding-system-for-write
2988 (coding-system-for-write 2990 (if (symbolp coding) coding (car coding)))
2989 (if (symbolp coding) coding (car coding))) 2991 (coding-system-for-read
2990 (coding-system-for-read 2992 (if (symbolp coding) coding (cdr coding))))
2991 (if (symbolp coding) coding (cdr coding)))) 2993 (clear-visited-file-modtime)
2992 (clear-visited-file-modtime) 2994 (narrow-to-region (point-max) (point-max))
2995 (catch 'suppress
2996 ;; Set the pid of the remote shell. This
2997 ;; is needed when sending signals
2998 ;; remotely.
2999 (let ((pid
3000 (tramp-send-command-and-read v "echo $$")))
3001 (setq p (tramp-get-connection-process v))
3002 (process-put p 'remote-pid pid)
3003 (tramp-set-connection-property
3004 p "remote-pid" pid))
3005 ;; Disable carriage return to newline
3006 ;; translation. This does not work on
3007 ;; macOS, see Bug#50748.
3008 (when (and (memq connection-type '(nil pipe))
3009 (not
3010 (tramp-check-remote-uname v "Darwin")))
3011 (tramp-send-command v "stty -icrnl"))
3012 ;; `tramp-maybe-open-connection' and
3013 ;; `tramp-send-command-and-read' could
3014 ;; have trashed the connection buffer.
3015 ;; Remove this.
3016 (widen)
3017 (delete-region mark (point-max))
2993 (narrow-to-region (point-max) (point-max)) 3018 (narrow-to-region (point-max) (point-max))
2994 (catch 'suppress 3019 ;; Now do it.
2995 ;; Set the pid of the remote shell. This is 3020 (if command
2996 ;; needed when sending signals remotely. 3021 ;; Send the command.
2997 (let ((pid 3022 (tramp-send-command v command nil t) ; nooutput
2998 (tramp-send-command-and-read v "echo $$"))) 3023 ;; Check, whether a pty is associated.
2999 (setq p (tramp-get-connection-process v)) 3024 (unless (process-get p 'remote-tty)
3000 (process-put p 'remote-pid pid) 3025 (tramp-error
3001 (tramp-set-connection-property 3026 v 'file-error
3002 p "remote-pid" pid)) 3027 "pty association is not supported for `%s'"
3003 ;; Disable carriage return to newline 3028 name))))
3004 ;; translation. This does not work on 3029 ;; Set sentinel and filter.
3005 ;; macOS, see Bug#50748. 3030 (when sentinel
3006 (when (and (memq connection-type '(nil pipe)) 3031 (set-process-sentinel p sentinel))
3007 (not 3032 (when filter
3008 (tramp-check-remote-uname v "Darwin"))) 3033 (set-process-filter p filter))
3009 (tramp-send-command v "stty -icrnl")) 3034 (process-put p 'remote-command orig-command)
3010 ;; `tramp-maybe-open-connection' and 3035 (tramp-set-connection-property
3011 ;; `tramp-send-command-and-read' could have 3036 p "remote-command" orig-command)
3012 ;; trashed the connection buffer. Remove this. 3037 ;; Set query flag and process marker for
3013 (widen) 3038 ;; this process. We ignore errors, because
3014 (delete-region mark (point-max)) 3039 ;; the process could have finished already.
3015 (narrow-to-region (point-max) (point-max)) 3040 (ignore-errors
3016 ;; Now do it. 3041 (set-process-query-on-exit-flag p (null noquery))
3017 (if command 3042 (set-marker (process-mark p) (point)))
3018 ;; Send the command. 3043 ;; We must flush them here already;
3019 (tramp-send-command v command nil t) ; nooutput 3044 ;; otherwise `delete-file' will fail.
3020 ;; Check, whether a pty is associated. 3045 (tramp-flush-connection-property v "process-name")
3021 (unless (process-get p 'remote-tty) 3046 (tramp-flush-connection-property v "process-buffer")
3022 (tramp-error 3047 ;; Kill stderr process and delete named pipe.
3023 v 'file-error 3048 (when (bufferp stderr)
3024 "pty association is not supported for `%s'" 3049 (add-function
3025 name)))) 3050 :after (process-sentinel p)
3026 ;; Set sentinel and filter. 3051 (lambda (_proc _msg)
3027 (when sentinel 3052 (ignore-errors
3028 (set-process-sentinel p sentinel)) 3053 (while (accept-process-output
3029 (when filter 3054 (get-buffer-process stderr) 0 nil t))
3030 (set-process-filter p filter)) 3055 (delete-process (get-buffer-process stderr)))
3031 (process-put p 'remote-command orig-command) 3056 (ignore-errors
3032 (tramp-set-connection-property 3057 (delete-file remote-tmpstderr)))))
3033 p "remote-command" orig-command) 3058 ;; Return process.
3034 ;; Set query flag and process marker for 3059 p)))
3035 ;; this process. We ignore errors, 3060
3036 ;; because the process could have finished 3061 ;; Save exit.
3037 ;; already. 3062 (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
3038 (ignore-errors 3063 (ignore-errors
3039 (set-process-query-on-exit-flag p (null noquery)) 3064 (set-process-buffer p nil)
3040 (set-marker (process-mark p) (point))) 3065 (kill-buffer (current-buffer)))
3041 ;; We must flush them here already; 3066 (set-buffer-modified-p bmp)))))))))))
3042 ;; otherwise `delete-file' will fail.
3043 (tramp-flush-connection-property v "process-name")
3044 (tramp-flush-connection-property v "process-buffer")
3045 ;; Kill stderr process and delete named pipe.
3046 (when (bufferp stderr)
3047 (add-function
3048 :after (process-sentinel p)
3049 (lambda (_proc _msg)
3050 (ignore-errors
3051 (while (accept-process-output
3052 (get-buffer-process stderr) 0 nil t))
3053 (delete-process (get-buffer-process stderr)))
3054 (ignore-errors
3055 (delete-file remote-tmpstderr)))))
3056 ;; Return process.
3057 p)))
3058
3059 ;; Save exit.
3060 (if (string-prefix-p tramp-temp-buffer-name (buffer-name))
3061 (ignore-errors
3062 (set-process-buffer p nil)
3063 (kill-buffer (current-buffer)))
3064 (set-buffer-modified-p bmp))))))))))))
3065 3067
3066(defun tramp-sh-get-signal-strings (vec) 3068(defun tramp-sh-get-signal-strings (vec)
3067 "Strings to return by `process-file' in case of signals." 3069 "Strings to return by `process-file' in case of signals."
@@ -3242,7 +3244,7 @@ implementation will be used."
3242 ;; because the remote process could have changed them. 3244 ;; because the remote process could have changed them.
3243 (when tmpinput (delete-file tmpinput)) 3245 (when tmpinput (delete-file tmpinput))
3244 (when process-file-side-effects 3246 (when process-file-side-effects
3245 (tramp-flush-directory-properties v "")) 3247 (tramp-flush-directory-properties v "/"))
3246 3248
3247 ;; Return exit status. 3249 ;; Return exit status.
3248 (if (equal ret -1) 3250 (if (equal ret -1)
@@ -3334,194 +3336,201 @@ implementation will be used."
3334 (start end filename &optional append visit lockname mustbenew) 3336 (start end filename &optional append visit lockname mustbenew)
3335 "Like `write-region' for Tramp files." 3337 "Like `write-region' for Tramp files."
3336 (tramp-skeleton-write-region start end filename append visit lockname mustbenew 3338 (tramp-skeleton-write-region start end filename append visit lockname mustbenew
3337 (if (and (tramp-local-host-p v) 3339 ;; If `start' is the empty string, it is likely that a temporary
3338 ;; `file-writable-p' calls `file-expand-file-name'. We 3340 ;; file is created. Do it directly.
3339 ;; cannot use `tramp-run-real-handler' therefore. 3341 (if (and (stringp start) (string-empty-p start))
3340 (file-writable-p (file-name-directory localname)) 3342 (tramp-send-command
3341 (or (file-directory-p localname) 3343 v (format "echo -n \"\">%s" (tramp-shell-quote-argument localname)))
3342 (file-writable-p localname))) 3344
3343 ;; Short track: if we are on the local host, we can run directly. 3345 ;; Short track: if we are on the local host, we can run directly.
3344 (let ((create-lockfiles (not file-locked))) 3346 (if (and (tramp-local-host-p v)
3345 (write-region start end localname append 'no-message lockname)) 3347 ;; `file-writable-p' calls `file-expand-file-name'. We
3346 3348 ;; cannot use `tramp-run-real-handler' therefore.
3347 (let* ((modes (tramp-default-file-modes 3349 (file-writable-p (file-name-directory localname))
3348 filename (and (eq mustbenew 'excl) 'nofollow))) 3350 (or (file-directory-p localname)
3349 ;; We use this to save the value of 3351 (file-writable-p localname)))
3350 ;; `last-coding-system-used' after writing the tmp file. 3352 (let ((create-lockfiles (not file-locked)))
3351 ;; At the end of the function, we set 3353 (write-region start end localname append 'no-message lockname))
3352 ;; `last-coding-system-used' to this saved value. This 3354
3353 ;; way, any intermediary coding systems used while 3355 (let* ((modes (tramp-default-file-modes
3354 ;; talking to the remote shell or suchlike won't hose 3356 filename (and (eq mustbenew 'excl) 'nofollow)))
3355 ;; this variable. This approach was snarfed from 3357 ;; We use this to save the value of
3356 ;; ange-ftp.el. 3358 ;; `last-coding-system-used' after writing the tmp
3357 coding-system-used 3359 ;; file. At the end of the function, we set
3358 ;; Write region into a tmp file. This isn't really 3360 ;; `last-coding-system-used' to this saved value. This
3359 ;; needed if we use an encoding function, but currently 3361 ;; way, any intermediary coding systems used while
3360 ;; we use it always because this makes the logic simpler. 3362 ;; talking to the remote shell or suchlike won't hose
3361 ;; We must also set `temporary-file-directory', because 3363 ;; this variable. This approach was snarfed from
3362 ;; it could point to a remote directory. 3364 ;; ange-ftp.el.
3363 (temporary-file-directory 3365 coding-system-used
3364 tramp-compat-temporary-file-directory) 3366 ;; Write region into a tmp file. This isn't really
3365 (tmpfile (or tramp-temp-buffer-file-name 3367 ;; needed if we use an encoding function, but currently
3366 (tramp-compat-make-temp-file filename)))) 3368 ;; we use it always because this makes the logic
3367 3369 ;; simpler. We must also set
3368 ;; If `append' is non-nil, we copy the file locally, and let 3370 ;; `temporary-file-directory', because it could point
3369 ;; the native `write-region' implementation do the job. 3371 ;; to a remote directory.
3370 (when (and append (file-exists-p filename)) 3372 (temporary-file-directory
3371 (copy-file filename tmpfile 'ok)) 3373 tramp-compat-temporary-file-directory)
3372 3374 (tmpfile (or tramp-temp-buffer-file-name
3373 ;; We say `no-message' here because we don't want the visited 3375 (tramp-compat-make-temp-file filename))))
3374 ;; file modtime data to be clobbered from the temp file. We 3376
3375 ;; call `set-visited-file-modtime' ourselves later on. We 3377 ;; If `append' is non-nil, we copy the file locally, and let
3376 ;; must ensure that `file-coding-system-alist' matches 3378 ;; the native `write-region' implementation do the job.
3377 ;; `tmpfile'. 3379 (when (and append (file-exists-p filename))
3378 (let ((file-coding-system-alist 3380 (copy-file filename tmpfile 'ok))
3379 (tramp-find-file-name-coding-system-alist filename tmpfile)) 3381
3380 create-lockfiles) 3382 ;; We say `no-message' here because we don't want the
3381 (condition-case err 3383 ;; visited file modtime data to be clobbered from the temp
3382 (write-region start end tmpfile append 'no-message) 3384 ;; file. We call `set-visited-file-modtime' ourselves later
3383 ((error quit) 3385 ;; on. We must ensure that `file-coding-system-alist'
3384 (setq tramp-temp-buffer-file-name nil) 3386 ;; matches `tmpfile'.
3385 (delete-file tmpfile) 3387 (let ((file-coding-system-alist
3386 (signal (car err) (cdr err)))) 3388 (tramp-find-file-name-coding-system-alist filename tmpfile))
3387 3389 create-lockfiles)
3388 ;; Now, `last-coding-system-used' has the right value. 3390 (condition-case err
3389 ;; Remember it. 3391 (write-region start end tmpfile append 'no-message)
3390 (setq coding-system-used last-coding-system-used)) 3392 ((error quit)
3391 3393 (setq tramp-temp-buffer-file-name nil)
3392 ;; The permissions of the temporary file should be set. If 3394 (delete-file tmpfile)
3393 ;; FILENAME does not exist (eq modes nil) it has been renamed 3395 (signal (car err) (cdr err))))
3394 ;; to the backup file. This case `save-buffer' handles 3396
3395 ;; permissions. Ensure that it is still readable. 3397 ;; Now, `last-coding-system-used' has the right value.
3396 (when modes 3398 ;; Remember it.
3397 (set-file-modes tmpfile (logior (or modes 0) #o0400))) 3399 (setq coding-system-used last-coding-system-used))
3398 3400
3399 ;; This is a bit lengthy due to the different methods possible 3401 ;; The permissions of the temporary file should be set. If
3400 ;; for file transfer. First, we check whether the method uses 3402 ;; FILENAME does not exist (eq modes nil) it has been
3401 ;; an scp program. If so, we call it. Otherwise, both 3403 ;; renamed to the backup file. This case `save-buffer'
3402 ;; encoding and decoding command must be specified. However, 3404 ;; handles permissions. Ensure that it is still readable.
3403 ;; if the method _also_ specifies an encoding function, then 3405 (when modes
3404 ;; that is used for encoding the contents of the tmp file. 3406 (set-file-modes tmpfile (logior (or modes 0) #o0400)))
3405 (let* ((size (file-attribute-size (file-attributes tmpfile))) 3407
3406 (rem-dec (tramp-get-inline-coding v "remote-decoding" size)) 3408 ;; This is a bit lengthy due to the different methods
3407 (loc-enc (tramp-get-inline-coding v "local-encoding" size))) 3409 ;; possible for file transfer. First, we check whether the
3408 (cond 3410 ;; method uses an scp program. If so, we call it.
3409 ;; `copy-file' handles direct copy and out-of-band methods. 3411 ;; Otherwise, both encoding and decoding command must be
3410 ((or (tramp-local-host-p v) 3412 ;; specified. However, if the method _also_ specifies an
3411 (tramp-method-out-of-band-p v size)) 3413 ;; encoding function, then that is used for encoding the
3412 (if (and (not (stringp start)) 3414 ;; contents of the tmp file.
3413 (= (or end (point-max)) (point-max)) 3415 (let* ((size (file-attribute-size (file-attributes tmpfile)))
3414 (= (or start (point-min)) (point-min)) 3416 (rem-dec (tramp-get-inline-coding v "remote-decoding" size))
3415 (tramp-get-method-parameter 3417 (loc-enc (tramp-get-inline-coding v "local-encoding" size)))
3416 v 'tramp-copy-keep-tmpfile)) 3418 (cond
3417 (progn 3419 ;; `copy-file' handles direct copy and out-of-band methods.
3418 (setq tramp-temp-buffer-file-name tmpfile) 3420 ((or (tramp-local-host-p v)
3419 (condition-case err 3421 (tramp-method-out-of-band-p v size))
3420 ;; We keep the local file for performance 3422 (if (and (not (stringp start))
3421 ;; reasons, useful for "rsync". 3423 (= (or end (point-max)) (point-max))
3422 (copy-file tmpfile filename t) 3424 (= (or start (point-min)) (point-min))
3423 ((error quit) 3425 (tramp-get-method-parameter
3424 (setq tramp-temp-buffer-file-name nil) 3426 v 'tramp-copy-keep-tmpfile))
3425 (delete-file tmpfile) 3427 (progn
3426 (signal (car err) (cdr err))))) 3428 (setq tramp-temp-buffer-file-name tmpfile)
3427 (setq tramp-temp-buffer-file-name nil) 3429 (condition-case err
3428 ;; Don't rename, in order to keep context in SELinux. 3430 ;; We keep the local file for performance
3431 ;; reasons, useful for "rsync".
3432 (copy-file tmpfile filename t)
3433 ((error quit)
3434 (setq tramp-temp-buffer-file-name nil)
3435 (delete-file tmpfile)
3436 (signal (car err) (cdr err)))))
3437 (setq tramp-temp-buffer-file-name nil)
3438 ;; Don't rename, in order to keep context in SELinux.
3439 (unwind-protect
3440 (copy-file tmpfile filename t)
3441 (delete-file tmpfile))))
3442
3443 ;; Use inline file transfer.
3444 (rem-dec
3445 ;; Encode tmpfile.
3429 (unwind-protect 3446 (unwind-protect
3430 (copy-file tmpfile filename t) 3447 (with-temp-buffer
3431 (delete-file tmpfile)))) 3448 (set-buffer-multibyte nil)
3432 3449 ;; Use encoding function or command.
3433 ;; Use inline file transfer. 3450 (with-tramp-progress-reporter
3434 (rem-dec 3451 v 3 (format-message
3435 ;; Encode tmpfile. 3452 "Encoding local file `%s' using `%s'"
3436 (unwind-protect 3453 tmpfile loc-enc)
3437 (with-temp-buffer 3454 (if (functionp loc-enc)
3438 (set-buffer-multibyte nil) 3455 ;; The following `let' is a workaround for
3439 ;; Use encoding function or command. 3456 ;; the base64.el that comes with pgnus-0.84.
3440 (with-tramp-progress-reporter 3457 ;; If both of the following conditions are
3441 v 3 (format-message 3458 ;; satisfied, it tries to write to a local
3442 "Encoding local file `%s' using `%s'" 3459 ;; file in default-directory, but at this
3443 tmpfile loc-enc) 3460 ;; point, default-directory is remote.
3444 (if (functionp loc-enc) 3461 ;; (`call-process-region' can't write to
3445 ;; The following `let' is a workaround for the 3462 ;; remote files, it seems.) The file in
3446 ;; base64.el that comes with pgnus-0.84. If 3463 ;; question is a tmp file anyway.
3447 ;; both of the following conditions are 3464 (let ((coding-system-for-read 'binary)
3448 ;; satisfied, it tries to write to a local 3465 (default-directory
3449 ;; file in default-directory, but at this 3466 tramp-compat-temporary-file-directory))
3450 ;; point, default-directory is remote. 3467 (insert-file-contents-literally tmpfile)
3451 ;; (`call-process-region' can't write to 3468 (funcall loc-enc (point-min) (point-max)))
3452 ;; remote files, it seems.) The file in 3469
3453 ;; question is a tmp file anyway. 3470 (unless (zerop (tramp-call-local-coding-command
3454 (let ((coding-system-for-read 'binary) 3471 loc-enc tmpfile t))
3455 (default-directory 3472 (tramp-error
3456 tramp-compat-temporary-file-directory)) 3473 v 'file-error
3457 (insert-file-contents-literally tmpfile) 3474 (concat "Cannot write to `%s', "
3458 (funcall loc-enc (point-min) (point-max))) 3475 "local encoding command `%s' failed")
3459 3476 filename loc-enc))))
3460 (unless (zerop (tramp-call-local-coding-command 3477
3461 loc-enc tmpfile t)) 3478 ;; Send buffer into remote decoding command which
3462 (tramp-error 3479 ;; writes to remote file. Because this happens on
3463 v 'file-error 3480 ;; the remote host, we cannot use the function.
3464 (concat "Cannot write to `%s', " 3481 (with-tramp-progress-reporter
3465 "local encoding command `%s' failed") 3482 v 3 (format-message
3466 filename loc-enc)))) 3483 "Decoding remote file `%s' using `%s'"
3467 3484 filename rem-dec)
3468 ;; Send buffer into remote decoding command which 3485 (goto-char (point-max))
3469 ;; writes to remote file. Because this happens on 3486 (unless (bolp) (newline))
3470 ;; the remote host, we cannot use the function. 3487 (tramp-barf-unless-okay
3471 (with-tramp-progress-reporter 3488 v (format
3472 v 3 (format-message 3489 (concat rem-dec " <<'%s'\n%s%s")
3473 "Decoding remote file `%s' using `%s'" 3490 (tramp-shell-quote-argument localname)
3474 filename rem-dec) 3491 tramp-end-of-heredoc
3475 (goto-char (point-max)) 3492 (buffer-string)
3476 (unless (bolp) (newline)) 3493 tramp-end-of-heredoc)
3477 (tramp-barf-unless-okay 3494 "Couldn't write region to `%s', decode using `%s' failed"
3478 v 3495 filename rem-dec)
3479 (format 3496 ;; When `file-precious-flag' is set, the region
3480 (concat rem-dec " <<'%s'\n%s%s") 3497 ;; is written to a temporary file. Check that
3481 (tramp-shell-quote-argument localname) 3498 ;; the checksum is equal to that from the local
3482 tramp-end-of-heredoc 3499 ;; tmpfile.
3483 (buffer-string) 3500 (when file-precious-flag
3484 tramp-end-of-heredoc) 3501 (erase-buffer)
3485 "Couldn't write region to `%s', decode using `%s' failed" 3502 (and
3486 filename rem-dec) 3503 ;; cksum runs locally, if possible.
3487 ;; When `file-precious-flag' is set, the region is 3504 (zerop (tramp-call-process v "cksum" tmpfile t))
3488 ;; written to a temporary file. Check that the 3505 ;; cksum runs remotely.
3489 ;; checksum is equal to that from the local tmpfile. 3506 (tramp-send-command-and-check
3490 (when file-precious-flag 3507 v (format
3491 (erase-buffer) 3508 "cksum <%s" (tramp-shell-quote-argument localname)))
3492 (and 3509 ;; ... they are different.
3493 ;; cksum runs locally, if possible. 3510 (not
3494 (zerop (tramp-call-process v "cksum" tmpfile t)) 3511 (string-equal
3495 ;; cksum runs remotely. 3512 (buffer-string)
3496 (tramp-send-command-and-check 3513 (tramp-get-buffer-string (tramp-get-buffer v))))
3497 v 3514 (tramp-error
3498 (format 3515 v 'file-error
3499 "cksum <%s" 3516 (concat "Couldn't write region to `%s',"
3500 (tramp-shell-quote-argument localname))) 3517 " decode using `%s' failed")
3501 ;; ... they are different. 3518 filename rem-dec)))))
3502 (not 3519
3503 (string-equal 3520 ;; Save exit.
3504 (buffer-string) 3521 (delete-file tmpfile)))
3505 (tramp-get-buffer-string (tramp-get-buffer v))))
3506 (tramp-error
3507 v 'file-error
3508 "Couldn't write region to `%s', decode using `%s' failed"
3509 filename rem-dec)))))
3510
3511 ;; Save exit.
3512 (delete-file tmpfile)))
3513
3514 ;; That's not expected.
3515 (t
3516 (tramp-error
3517 v 'file-error
3518 (concat "Method `%s' should specify both encoding and "
3519 "decoding command or an scp program")
3520 method))))
3521 3522
3522 ;; Make `last-coding-system-used' have the right value. 3523 ;; That's not expected.
3523 (when coding-system-used 3524 (t
3524 (setq last-coding-system-used coding-system-used)))))) 3525 (tramp-error
3526 v 'file-error
3527 (concat "Method `%s' should specify both encoding and "
3528 "decoding command or an scp program")
3529 method))))
3530
3531 ;; Make `last-coding-system-used' have the right value.
3532 (when coding-system-used
3533 (setq last-coding-system-used coding-system-used)))))))
3525 3534
3526(defvar tramp-vc-registered-file-names nil 3535(defvar tramp-vc-registered-file-names nil
3527 "List used to collect file names, which are checked during `vc-registered'.") 3536 "List used to collect file names, which are checked during `vc-registered'.")
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 29abdb575d3..a81a8f13636 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -523,49 +523,49 @@ arguments to pass to the OPERATION."
523 "tar qx -"))))) 523 "tar qx -")))))
524 524
525 (unwind-protect 525 (unwind-protect
526 (with-tramp-saved-connection-property v "process-name" 526 (with-tramp-saved-connection-properties
527 (with-tramp-saved-connection-property v "process-buffer" 527 v '("process-name" "process-buffer")
528 (with-temp-buffer 528 (with-temp-buffer
529 ;; Set the transfer process properties. 529 ;; Set the transfer process properties.
530 (tramp-set-connection-property 530 (tramp-set-connection-property
531 v "process-name" (buffer-name (current-buffer))) 531 v "process-name" (buffer-name (current-buffer)))
532 (tramp-set-connection-property 532 (tramp-set-connection-property
533 v "process-buffer" (current-buffer)) 533 v "process-buffer" (current-buffer))
534 534
535 (when t1 535 (when t1
536 ;; The smbclient tar command creates 536 ;; The smbclient tar command creates
537 ;; always complete paths. We must 537 ;; always complete paths. We must emulate
538 ;; emulate the directory structure, and 538 ;; the directory structure, and symlink to
539 ;; symlink to the real target. 539 ;; the real target.
540 (make-directory 540 (make-directory
541 (expand-file-name 541 (expand-file-name
542 ".." (concat tmpdir localname)) 542 ".." (concat tmpdir localname))
543 'parents) 543 'parents)
544 (make-symbolic-link 544 (make-symbolic-link
545 newname 545 newname
546 (directory-file-name (concat tmpdir localname)))) 546 (directory-file-name (concat tmpdir localname))))
547 547
548 ;; Use an asynchronous processes. By 548 ;; Use an asynchronous processes. By this,
549 ;; this, password can be handled. 549 ;; password can be handled.
550 (let* ((default-directory tmpdir) 550 (let* ((default-directory tmpdir)
551 (p (apply 551 (p (apply
552 #'start-process 552 #'start-process
553 (tramp-get-connection-name v) 553 (tramp-get-connection-name v)
554 (tramp-get-connection-buffer v) 554 (tramp-get-connection-buffer v)
555 tramp-smb-program args))) 555 tramp-smb-program args)))
556 556
557 (tramp-message 557 (tramp-message
558 v 6 "%s" (string-join (process-command p) " ")) 558 v 6 "%s" (string-join (process-command p) " "))
559 (process-put p 'vector v) 559 (process-put p 'vector v)
560 (process-put 560 (process-put
561 p 'adjust-window-size-function #'ignore) 561 p 'adjust-window-size-function #'ignore)
562 (set-process-query-on-exit-flag p nil) 562 (set-process-query-on-exit-flag p nil)
563 (tramp-process-actions 563 (tramp-process-actions
564 p v nil tramp-smb-actions-with-tar) 564 p v nil tramp-smb-actions-with-tar)
565 565
566 (while (process-live-p p) 566 (while (process-live-p p)
567 (sleep-for 0.1)) 567 (sleep-for 0.1))
568 (tramp-message v 6 "\n%s" (buffer-string)))))) 568 (tramp-message v 6 "\n%s" (buffer-string)))))
569 569
570 ;; Save exit. 570 ;; Save exit.
571 (when t1 (delete-directory tmpdir 'recursive)))) 571 (when t1 (delete-directory tmpdir 'recursive))))
@@ -751,6 +751,10 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
751 localname 751 localname
752 (tramp-run-real-handler #'expand-file-name (list localname))))))) 752 (tramp-run-real-handler #'expand-file-name (list localname)))))))
753 753
754(defun tramp-smb-remote-acl-p (_vec)
755 "Check, whether ACL is enabled on the remote host."
756 (and (stringp tramp-smb-acl-program) (executable-find tramp-smb-acl-program)))
757
754(defun tramp-smb-action-get-acl (proc vec) 758(defun tramp-smb-action-get-acl (proc vec)
755 "Read ACL data from connection buffer." 759 "Read ACL data from connection buffer."
756 (unless (process-live-p proc) 760 (unless (process-live-p proc)
@@ -774,7 +778,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
774 (ignore-errors 778 (ignore-errors
775 (with-parsed-tramp-file-name filename nil 779 (with-parsed-tramp-file-name filename nil
776 (with-tramp-file-property v localname "file-acl" 780 (with-tramp-file-property v localname "file-acl"
777 (when (executable-find tramp-smb-acl-program) 781 (when (tramp-smb-remote-acl-p v)
778 (let* ((share (tramp-smb-get-share v)) 782 (let* ((share (tramp-smb-get-share v))
779 (localname (tramp-compat-string-replace 783 (localname (tramp-compat-string-replace
780 "\\" "/" (tramp-smb-get-localname v))) 784 "\\" "/" (tramp-smb-get-localname v)))
@@ -799,31 +803,31 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
799 (concat "2>" (tramp-get-remote-null-device v))))) 803 (concat "2>" (tramp-get-remote-null-device v)))))
800 804
801 (unwind-protect 805 (unwind-protect
802 (with-tramp-saved-connection-property v "process-name" 806 (with-tramp-saved-connection-properties
803 (with-tramp-saved-connection-property v "process-buffer" 807 v '("process-name" "process-buffer")
804 (with-temp-buffer 808 (with-temp-buffer
805 ;; Set the transfer process properties. 809 ;; Set the transfer process properties.
806 (tramp-set-connection-property 810 (tramp-set-connection-property
807 v "process-name" (buffer-name (current-buffer))) 811 v "process-name" (buffer-name (current-buffer)))
808 (tramp-set-connection-property 812 (tramp-set-connection-property
809 v "process-buffer" (current-buffer)) 813 v "process-buffer" (current-buffer))
810 814
811 ;; Use an asynchronous process. By this, 815 ;; Use an asynchronous process. By this, password
812 ;; password can be handled. 816 ;; can be handled.
813 (let ((p (apply 817 (let ((p (apply
814 #'start-process 818 #'start-process
815 (tramp-get-connection-name v) 819 (tramp-get-connection-name v)
816 (tramp-get-connection-buffer v) 820 (tramp-get-connection-buffer v)
817 tramp-smb-acl-program args))) 821 tramp-smb-acl-program args)))
818 822
819 (tramp-message 823 (tramp-message
820 v 6 "%s" (string-join (process-command p) " ")) 824 v 6 "%s" (string-join (process-command p) " "))
821 (process-put p 'vector v) 825 (process-put p 'vector v)
822 (process-put p 'adjust-window-size-function #'ignore) 826 (process-put p 'adjust-window-size-function #'ignore)
823 (set-process-query-on-exit-flag p nil) 827 (set-process-query-on-exit-flag p nil)
824 (tramp-process-actions p v nil tramp-smb-actions-get-acl) 828 (tramp-process-actions p v nil tramp-smb-actions-get-acl)
825 (when (> (point-max) (point-min)) 829 (when (> (point-max) (point-min))
826 (substring-no-properties (buffer-string)))))))))))))) 830 (substring-no-properties (buffer-string)))))))))))))
827 831
828(defun tramp-smb-handle-file-attributes (filename &optional id-format) 832(defun tramp-smb-handle-file-attributes (filename &optional id-format)
829 "Like `file-attributes' for Tramp files." 833 "Like `file-attributes' for Tramp files."
@@ -1311,32 +1315,32 @@ component is used as the target of the symlink."
1311 1315
1312 ;; Call it. 1316 ;; Call it.
1313 (condition-case nil 1317 (condition-case nil
1314 (with-tramp-saved-connection-property v "process-name" 1318 (with-tramp-saved-connection-properties
1315 (with-tramp-saved-connection-property v "process-buffer" 1319 v '("process-name" "process-buffer")
1316 ;; Set the new process properties. 1320 ;; Set the new process properties.
1317 (tramp-set-connection-property v "process-name" name1) 1321 (tramp-set-connection-property v "process-name" name1)
1318 (tramp-set-connection-property 1322 (tramp-set-connection-property
1319 v "process-buffer" 1323 v "process-buffer"
1320 (or outbuf (generate-new-buffer tramp-temp-buffer-name))) 1324 (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
1321 (with-current-buffer (tramp-get-connection-buffer v) 1325 (with-current-buffer (tramp-get-connection-buffer v)
1322 ;; Preserve buffer contents. 1326 ;; Preserve buffer contents.
1323 (narrow-to-region (point-max) (point-max)) 1327 (narrow-to-region (point-max) (point-max))
1324 (tramp-smb-call-winexe v) 1328 (tramp-smb-call-winexe v)
1325 (when (tramp-smb-get-share v) 1329 (when (tramp-smb-get-share v)
1326 (tramp-smb-send-command 1330 (tramp-smb-send-command
1327 v (format "cd //%s%s" host 1331 v (format "cd //%s%s" host
1328 (tramp-smb-shell-quote-argument 1332 (tramp-smb-shell-quote-argument
1329 (file-name-directory localname))))) 1333 (file-name-directory localname)))))
1330 (tramp-smb-send-command v command) 1334 (tramp-smb-send-command v command)
1331 ;; Preserve command output. 1335 ;; Preserve command output.
1332 (narrow-to-region (point-max) (point-max)) 1336 (narrow-to-region (point-max) (point-max))
1333 (let ((p (tramp-get-connection-process v))) 1337 (let ((p (tramp-get-connection-process v)))
1334 (tramp-smb-send-command v "exit $lasterrorcode") 1338 (tramp-smb-send-command v "exit $lasterrorcode")
1335 (while (process-live-p p) 1339 (while (process-live-p p)
1336 (sleep-for 0.1) 1340 (sleep-for 0.1)
1337 (setq ret (process-exit-status p)))) 1341 (setq ret (process-exit-status p))))
1338 (delete-region (point-min) (point-max)) 1342 (delete-region (point-min) (point-max))
1339 (widen)))) 1343 (widen)))
1340 1344
1341 ;; When the user did interrupt, we should do it also. We use 1345 ;; When the user did interrupt, we should do it also. We use
1342 ;; return code -1 as marker. 1346 ;; return code -1 as marker.
@@ -1356,7 +1360,7 @@ component is used as the target of the symlink."
1356 (unless outbuf 1360 (unless outbuf
1357 (kill-buffer (tramp-get-connection-property v "process-buffer"))) 1361 (kill-buffer (tramp-get-connection-property v "process-buffer")))
1358 (when process-file-side-effects 1362 (when process-file-side-effects
1359 (tramp-flush-directory-properties v "")) 1363 (tramp-flush-directory-properties v "/"))
1360 1364
1361 ;; Return exit status. 1365 ;; Return exit status.
1362 (if (equal ret -1) 1366 (if (equal ret -1)
@@ -1427,7 +1431,7 @@ component is used as the target of the symlink."
1427 (with-parsed-tramp-file-name filename nil 1431 (with-parsed-tramp-file-name filename nil
1428 (tramp-flush-file-property v localname "file-acl") 1432 (tramp-flush-file-property v localname "file-acl")
1429 1433
1430 (when (and (stringp acl-string) (executable-find tramp-smb-acl-program)) 1434 (when (and (stringp acl-string) (tramp-smb-remote-acl-p v))
1431 (let* ((share (tramp-smb-get-share v)) 1435 (let* ((share (tramp-smb-get-share v))
1432 (localname (tramp-compat-string-replace 1436 (localname (tramp-compat-string-replace
1433 "\\" "/" (tramp-smb-get-localname v))) 1437 "\\" "/" (tramp-smb-get-localname v)))
@@ -1455,52 +1459,50 @@ component is used as the target of the symlink."
1455 "||" "echo" "tramp_exit_status" "1"))) 1459 "||" "echo" "tramp_exit_status" "1")))
1456 1460
1457 (unwind-protect 1461 (unwind-protect
1458 (with-tramp-saved-connection-property v "process-name" 1462 (with-tramp-saved-connection-properties
1459 (with-tramp-saved-connection-property v "process-buffer" 1463 v '("process-name" "process-buffer")
1460 (with-temp-buffer 1464 (with-temp-buffer
1461 ;; Set the transfer process properties. 1465 ;; Set the transfer process properties.
1462 (tramp-set-connection-property 1466 (tramp-set-connection-property
1463 v "process-name" (buffer-name (current-buffer))) 1467 v "process-name" (buffer-name (current-buffer)))
1464 (tramp-set-connection-property 1468 (tramp-set-connection-property
1465 v "process-buffer" (current-buffer)) 1469 v "process-buffer" (current-buffer))
1466 1470
1467 ;; Use an asynchronous process. By this, password 1471 ;; Use an asynchronous process. By this, password
1468 ;; can be handled. 1472 ;; can be handled.
1469 (let ((p (apply 1473 (let ((p (apply
1470 #'start-process 1474 #'start-process
1471 (tramp-get-connection-name v) 1475 (tramp-get-connection-name v)
1472 (tramp-get-connection-buffer v) 1476 (tramp-get-connection-buffer v)
1473 tramp-smb-acl-program args))) 1477 tramp-smb-acl-program args)))
1474 1478
1475 (tramp-message 1479 (tramp-message
1476 v 6 "%s" (string-join (process-command p) " ")) 1480 v 6 "%s" (string-join (process-command p) " "))
1477 (process-put p 'vector v) 1481 (process-put p 'vector v)
1478 (process-put p 'adjust-window-size-function #'ignore) 1482 (process-put p 'adjust-window-size-function #'ignore)
1479 (set-process-query-on-exit-flag p nil) 1483 (set-process-query-on-exit-flag p nil)
1480 (tramp-process-actions p v nil tramp-smb-actions-set-acl) 1484 (tramp-process-actions p v nil tramp-smb-actions-set-acl)
1481 ;; This is meant for traces, and returning from 1485 ;; This is meant for traces, and returning from
1482 ;; the function. No error is propagated 1486 ;; the function. No error is propagated outside,
1483 ;; outside, due to the `ignore-errors' closure. 1487 ;; due to the `ignore-errors' closure.
1484 (unless 1488 (unless
1485 (tramp-search-regexp "tramp_exit_status [[:digit:]]+") 1489 (tramp-search-regexp "tramp_exit_status [[:digit:]]+")
1486 (tramp-error 1490 (tramp-error
1487 v 'file-error 1491 v 'file-error
1488 "Couldn't find exit status of `%s'" 1492 "Couldn't find exit status of `%s'"
1489 tramp-smb-acl-program)) 1493 tramp-smb-acl-program))
1490 (skip-chars-forward "^ ") 1494 (skip-chars-forward "^ ")
1491 (when (zerop (read (current-buffer))) 1495 (when (zerop (read (current-buffer)))
1492 ;; Success. 1496 ;; Success.
1493 (tramp-set-file-property 1497 (tramp-set-file-property v localname "file-acl" acl-string)
1494 v localname "file-acl" acl-string) 1498 t))))))))))
1495 t)))))))))))
1496 1499
1497(defun tramp-smb-handle-set-file-modes (filename mode &optional flag) 1500(defun tramp-smb-handle-set-file-modes (filename mode &optional flag)
1498 "Like `set-file-modes' for Tramp files." 1501 "Like `set-file-modes' for Tramp files."
1499 (with-parsed-tramp-file-name filename nil 1502 ;; smbclient chmod does not support nofollow.
1500 ;; smbclient chmod does not support nofollow. 1503 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
1501 (unless (and (eq flag 'nofollow) (file-symlink-p filename)) 1504 (tramp-skeleton-set-file-modes-times-uid-gid filename
1502 (when (tramp-smb-get-cifs-capabilities v) 1505 (when (tramp-smb-get-cifs-capabilities v)
1503 (tramp-flush-file-properties v localname)
1504 (unless (tramp-smb-send-command 1506 (unless (tramp-smb-send-command
1505 v 1507 v
1506 (format "chmod %s %o" (tramp-smb-shell-quote-localname v) mode)) 1508 (format "chmod %s %o" (tramp-smb-shell-quote-localname v) mode))
@@ -1524,38 +1526,38 @@ component is used as the target of the symlink."
1524 (i 0) 1526 (i 0)
1525 p) 1527 p)
1526 (unwind-protect 1528 (unwind-protect
1527 (with-tramp-saved-connection-property v "process-name" 1529 (with-tramp-saved-connection-properties
1528 (with-tramp-saved-connection-property v "process-buffer" 1530 v '("process-name" "process-buffer")
1529 (save-excursion 1531 (save-excursion
1530 (save-restriction 1532 (save-restriction
1531 (while (get-process name1) 1533 (while (get-process name1)
1532 ;; NAME must be unique as process name. 1534 ;; NAME must be unique as process name.
1533 (setq i (1+ i) 1535 (setq i (1+ i)
1534 name1 (format "%s<%d>" name i))) 1536 name1 (format "%s<%d>" name i)))
1535 ;; Set the new process properties. 1537 ;; Set the new process properties.
1536 (tramp-set-connection-property v "process-name" name1) 1538 (tramp-set-connection-property v "process-name" name1)
1537 (tramp-set-connection-property v "process-buffer" buffer) 1539 (tramp-set-connection-property v "process-buffer" buffer)
1538 ;; Activate narrowing in order to save BUFFER contents. 1540 ;; Activate narrowing in order to save BUFFER contents.
1539 (with-current-buffer (tramp-get-connection-buffer v) 1541 (with-current-buffer (tramp-get-connection-buffer v)
1540 (let ((buffer-undo-list t)) 1542 (let ((buffer-undo-list t))
1541 (narrow-to-region (point-max) (point-max)) 1543 (narrow-to-region (point-max) (point-max))
1542 (tramp-smb-call-winexe v) 1544 (tramp-smb-call-winexe v)
1543 (when (tramp-smb-get-share v) 1545 (when (tramp-smb-get-share v)
1544 (tramp-smb-send-command 1546 (tramp-smb-send-command
1545 v (format 1547 v (format
1546 "cd //%s%s" 1548 "cd //%s%s"
1547 host 1549 host
1548 (tramp-smb-shell-quote-argument 1550 (tramp-smb-shell-quote-argument
1549 (file-name-directory localname))))) 1551 (file-name-directory localname)))))
1550 (tramp-message v 6 "(%s); exit" command) 1552 (tramp-message v 6 "(%s); exit" command)
1551 (tramp-send-string v command))) 1553 (tramp-send-string v command)))
1552 (setq p (tramp-get-connection-process v)) 1554 (setq p (tramp-get-connection-process v))
1553 (when program 1555 (when program
1554 (process-put p 'remote-command (cons program args)) 1556 (process-put p 'remote-command (cons program args))
1555 (tramp-set-connection-property 1557 (tramp-set-connection-property
1556 p "remote-command" (cons program args))) 1558 p "remote-command" (cons program args)))
1557 ;; Return value. 1559 ;; Return value.
1558 p)))) 1560 p)))
1559 1561
1560 ;; Save exit. 1562 ;; Save exit.
1561 ;; FIXME: Does `tramp-get-connection-buffer' return the proper value? 1563 ;; FIXME: Does `tramp-get-connection-buffer' return the proper value?
@@ -1933,7 +1935,7 @@ If ARGUMENT is non-nil, use it as argument for
1933 tramp-smb-version 1935 tramp-smb-version
1934 (tramp-get-connection-property 1936 (tramp-get-connection-property
1935 vec "smbclient-version" tramp-smb-version)) 1937 vec "smbclient-version" tramp-smb-version))
1936 (tramp-flush-directory-properties vec "") 1938 (tramp-flush-directory-properties vec "/")
1937 (tramp-flush-connection-properties vec)) 1939 (tramp-flush-connection-properties vec))
1938 1940
1939 (tramp-set-connection-property 1941 (tramp-set-connection-property
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index d7c918fbc83..a9225db434e 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -333,7 +333,7 @@ arguments to pass to the OPERATION."
333 ;; them. 333 ;; them.
334 (when tmpinput (delete-file tmpinput)) 334 (when tmpinput (delete-file tmpinput))
335 (when process-file-side-effects 335 (when process-file-side-effects
336 (tramp-flush-directory-properties v "")))))) 336 (tramp-flush-directory-properties v "/"))))))
337 337
338(defun tramp-sshfs-handle-rename-file 338(defun tramp-sshfs-handle-rename-file
339 (filename newname &optional ok-if-already-exists) 339 (filename newname &optional ok-if-already-exists)
@@ -355,18 +355,15 @@ arguments to pass to the OPERATION."
355 355
356(defun tramp-sshfs-handle-set-file-modes (filename mode &optional flag) 356(defun tramp-sshfs-handle-set-file-modes (filename mode &optional flag)
357 "Like `set-file-modes' for Tramp files." 357 "Like `set-file-modes' for Tramp files."
358 (with-parsed-tramp-file-name filename nil 358 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
359 (unless (and (eq flag 'nofollow) (file-symlink-p filename)) 359 (tramp-skeleton-set-file-modes-times-uid-gid filename
360 (tramp-flush-file-properties v localname)
361 (tramp-compat-set-file-modes 360 (tramp-compat-set-file-modes
362 (tramp-fuse-local-file-name filename) mode flag)))) 361 (tramp-fuse-local-file-name filename) mode flag))))
363 362
364(defun tramp-sshfs-handle-set-file-times (filename &optional timestamp flag) 363(defun tramp-sshfs-handle-set-file-times (filename &optional timestamp flag)
365 "Like `set-file-times' for Tramp files." 364 "Like `set-file-times' for Tramp files."
366 (or (file-exists-p filename) (write-region "" nil filename nil 0)) 365 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
367 (with-parsed-tramp-file-name filename nil 366 (tramp-skeleton-set-file-modes-times-uid-gid filename
368 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
369 (tramp-flush-file-properties v localname)
370 (tramp-compat-set-file-times 367 (tramp-compat-set-file-times
371 (tramp-fuse-local-file-name filename) timestamp flag)))) 368 (tramp-fuse-local-file-name filename) timestamp flag))))
372 369
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 5ec68e904e7..3564a1b7b44 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -484,10 +484,9 @@ the result will be a local, non-Tramp, file name."
484 484
485(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) 485(defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
486 "Like `set-file-modes' for Tramp files." 486 "Like `set-file-modes' for Tramp files."
487 (with-parsed-tramp-file-name filename nil 487 ;; It is unlikely that "chmod -h" works.
488 ;; It is unlikely that "chmod -h" works. 488 (unless (and (eq flag 'nofollow) (file-symlink-p filename))
489 (unless (and (eq flag 'nofollow) (file-symlink-p filename)) 489 (tramp-skeleton-set-file-modes-times-uid-gid filename
490 (tramp-flush-file-properties v localname)
491 (unless (tramp-sudoedit-send-command 490 (unless (tramp-sudoedit-send-command
492 v "chmod" (format "%o" mode) 491 v "chmod" (format "%o" mode)
493 (tramp-compat-file-name-unquote localname)) 492 (tramp-compat-file-name-unquote localname))
@@ -542,8 +541,7 @@ the result will be a local, non-Tramp, file name."
542 541
543(defun tramp-sudoedit-handle-set-file-times (filename &optional time flag) 542(defun tramp-sudoedit-handle-set-file-times (filename &optional time flag)
544 "Like `set-file-times' for Tramp files." 543 "Like `set-file-times' for Tramp files."
545 (with-parsed-tramp-file-name filename nil 544 (tramp-skeleton-set-file-modes-times-uid-gid filename
546 (tramp-flush-file-properties v localname)
547 (let ((time 545 (let ((time
548 (if (or (null time) 546 (if (or (null time)
549 (tramp-compat-time-equal-p time tramp-time-doesnt-exist) 547 (tramp-compat-time-equal-p time tramp-time-doesnt-exist)
@@ -730,13 +728,13 @@ ID-FORMAT valid values are `string' and `integer'."
730 728
731(defun tramp-sudoedit-handle-set-file-uid-gid (filename &optional uid gid) 729(defun tramp-sudoedit-handle-set-file-uid-gid (filename &optional uid gid)
732 "Like `tramp-set-file-uid-gid' for Tramp files." 730 "Like `tramp-set-file-uid-gid' for Tramp files."
733 (with-parsed-tramp-file-name filename nil 731 (tramp-skeleton-set-file-modes-times-uid-gid filename
734 (tramp-sudoedit-send-command 732 (tramp-sudoedit-send-command
735 v "chown" 733 v "chown"
736 (format "%d:%d" 734 (format "%d:%d"
737 (or uid (tramp-get-remote-uid v 'integer)) 735 (or uid (tramp-get-remote-uid v 'integer))
738 (or gid (tramp-get-remote-gid v 'integer))) 736 (or gid (tramp-get-remote-gid v 'integer)))
739 (tramp-unquote-file-local-name filename)))) 737 (tramp-unquote-file-local-name filename))))
740 738
741 739
742;; Internal functions. 740;; Internal functions.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 0afa6fc4312..aac63882ced 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -62,7 +62,6 @@
62(require 'cl-lib) 62(require 'cl-lib)
63(declare-function file-notify-rm-watch "filenotify") 63(declare-function file-notify-rm-watch "filenotify")
64(declare-function netrc-parse "netrc") 64(declare-function netrc-parse "netrc")
65(declare-function tramp-archive-file-name-handler "tramp-archive")
66(defvar auto-save-file-name-transforms) 65(defvar auto-save-file-name-transforms)
67 66
68;; Reload `tramp-compat' when we reload `tramp-autoloads' of the GNU ELPA package. 67;; Reload `tramp-compat' when we reload `tramp-autoloads' of the GNU ELPA package.
@@ -97,6 +96,7 @@
97If it is set to nil, all remote file names are used literally." 96If it is set to nil, all remote file names are used literally."
98 :type 'boolean) 97 :type 'boolean)
99 98
99;;;###tramp-autoload
100(defcustom tramp-verbose 3 100(defcustom tramp-verbose 3
101 "Verbosity level for Tramp messages. 101 "Verbosity level for Tramp messages.
102Any level x includes messages for all levels 1 .. x-1. The levels are 102Any level x includes messages for all levels 1 .. x-1. The levels are
@@ -1441,8 +1441,9 @@ calling HANDLER.")
1441;; work otherwise when unloading / reloading Tramp. (Bug#50869) 1441;; work otherwise when unloading / reloading Tramp. (Bug#50869)
1442;;;###tramp-autoload(require 'cl-lib) 1442;;;###tramp-autoload(require 'cl-lib)
1443;;;###tramp-autoload 1443;;;###tramp-autoload
1444(cl-defstruct (tramp-file-name (:type list) :named) 1444(progn
1445 method user domain host port localname hop) 1445 (cl-defstruct (tramp-file-name (:type list) :named)
1446 method user domain host port localname hop))
1446 1447
1447(put #'tramp-file-name-method 'tramp-suppress-trace t) 1448(put #'tramp-file-name-method 'tramp-suppress-trace t)
1448(put #'tramp-file-name-user 'tramp-suppress-trace t) 1449(put #'tramp-file-name-user 'tramp-suppress-trace t)
@@ -1485,13 +1486,22 @@ If nil, return `tramp-default-port'."
1485 1486
1486(put #'tramp-file-name-port-or-default 'tramp-suppress-trace t) 1487(put #'tramp-file-name-port-or-default 'tramp-suppress-trace t)
1487 1488
1488(defun tramp-file-name-unify (vec) 1489;;;###tramp-autoload
1490(defun tramp-file-name-unify (vec &optional file)
1489 "Unify VEC by removing localname and hop from `tramp-file-name' structure. 1491 "Unify VEC by removing localname and hop from `tramp-file-name' structure.
1492If FILE is a string, set it as localname.
1490Objects returned by this function compare `equal' if they refer to the 1493Objects returned by this function compare `equal' if they refer to the
1491same connection. Make a copy in order to avoid side effects." 1494same connection. Make a copy in order to avoid side effects."
1492 (when (tramp-file-name-p vec) 1495 (when (tramp-file-name-p vec)
1493 (setq vec (copy-tramp-file-name vec)) 1496 (setq vec (copy-tramp-file-name vec))
1494 (setf (tramp-file-name-localname vec) nil 1497 (setf (tramp-file-name-localname vec)
1498 (and (stringp file)
1499 ;; FIXME: This is a sanity check. When this error
1500 ;; doesn't happen for a while, it can be removed.
1501 (or (file-name-absolute-p file)
1502 (tramp-error
1503 vec 'file-error "File `%s' must be absolute" file))
1504 (directory-file-name (tramp-compat-file-name-unquote file)))
1495 (tramp-file-name-hop vec) nil)) 1505 (tramp-file-name-hop vec) nil))
1496 vec) 1506 vec)
1497 1507
@@ -1525,6 +1535,7 @@ entry does not exist, return nil."
1525 "Return unquoted localname component of VEC." 1535 "Return unquoted localname component of VEC."
1526 (tramp-compat-file-name-unquote (tramp-file-name-localname vec))) 1536 (tramp-compat-file-name-unquote (tramp-file-name-localname vec)))
1527 1537
1538;;;###tramp-autoload
1528(defun tramp-tramp-file-p (name) 1539(defun tramp-tramp-file-p (name)
1529 "Return t if NAME is a string with Tramp file name syntax." 1540 "Return t if NAME is a string with Tramp file name syntax."
1530 (and tramp-mode (stringp name) 1541 (and tramp-mode (stringp name)
@@ -1546,6 +1557,7 @@ entry does not exist, return nil."
1546;; However, it is more performant than `file-local-name', and might be 1557;; However, it is more performant than `file-local-name', and might be
1547;; useful where performance matters, like in operations over a bulk 1558;; useful where performance matters, like in operations over a bulk
1548;; list of file names. 1559;; list of file names.
1560;;;###tramp-autoload
1549(defun tramp-file-local-name (name) 1561(defun tramp-file-local-name (name)
1550 "Return the local name component of NAME. 1562 "Return the local name component of NAME.
1551This function removes from NAME the specification of the remote 1563This function removes from NAME the specification of the remote
@@ -1637,6 +1649,7 @@ This is HOST, if non-nil. Otherwise, do a lookup in
1637 1649
1638(put #'tramp-find-host 'tramp-suppress-trace t) 1650(put #'tramp-find-host 'tramp-suppress-trace t)
1639 1651
1652;;;###tramp-autoload
1640(defun tramp-dissect-file-name (name &optional nodefault) 1653(defun tramp-dissect-file-name (name &optional nodefault)
1641 "Return a `tramp-file-name' structure of NAME, a remote file name. 1654 "Return a `tramp-file-name' structure of NAME, a remote file name.
1642The structure consists of method, user, domain, host, port, 1655The structure consists of method, user, domain, host, port,
@@ -1747,6 +1760,7 @@ See `tramp-dissect-file-name' for details."
1747 1760
1748(put #'tramp-buffer-name 'tramp-suppress-trace t) 1761(put #'tramp-buffer-name 'tramp-suppress-trace t)
1749 1762
1763;;;###tramp-autoload
1750(defun tramp-make-tramp-file-name (&rest args) 1764(defun tramp-make-tramp-file-name (&rest args)
1751 "Construct a Tramp file name from ARGS. 1765 "Construct a Tramp file name from ARGS.
1752 1766
@@ -1856,6 +1870,7 @@ Unless DONT-CREATE, the buffer is created when it doesn't exist yet."
1856 (tramp-make-tramp-file-name vec 'noloc)) 1870 (tramp-make-tramp-file-name vec 'noloc))
1857 (current-buffer))))) 1871 (current-buffer)))))
1858 1872
1873;;;###tramp-autoload
1859(defun tramp-get-connection-buffer (vec &optional dont-create) 1874(defun tramp-get-connection-buffer (vec &optional dont-create)
1860 "Get the connection buffer to be used for VEC. 1875 "Get the connection buffer to be used for VEC.
1861Unless DONT-CREATE, the buffer is created when it doesn't exist yet. 1876Unless DONT-CREATE, the buffer is created when it doesn't exist yet.
@@ -1912,8 +1927,7 @@ version, the function does nothing."
1912 "Return `default-directory' of BUFFER." 1927 "Return `default-directory' of BUFFER."
1913 (buffer-local-value 'default-directory buffer)) 1928 (buffer-local-value 'default-directory buffer))
1914 1929
1915(put #'tramp-get-default-directory 'tramp-suppress-trace t) 1930;;;###tramp-autoload
1916
1917(defsubst tramp-get-buffer-string (&optional buffer) 1931(defsubst tramp-get-buffer-string (&optional buffer)
1918 "Return contents of BUFFER. 1932 "Return contents of BUFFER.
1919If BUFFER is not a buffer or a buffer name, return the contents 1933If BUFFER is not a buffer or a buffer name, return the contents
@@ -1921,8 +1935,6 @@ of `current-buffer'."
1921 (with-current-buffer (or buffer (current-buffer)) 1935 (with-current-buffer (or buffer (current-buffer))
1922 (substring-no-properties (buffer-string)))) 1936 (substring-no-properties (buffer-string))))
1923 1937
1924(put #'tramp-get-buffer-string 'tramp-suppress-trace t)
1925
1926(defun tramp-debug-buffer-name (vec) 1938(defun tramp-debug-buffer-name (vec)
1927 "A name for the debug buffer for VEC." 1939 "A name for the debug buffer for VEC."
1928 (let ((method (tramp-file-name-method vec)) 1940 (let ((method (tramp-file-name-method vec))
@@ -2034,6 +2046,7 @@ They are completed by \"M-x TAB\" only in Tramp debug buffers."
2034(defvar tramp-trace-functions nil 2046(defvar tramp-trace-functions nil
2035 "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.") 2047 "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.")
2036 2048
2049;;;###tramp-autoload
2037(defun tramp-debug-message (vec fmt-string &rest arguments) 2050(defun tramp-debug-message (vec fmt-string &rest arguments)
2038 "Append message to debug buffer of VEC. 2051 "Append message to debug buffer of VEC.
2039Message is formatted with FMT-STRING as control string and the remaining 2052Message is formatted with FMT-STRING as control string and the remaining
@@ -2107,10 +2120,12 @@ ARGUMENTS to actually emit the message (if applicable)."
2107 2120
2108(put #'tramp-debug-message 'tramp-suppress-trace t) 2121(put #'tramp-debug-message 'tramp-suppress-trace t)
2109 2122
2123;;;###tramp-autoload
2110(defvar tramp-inhibit-progress-reporter nil 2124(defvar tramp-inhibit-progress-reporter nil
2111 "Show Tramp progress reporter in the minibuffer. 2125 "Show Tramp progress reporter in the minibuffer.
2112This variable is used to disable concurrent progress reporter messages.") 2126This variable is used to disable concurrent progress reporter messages.")
2113 2127
2128;;;###tramp-autoload
2114(defsubst tramp-message (vec-or-proc level fmt-string &rest arguments) 2129(defsubst tramp-message (vec-or-proc level fmt-string &rest arguments)
2115 "Emit a message depending on verbosity level. 2130 "Emit a message depending on verbosity level.
2116VEC-OR-PROC identifies the Tramp buffer to use. It can be either a 2131VEC-OR-PROC identifies the Tramp buffer to use. It can be either a
@@ -2163,8 +2178,6 @@ applicable)."
2163 (concat (format "(%d) # " level) fmt-string) 2178 (concat (format "(%d) # " level) fmt-string)
2164 arguments)))))) 2179 arguments))))))
2165 2180
2166(put #'tramp-message 'tramp-suppress-trace t)
2167
2168(defsubst tramp-backtrace (&optional vec-or-proc force) 2181(defsubst tramp-backtrace (&optional vec-or-proc force)
2169 "Dump a backtrace into the debug buffer. 2182 "Dump a backtrace into the debug buffer.
2170If VEC-OR-PROC is nil, the buffer *debug tramp* is used. FORCE 2183If VEC-OR-PROC is nil, the buffer *debug tramp* is used. FORCE
@@ -2177,8 +2190,6 @@ This function is meant for debugging purposes."
2177 vec-or-proc 10 "\n%s" (with-output-to-string (backtrace))) 2190 vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
2178 (with-output-to-temp-buffer "*debug tramp*" (backtrace)))))) 2191 (with-output-to-temp-buffer "*debug tramp*" (backtrace))))))
2179 2192
2180(put #'tramp-backtrace 'tramp-suppress-trace t)
2181
2182(defun tramp-error (vec-or-proc signal fmt-string &rest arguments) 2193(defun tramp-error (vec-or-proc signal fmt-string &rest arguments)
2183 "Emit an error. 2194 "Emit an error.
2184VEC-OR-PROC identifies the connection to use, SIGNAL is the 2195VEC-OR-PROC identifies the connection to use, SIGNAL is the
@@ -2246,8 +2257,6 @@ an input event arrives. The other arguments are passed to `tramp-error'."
2246 (when (tramp-file-name-equal-p vec (car tramp-current-connection)) 2257 (when (tramp-file-name-equal-p vec (car tramp-current-connection))
2247 (setcdr tramp-current-connection (current-time))))))) 2258 (setcdr tramp-current-connection (current-time)))))))
2248 2259
2249(put #'tramp-error-with-buffer 'tramp-suppress-trace t)
2250
2251;; We must make it a defun, because it is used earlier already. 2260;; We must make it a defun, because it is used earlier already.
2252(defun tramp-user-error (vec-or-proc fmt-string &rest arguments) 2261(defun tramp-user-error (vec-or-proc fmt-string &rest arguments)
2253 "Signal a user error (or \"pilot error\")." 2262 "Signal a user error (or \"pilot error\")."
@@ -2284,8 +2293,6 @@ the resulting error message."
2284 (progn ,@body) 2293 (progn ,@body)
2285 (error (tramp-message ,vec-or-proc 3 ,format ,err) nil)))) 2294 (error (tramp-message ,vec-or-proc 3 ,format ,err) nil))))
2286 2295
2287(put #'tramp-with-demoted-errors 'tramp-suppress-trace t)
2288
2289;; This macro shall optimize the cases where an `file-exists-p' call 2296;; This macro shall optimize the cases where an `file-exists-p' call
2290;; is invoked first. Often, the file exists, so the remote command is 2297;; is invoked first. Often, the file exists, so the remote command is
2291;; superfluous. 2298;; superfluous.
@@ -2302,8 +2309,6 @@ does not exist, otherwise propagate the error."
2302 (tramp-error ,vec 'file-missing ,filename) 2309 (tramp-error ,vec 'file-missing ,filename)
2303 (signal (car ,err) (cdr ,err))))))) 2310 (signal (car ,err) (cdr ,err)))))))
2304 2311
2305(put #'tramp-barf-if-file-missing 'tramp-suppress-trace t)
2306
2307(defun tramp-test-message (fmt-string &rest arguments) 2312(defun tramp-test-message (fmt-string &rest arguments)
2308 "Emit a Tramp message according `default-directory'." 2313 "Emit a Tramp message according `default-directory'."
2309 (cond 2314 (cond
@@ -2399,45 +2404,6 @@ without a visible progress reporter."
2399 (if tm (cancel-timer tm)) 2404 (if tm (cancel-timer tm))
2400 (tramp-message ,vec ,level "%s...%s" ,message cookie))))) 2405 (tramp-message ,vec ,level "%s...%s" ,message cookie)))))
2401 2406
2402(defmacro with-tramp-file-property (vec file property &rest body)
2403 "Check in Tramp cache for PROPERTY, otherwise execute BODY and set cache.
2404FILE must be a local file name on a connection identified via VEC."
2405 (declare (indent 3) (debug t))
2406 `(if (file-name-absolute-p ,file)
2407 (let ((value (tramp-get-file-property
2408 ,vec ,file ,property tramp-cache-undefined)))
2409 (when (eq value tramp-cache-undefined)
2410 ;; We cannot pass @body as parameter to
2411 ;; `tramp-set-file-property' because it mangles our debug
2412 ;; messages.
2413 (setq value (progn ,@body))
2414 (tramp-set-file-property ,vec ,file ,property value))
2415 value)
2416 ,@body))
2417
2418(defmacro with-tramp-connection-property (key property &rest body)
2419 "Check in Tramp for property PROPERTY, otherwise execute BODY and set."
2420 (declare (indent 2) (debug t))
2421 `(let ((value (tramp-get-connection-property
2422 ,key ,property tramp-cache-undefined)))
2423 (when (eq value tramp-cache-undefined)
2424 ;; We cannot pass ,@body as parameter to
2425 ;; `tramp-set-connection-property' because it mangles our debug
2426 ;; messages.
2427 (setq value (progn ,@body))
2428 (tramp-set-connection-property ,key ,property value))
2429 value))
2430
2431(defmacro with-tramp-saved-connection-property (key property &rest body)
2432 "Save PROPERTY, run BODY, reset PROPERTY."
2433 (declare (indent 2) (debug t))
2434 `(let ((value (tramp-get-connection-property
2435 ,key ,property tramp-cache-undefined)))
2436 (unwind-protect (progn ,@body)
2437 (if (eq value tramp-cache-undefined)
2438 (tramp-flush-connection-property ,key ,property)
2439 (tramp-set-connection-property ,key ,property value)))))
2440
2441(defun tramp-drop-volume-letter (name) 2407(defun tramp-drop-volume-letter (name)
2442 "Cut off unnecessary drive letter from file NAME. 2408 "Cut off unnecessary drive letter from file NAME.
2443The functions `tramp-*-handle-expand-file-name' call `expand-file-name' 2409The functions `tramp-*-handle-expand-file-name' call `expand-file-name'
@@ -3424,8 +3390,6 @@ BODY is the backend specific code."
3424 (tramp-dissect-file-name ,directory) 'file-missing ,directory)) 3390 (tramp-dissect-file-name ,directory) 'file-missing ,directory))
3425 ,@body)) 3391 ,@body))
3426 3392
3427(put #'tramp-skeleton-copy-directory 'tramp-suppress-trace t)
3428
3429(defmacro tramp-skeleton-delete-directory (directory recursive trash &rest body) 3393(defmacro tramp-skeleton-delete-directory (directory recursive trash &rest body)
3430 "Skeleton for `tramp-*-handle-delete-directory'. 3394 "Skeleton for `tramp-*-handle-delete-directory'.
3431BODY is the backend specific code." 3395BODY is the backend specific code."
@@ -3441,8 +3405,6 @@ BODY is the backend specific code."
3441 ,@body) 3405 ,@body)
3442 (tramp-flush-directory-properties v localname))) 3406 (tramp-flush-directory-properties v localname)))
3443 3407
3444(put #'tramp-skeleton-delete-directory 'tramp-suppress-trace t)
3445
3446(defmacro tramp-skeleton-directory-files 3408(defmacro tramp-skeleton-directory-files
3447 (directory &optional full match nosort count &rest body) 3409 (directory &optional full match nosort count &rest body)
3448 "Skeleton for `tramp-*-handle-directory-files'. 3410 "Skeleton for `tramp-*-handle-directory-files'.
@@ -3474,8 +3436,6 @@ BODY is the backend specific code."
3474 (tramp-dissect-file-name ,directory) 'file-missing ,directory) 3436 (tramp-dissect-file-name ,directory) 'file-missing ,directory)
3475 nil))) 3437 nil)))
3476 3438
3477(put #'tramp-skeleton-directory-files 'tramp-suppress-trace t)
3478
3479(defmacro tramp-skeleton-directory-files-and-attributes 3439(defmacro tramp-skeleton-directory-files-and-attributes
3480 (directory &optional full match nosort id-format count &rest body) 3440 (directory &optional full match nosort id-format count &rest body)
3481 "Skeleton for `tramp-*-handle-directory-files-and-attributes'. 3441 "Skeleton for `tramp-*-handle-directory-files-and-attributes'.
@@ -3485,7 +3445,6 @@ BODY is the backend specific code."
3485 (with-parsed-tramp-file-name ,directory nil 3445 (with-parsed-tramp-file-name ,directory nil
3486 (tramp-barf-if-file-missing v ,directory 3446 (tramp-barf-if-file-missing v ,directory
3487 (when (file-directory-p ,directory) 3447 (when (file-directory-p ,directory)
3488 (setq ,directory (expand-file-name ,directory))
3489 (let ((temp 3448 (let ((temp
3490 (copy-tree 3449 (copy-tree
3491 (mapcar 3450 (mapcar
@@ -3493,9 +3452,10 @@ BODY is the backend specific code."
3493 (cons 3452 (cons
3494 (car x) 3453 (car x)
3495 (tramp-convert-file-attributes 3454 (tramp-convert-file-attributes
3496 v (car x) ,id-format (cdr x)))) 3455 v (expand-file-name (car x) localname)
3456 ,id-format (cdr x))))
3497 (with-tramp-file-property 3457 (with-tramp-file-property
3498 v localname ",directory-files-and-attributes" 3458 v localname "directory-files-and-attributes"
3499 ,@body)))) 3459 ,@body))))
3500 result item) 3460 result item)
3501 3461
@@ -3524,10 +3484,8 @@ BODY is the backend specific code."
3524 (tramp-dissect-file-name ,directory) 'file-missing ,directory) 3484 (tramp-dissect-file-name ,directory) 'file-missing ,directory)
3525 nil))) 3485 nil)))
3526 3486
3527(put #'tramp-skeleton-directory-files-and-attributes 'tramp-suppress-trace t)
3528
3529(defmacro tramp-skeleton-file-local-copy (filename &rest body) 3487(defmacro tramp-skeleton-file-local-copy (filename &rest body)
3530 "Skeleton for `tramp-*-handle-file-local-copy-files'. 3488 "Skeleton for `tramp-*-handle-file-local-copy'.
3531BODY is the backend specific code." 3489BODY is the backend specific code."
3532 (declare (indent 1) (debug t)) 3490 (declare (indent 1) (debug t))
3533 `(with-parsed-tramp-file-name (file-truename ,filename) nil 3491 `(with-parsed-tramp-file-name (file-truename ,filename) nil
@@ -3541,7 +3499,22 @@ BODY is the backend specific code."
3541 ;; Trigger the `file-missing' error. 3499 ;; Trigger the `file-missing' error.
3542 (signal 'error nil))))) 3500 (signal 'error nil)))))
3543 3501
3544(put #'tramp-skeleton-file-local-copy 'tramp-suppress-trace t) 3502(defmacro tramp-skeleton-set-file-modes-times-uid-gid
3503 (filename &rest body)
3504 "Skeleton for `tramp-*-set-file-{modes,times,uid-gid}'.
3505BODY is the backend specific code."
3506 (declare (indent 1) (debug t))
3507 `(with-parsed-tramp-file-name ,filename nil
3508 (when (not (file-exists-p ,filename))
3509 (tramp-error v 'file-missing ,filename))
3510 (with-tramp-saved-file-properties
3511 v localname
3512 ;; We cannot add "file-attributes", "file-executable-p",
3513 ;; "file-ownership-preserved-p", "file-readable-p",
3514 ;; "file-writable-p".
3515 '("file-directory-p" "file-exists-p" "file-symlinkp" "file-truename")
3516 (tramp-flush-file-properties v localname))
3517 ,@body))
3545 3518
3546(defmacro tramp-skeleton-write-region 3519(defmacro tramp-skeleton-write-region
3547 (start end filename append visit lockname mustbenew &rest body) 3520 (start end filename append visit lockname mustbenew &rest body)
@@ -3602,6 +3575,9 @@ BODY is the backend specific code."
3602 ;; We must also flush the cache of the directory, because 3575 ;; We must also flush the cache of the directory, because
3603 ;; `file-attributes' reads the values from there. 3576 ;; `file-attributes' reads the values from there.
3604 (tramp-flush-file-properties v localname) 3577 (tramp-flush-file-properties v localname)
3578 ;; Set the "file-exists-p" file property, because it is
3579 ;; likely that it is needed shortly after `write-region'.
3580 (tramp-set-file-property v localname "file-exists-p" t)
3605 3581
3606 ;; We must protect `last-coding-system-used', now we have 3582 ;; We must protect `last-coding-system-used', now we have
3607 ;; set it to its correct value. 3583 ;; set it to its correct value.
@@ -3645,8 +3621,6 @@ BODY is the backend specific code."
3645 (tramp-message v 0 "Wrote %s" filename)) 3621 (tramp-message v 0 "Wrote %s" filename))
3646 (run-hooks 'tramp-handle-write-region-hook)))))) 3622 (run-hooks 'tramp-handle-write-region-hook))))))
3647 3623
3648(put #'tramp-skeleton-write-region 'tramp-suppress-trace t)
3649
3650;;; Common file name handler functions for different backends: 3624;;; Common file name handler functions for different backends:
3651 3625
3652(defvar tramp-handle-file-local-copy-hook nil 3626(defvar tramp-handle-file-local-copy-hook nil
@@ -3843,7 +3817,9 @@ Let-bind it when necessary.")
3843 ;; We don't want to run it when `non-essential' is t, or there is 3817 ;; We don't want to run it when `non-essential' is t, or there is
3844 ;; no connection process yet. 3818 ;; no connection process yet.
3845 (when (tramp-connectable-p filename) 3819 (when (tramp-connectable-p filename)
3846 (not (null (file-attributes filename))))) 3820 (with-parsed-tramp-file-name filename nil
3821 (with-tramp-file-property v localname "file-exists-p"
3822 (not (null (file-attributes filename)))))))
3847 3823
3848(defun tramp-handle-file-in-directory-p (filename directory) 3824(defun tramp-handle-file-in-directory-p (filename directory)
3849 "Like `file-in-directory-p' for Tramp files." 3825 "Like `file-in-directory-p' for Tramp files."
@@ -5620,7 +5596,7 @@ the remote host use line-endings as defined in the variable
5620 (when vec 5596 (when vec
5621 (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event) 5597 (tramp-message vec 5 "Sentinel called: `%S' `%s'" proc event)
5622 (tramp-flush-connection-properties proc) 5598 (tramp-flush-connection-properties proc)
5623 (tramp-flush-directory-properties vec "")) 5599 (tramp-flush-directory-properties vec "/"))
5624 (when (buffer-live-p buf) 5600 (when (buffer-live-p buf)
5625 (with-current-buffer buf 5601 (with-current-buffer buf
5626 (when (and prompt (tramp-search-regexp (regexp-quote prompt))) 5602 (when (and prompt (tramp-search-regexp (regexp-quote prompt)))
@@ -6049,6 +6025,7 @@ Return the local name of the temporary file."
6049 (let (create-lockfiles) 6025 (let (create-lockfiles)
6050 (cl-letf (((symbol-function 'tramp-remote-acl-p) #'ignore) 6026 (cl-letf (((symbol-function 'tramp-remote-acl-p) #'ignore)
6051 ((symbol-function 'tramp-remote-selinux-p) #'ignore) 6027 ((symbol-function 'tramp-remote-selinux-p) #'ignore)
6028 ((symbol-function 'tramp-smb-remote-acl-p) #'ignore)
6052 ((symbol-function 'tramp-sudoedit-remote-acl-p) #'ignore) 6029 ((symbol-function 'tramp-sudoedit-remote-acl-p) #'ignore)
6053 ((symbol-function 'tramp-sudoedit-remote-selinux-p) #'ignore)) 6030 ((symbol-function 'tramp-sudoedit-remote-selinux-p) #'ignore))
6054 (tramp-file-local-name 6031 (tramp-file-local-name
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 5a8d9100e18..63ccd05a263 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -2481,6 +2481,19 @@ This checks also `file-name-as-directory', `file-name-directory',
2481 (insert-file-contents tmp-name) 2481 (insert-file-contents tmp-name)
2482 (should (string-equal (buffer-string) "foo"))) 2482 (should (string-equal (buffer-string) "foo")))
2483 2483
2484 ;; Write empty string. Used for creation of temprorary files.
2485 ;; Since Emacs 27.1.
2486 (when (fboundp 'make-empty-file)
2487 (with-no-warnings
2488 (should-error
2489 (make-empty-file tmp-name)
2490 :type 'file-already-exists)
2491 (delete-file tmp-name)
2492 (make-empty-file tmp-name)
2493 (with-temp-buffer
2494 (insert-file-contents tmp-name)
2495 (should (string-equal (buffer-string) "")))))
2496
2484 ;; Write partly. 2497 ;; Write partly.
2485 (with-temp-buffer 2498 (with-temp-buffer
2486 (insert "123456789") 2499 (insert "123456789")
@@ -3790,7 +3803,11 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
3790 (when (tramp--test-emacs28-p) 3803 (when (tramp--test-emacs28-p)
3791 (with-no-warnings 3804 (with-no-warnings
3792 (set-file-modes tmp-name1 #o222 'nofollow) 3805 (set-file-modes tmp-name1 #o222 'nofollow)
3793 (should (= (file-modes tmp-name1 'nofollow) #o222))))) 3806 (should (= (file-modes tmp-name1 'nofollow) #o222))))
3807 ;; Setting the mode for not existing files shall fail.
3808 (should-error
3809 (set-file-modes tmp-name2 #o777)
3810 :type 'file-missing))
3794 3811
3795 ;; Cleanup. 3812 ;; Cleanup.
3796 (ignore-errors (delete-file tmp-name1))) 3813 (ignore-errors (delete-file tmp-name1)))
@@ -4153,6 +4170,10 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
4153 (tramp-compat-time-equal-p 4170 (tramp-compat-time-equal-p
4154 (file-attribute-modification-time (file-attributes tmp-name1)) 4171 (file-attribute-modification-time (file-attributes tmp-name1))
4155 (seconds-to-time 1))) 4172 (seconds-to-time 1)))
4173 ;; Setting the time for not existing files shall fail.
4174 (should-error
4175 (set-file-times tmp-name2)
4176 :type 'file-missing)
4156 (write-region "bla" nil tmp-name2) 4177 (write-region "bla" nil tmp-name2)
4157 (should (file-exists-p tmp-name2)) 4178 (should (file-exists-p tmp-name2))
4158 (should (file-newer-than-file-p tmp-name2 tmp-name1)) 4179 (should (file-newer-than-file-p tmp-name2 tmp-name1))