branch: externals/tramp commit cdbc051cd7f2c7d6fdc4f6d7b5a85a0ceb290787 Author: Michael Albinus <michael.albi...@gmx.de> Commit: Michael Albinus <michael.albi...@gmx.de>
Tramp ELPA version 2.7.2.3 released --- README | 6 +- test/tramp-tests.el | 128 +++++++++++++++++++++------- texi/.gitignore | 1 + texi/Makefile | 4 +- texi/trampver.texi | 2 +- tramp-adb.el | 2 +- tramp-cmds.el | 4 +- tramp-gvfs.el | 198 ++++++++++++++++++++++--------------------- tramp-sh.el | 239 +++++++++++++++++++++++++++------------------------- tramp-smb.el | 191 +++++++++++++++++++++-------------------- tramp-sshfs.el | 34 ++++---- tramp-sudoedit.el | 152 +++++++++++++++++---------------- tramp.el | 64 +++++++++----- trampver.el | 6 +- 14 files changed, 568 insertions(+), 463 deletions(-) diff --git a/README b/README index 8ce4391156..147214c4d9 100644 --- a/README +++ b/README @@ -32,11 +32,11 @@ Emacs 28 or older • Remove all byte-compiled Tramp files - $ rm -f ~/.emacs.d/elpa/tramp-2.7.2.2/tramp*.elc + $ rm -f ~/.emacs.d/elpa/tramp-2.7.2.3/tramp*.elc • Start Emacs with Tramp's source files - $ emacs -L ~/.emacs.d/elpa/tramp-2.7.2.2 -l tramp + $ emacs -L ~/.emacs.d/elpa/tramp-2.7.2.3 -l tramp This should not give you the error. @@ -50,7 +50,7 @@ Mitigation of a bug in Emacs 29.1 --------------------------------- Due to a bug in Emacs 29.1, you must apply the following change prior -installation or upgrading Tramp 2.7.2.2 from GNU ELPA: +installation or upgrading Tramp 2.7.2.3 from GNU ELPA: (when (string-equal emacs-version "29.1") (with-current-buffer diff --git a/test/tramp-tests.el b/test/tramp-tests.el index c1ef88937f..605b26206c 100644 --- a/test/tramp-tests.el +++ b/test/tramp-tests.el @@ -190,7 +190,7 @@ A resource file is in the resource directory as per tramp-error-show-message-timeout nil tramp-persistency-file-name nil tramp-verbose 0 - vc-handled-backends nil) + vc-handled-backends (unless noninteractive vc-handled-backends)) (defvar tramp--test-enabled-checked nil "Cached result of `tramp--test-enabled'. @@ -2886,7 +2886,9 @@ This checks also `file-name-as-directory', `file-name-directory', (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) - (tmp-name3 (tramp--test-make-temp-name 'local quoted))) + (tmp-name3 (tramp--test-make-temp-name 'local quoted)) + (tmp-name4 + (file-name-nondirectory (tramp--test-make-temp-name 'local quoted)))) (dolist (source-target `(;; Copy on remote side. (,tmp-name1 . ,tmp-name2) @@ -2894,8 +2896,12 @@ This checks also `file-name-as-directory', `file-name-directory', (,tmp-name1 . ,tmp-name3) ;; Copy from local side to remote side. (,tmp-name3 . ,tmp-name1))) - (let ((source (car source-target)) - (target (cdr source-target))) + (let* ((source (car source-target)) + (source-link + (expand-file-name tmp-name4 (file-name-directory source))) + (target (cdr source-target)) + (target-link + (expand-file-name tmp-name4 (file-name-directory target)))) ;; Copy simple file. (unwind-protect @@ -2920,6 +2926,26 @@ This checks also `file-name-as-directory', `file-name-directory', (ignore-errors (delete-file source)) (ignore-errors (delete-file target))) + ;; Copy symlinked file. + (unwind-protect + (tramp--test-ignore-make-symbolic-link-error + (write-region "foo" nil source-link) + (should (file-exists-p source-link)) + (make-symbolic-link tmp-name4 source) + (should (file-exists-p source)) + (should (string-equal (file-symlink-p source) tmp-name4)) + (copy-file source target) + ;; Some backends like tramp-gvfs.el do not create the + ;; link on the target. + (when (file-symlink-p target) + (should (string-equal (file-symlink-p target) tmp-name4)))) + + ;; Cleanup. + (ignore-errors (delete-file source)) + (ignore-errors (delete-file source-link)) + (ignore-errors (delete-file target)) + (ignore-errors (delete-file target-link))) + ;; Copy file to directory. (unwind-protect ;; This doesn't work on FTP. @@ -2995,7 +3021,9 @@ This checks also `file-name-as-directory', `file-name-directory', (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) - (tmp-name3 (tramp--test-make-temp-name 'local quoted))) + (tmp-name3 (tramp--test-make-temp-name 'local quoted)) + (tmp-name4 + (file-name-nondirectory (tramp--test-make-temp-name 'local quoted)))) (dolist (source-target `(;; Rename on remote side. (,tmp-name1 . ,tmp-name2) @@ -3003,8 +3031,12 @@ This checks also `file-name-as-directory', `file-name-directory', (,tmp-name1 . ,tmp-name3) ;; Rename from local side to remote side. (,tmp-name3 . ,tmp-name1))) - (let ((source (car source-target)) - (target (cdr source-target))) + (let* ((source (car source-target)) + (source-link + (expand-file-name tmp-name4 (file-name-directory source))) + (target (cdr source-target)) + (target-link + (expand-file-name tmp-name4 (file-name-directory target)))) ;; Rename simple file. (unwind-protect @@ -3033,6 +3065,27 @@ This checks also `file-name-as-directory', `file-name-directory', (ignore-errors (delete-file source)) (ignore-errors (delete-file target))) + ;; Rename symlinked file. + (unwind-protect + (tramp--test-ignore-make-symbolic-link-error + (write-region "foo" nil source-link) + (should (file-exists-p source-link)) + (make-symbolic-link tmp-name4 source) + (should (file-exists-p source)) + (should (string-equal (file-symlink-p source) tmp-name4)) + (rename-file source target) + (should-not (file-exists-p source)) + ;; Some backends like tramp-gvfs.el do not create the + ;; link on the target. + (when (file-symlink-p target) + (should (string-equal (file-symlink-p target) tmp-name4)))) + + ;; Cleanup. + (ignore-errors (delete-file source)) + (ignore-errors (delete-file source-link)) + (ignore-errors (delete-file target)) + (ignore-errors (delete-file target-link))) + ;; Rename file to directory. (unwind-protect (progn @@ -3813,6 +3866,7 @@ This tests also `access-file', `file-readable-p', (should (stringp (file-attribute-user-id attr))) (should (stringp (file-attribute-group-id attr))) + ;; Symbolic links. (tramp--test-ignore-make-symbolic-link-error (should-error (access-file tmp-name2 "error") @@ -3832,7 +3886,26 @@ This tests also `access-file', `file-readable-p', (if quoted #'file-name-quote #'identity) (file-attribute-type attr)) (file-remote-p (file-truename tmp-name1) 'localname))) - (delete-file tmp-name2)) + (delete-file tmp-name2) + + ;; A non-existent or cyclic link target makes the file + ;; unaccessible. + (dolist (target + `("does-not-exist" ,(file-name-nondirectory tmp-name2))) + (make-symbolic-link target tmp-name2) + (should (file-symlink-p tmp-name2)) + (should-not (file-exists-p tmp-name2)) + (should-not (file-directory-p tmp-name2)) + (should-error + (access-file tmp-name2 "error") + :type + (if (string-equal target "does-not-exist") + 'file-missing 'file-error)) + ;; `file-ownership-preserved-p' should return t for + ;; symlinked files to a non-existing or cyclic target. + (when test-file-ownership-preserved-p + (should (file-ownership-preserved-p tmp-name2 'group))) + (delete-file tmp-name2))) ;; Check, that "//" in symlinks are handled properly. (with-temp-buffer @@ -4488,13 +4561,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (file-symlink-p tmp-name1)) (should (file-symlink-p tmp-name2)) (should-not (file-regular-p tmp-name1)) - (should-not (file-regular-p tmp-name2)) - (should-error - (file-truename tmp-name1) - :type 'file-error) - (should-error - (file-truename tmp-name2) - :type 'file-error)))) + (should-not (file-regular-p tmp-name2))))) ;; Cleanup. (ignore-errors @@ -5274,19 +5341,20 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; (delete-file tmp-name))) ;; Check remote and local STDERR. - (dolist (local '(nil t)) - (setq tmp-name (tramp--test-make-temp-name local quoted)) - (should-not - (zerop - (process-file "cat" nil `(t ,tmp-name) nil "/does-not-exist"))) - (with-temp-buffer - (insert-file-contents tmp-name) - (should - (string-match-p - (rx "cat:" (* nonl) " No such file or directory") - (buffer-string))) - (should-not (get-buffer-window (current-buffer) t)) - (delete-file tmp-name)))) + (unless (tramp--test-sshfs-p) + (dolist (local '(nil t)) + (setq tmp-name (tramp--test-make-temp-name local quoted)) + (should-not + (zerop + (process-file "cat" nil `(t ,tmp-name) nil "/does-not-exist"))) + (with-temp-buffer + (insert-file-contents tmp-name) + (should + (string-match-p + (rx "cat:" (* nonl) " No such file or directory") + (buffer-string))) + (should-not (get-buffer-window (current-buffer) t)) + (delete-file tmp-name))))) ;; Cleanup. (ignore-errors (kill-buffer buffer)) @@ -7439,10 +7507,6 @@ This requires restrictions of file name syntax." (if quoted #'file-name-quote #'identity) (file-attribute-type (file-attributes file3))) (file-remote-p (file-truename file1) 'localname))) - ;; Check file contents. - (with-temp-buffer - (insert-file-contents file3) - (should (string-equal (buffer-string) elt))) (delete-file file3)))) ;; Check file names. diff --git a/texi/.gitignore b/texi/.gitignore index 7dc56a1698..b9fc08e253 100644 --- a/texi/.gitignore +++ b/texi/.gitignore @@ -7,6 +7,7 @@ *.html *.info *.ky +*.kys *.log *.pdf *.pg diff --git a/texi/Makefile b/texi/Makefile index 79c05deb55..db8f86df76 100644 --- a/texi/Makefile +++ b/texi/Makefile @@ -23,8 +23,8 @@ MAKEINFO = makeinfo --no-warn --no-split TEXI_FILES = $(wildcard *.texi) -CLEAN_FILES = .\\\#* \\\#* .*~ *~ *.aux *.cp *.cps *.diff *.fn *.fns \ - *.ky *.log *.pg *.tmp *.toc *.tp *.vr *.vrs ../tramp.info +CLEAN_FILES = .\\\#* \\\#* .*~ *~ *.aux *.cp *.cps *.diff *.fn *.fns *.ky \ + *.kys *.log *.pg *.tmp *.toc *.tp *.vr *.vrs ../tramp.info SOURCE_DIR = ~/src/tramp .PHONY: all clean sync diff --git a/texi/trampver.texi b/texi/trampver.texi index f3d1241a49..5365fc3172 100644 --- a/texi/trampver.texi +++ b/texi/trampver.texi @@ -7,7 +7,7 @@ @c In the Tramp GIT, the version number and the bug report address @c are auto-frobbed from configure.ac. -@set trampver 2.7.2.2 +@set trampver 2.7.2.3 @set trampurl https://www.gnu.org/software/tramp/ @set tramp-bug-report-address tramp-devel@@gnu.org @set emacsver 27.1 diff --git a/tramp-adb.el b/tramp-adb.el index 705d86828c..1ecabd8165 100644 --- a/tramp-adb.el +++ b/tramp-adb.el @@ -998,7 +998,7 @@ error and non-nil on success." ;; <https://android.stackexchange.com/questions/226638/how-to-use-multibyte-file-names-in-adb-shell/232379#232379> ;; mksh uses UTF-8 internally, but is currently limited to the ;; BMP (basic multilingua plane), which means U+0000 to - ;; U+FFFD. If you want to use SMP codepoints (U-00010000 to + ;; U+FFFD. If you want to use SMP codepoints (U-00010000 to ;; U-0010FFFD) on the input line, you currently have to disable ;; the UTF-8 mode (sorry). (tramp-adb-execute-adb-command vec "shell" command) diff --git a/tramp-cmds.el b/tramp-cmds.el index e31123ecd5..f03fa5cf40 100644 --- a/tramp-cmds.el +++ b/tramp-cmds.el @@ -611,7 +611,9 @@ If the buffer runs `dired', the buffer is reverted." (interactive) (cond ((buffer-file-name) - (find-alternate-file (tramp-file-name-with-sudo (buffer-file-name)))) + (let ((pos (point))) + (find-alternate-file (tramp-file-name-with-sudo (buffer-file-name))) + (goto-char pos))) ((tramp-dired-buffer-p) (dired-unadvertise (expand-file-name default-directory)) (setq default-directory (tramp-file-name-with-sudo default-directory) diff --git a/tramp-gvfs.el b/tramp-gvfs.el index f422d8e3d6..3df69d79fc 100644 --- a/tramp-gvfs.el +++ b/tramp-gvfs.el @@ -1042,105 +1042,113 @@ file names." (unless (memq op '(copy rename)) (error "Unknown operation `%s', must be `copy' or `rename'" op)) - (setq filename (file-truename filename)) + ;; We cannot use `file-truename', this would fail for symlinks with + ;; non-existing target. + (setq filename (expand-file-name filename)) (if (file-directory-p filename) (progn (copy-directory filename newname keep-date t) (when (eq op 'rename) (delete-directory filename 'recursive))) + (if (file-symlink-p filename) + (progn + (make-symbolic-link + (file-symlink-p filename) newname ok-if-already-exists) + (when (eq op 'rename) (delete-file filename))) + + (let ((t1 (tramp-tramp-file-p filename)) + (t2 (tramp-tramp-file-p newname)) + (equal-remote (tramp-equal-remote filename newname)) + (volatile + (and (eq op 'rename) (tramp-gvfs-file-name-p filename) + (equal + (cdr + (assoc + "standard::is-volatile" + (tramp-gvfs-get-file-attributes filename))) + "TRUE"))) + ;; "gvfs-rename" is not trustworthy. + (gvfs-operation (if (eq op 'copy) "gvfs-copy" "gvfs-move")) + (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) + + (with-parsed-tramp-file-name (if t1 filename newname) nil + (tramp-barf-if-file-missing v filename + (when (and (not ok-if-already-exists) (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + (when (and (file-directory-p newname) + (not (directory-name-p newname))) + (tramp-error v 'file-error "File is a directory %s" newname)) + (when (file-regular-p newname) + (delete-file newname)) - (let ((t1 (tramp-tramp-file-p filename)) - (t2 (tramp-tramp-file-p newname)) - (equal-remote (tramp-equal-remote filename newname)) - (volatile - (and (eq op 'rename) (tramp-gvfs-file-name-p filename) - (equal - (cdr - (assoc - "standard::is-volatile" - (tramp-gvfs-get-file-attributes filename))) - "TRUE"))) - ;; "gvfs-rename" is not trustworthy. - (gvfs-operation (if (eq op 'copy) "gvfs-copy" "gvfs-move")) - (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) - - (with-parsed-tramp-file-name (if t1 filename newname) nil - (tramp-barf-if-file-missing v filename - (when (and (not ok-if-already-exists) (file-exists-p newname)) - (tramp-error v 'file-already-exists newname)) - (when (and (file-directory-p newname) - (not (directory-name-p newname))) - (tramp-error v 'file-error "File is a directory %s" newname)) - (when (file-regular-p newname) - (delete-file newname)) - - (cond - ;; We cannot rename volatile files, as used by Google-drive. - ((and (not equal-remote) volatile) - (prog1 (copy-file - filename newname ok-if-already-exists keep-date - preserve-uid-gid preserve-extended-attributes) - (delete-file filename))) - - ;; We cannot copy or rename directly. - ((or (and equal-remote - (tramp-get-connection-property v "direct-copy-failed")) - (and t1 (not (tramp-gvfs-file-name-p filename))) - (and t2 (not (tramp-gvfs-file-name-p newname)))) - (let ((tmpfile (tramp-compat-make-temp-file filename))) - (if (eq op 'copy) - (copy-file - filename tmpfile t keep-date preserve-uid-gid - preserve-extended-attributes) - (rename-file filename tmpfile t)) - (rename-file tmpfile newname ok-if-already-exists))) - - ;; Direct action. - (t (with-tramp-progress-reporter - v 0 (format "%s %s to %s" msg-operation filename newname) - (unless - (and (apply - #'tramp-gvfs-send-command v gvfs-operation - (append - (and (eq op 'copy) (or keep-date preserve-uid-gid) - '("--preserve")) - (list - (tramp-gvfs-url-file-name filename) - (tramp-gvfs-url-file-name newname)))) - ;; Some backends do not return a proper error - ;; code in case of direct copy/move. Apply - ;; sanity checks. - (or (not equal-remote) - (and - (tramp-gvfs-info newname) - (or (eq op 'copy) - (not (tramp-gvfs-info filename)))))) - - (if (or (not equal-remote) - (and equal-remote - (tramp-get-connection-property - v "direct-copy-failed"))) - ;; Propagate the error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (tramp-error-with-buffer - nil v 'file-error - "%s failed, see buffer `%s' for details" - msg-operation (buffer-name))) - - ;; Some WebDAV server, like the one from QNAP, do - ;; not support direct copy/move. Try a fallback. - (tramp-set-connection-property v "direct-copy-failed" t) - (tramp-gvfs-do-copy-or-rename-file - op filename newname ok-if-already-exists keep-date - preserve-uid-gid preserve-extended-attributes)))) - - (when (and t1 (eq op 'rename)) - (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v localname))) - - (when t2 - (with-parsed-tramp-file-name newname nil - (tramp-flush-file-properties v localname)))))))))) + (cond + ;; We cannot rename volatile files, as used by Google-drive. + ((and (not equal-remote) volatile) + (prog1 (copy-file + filename newname ok-if-already-exists keep-date + preserve-uid-gid preserve-extended-attributes) + (delete-file filename))) + + ;; We cannot copy or rename directly. + ((or (and equal-remote + (tramp-get-connection-property v "direct-copy-failed")) + (and t1 (not (tramp-gvfs-file-name-p filename))) + (and t2 (not (tramp-gvfs-file-name-p newname)))) + (let ((tmpfile (tramp-compat-make-temp-file filename))) + (if (eq op 'copy) + (copy-file + filename tmpfile t keep-date preserve-uid-gid + preserve-extended-attributes) + (rename-file filename tmpfile t)) + (rename-file tmpfile newname ok-if-already-exists))) + + ;; Direct action. + (t (with-tramp-progress-reporter + v 0 (format "%s %s to %s" msg-operation filename newname) + (unless + (and (apply + #'tramp-gvfs-send-command v gvfs-operation + (append + (and (eq op 'copy) (or keep-date preserve-uid-gid) + '("--preserve")) + (list + (tramp-gvfs-url-file-name filename) + (tramp-gvfs-url-file-name newname)))) + ;; Some backends do not return a proper + ;; error code in case of direct copy/move. + ;; Apply sanity checks. + (or (not equal-remote) + (and + (tramp-gvfs-info newname) + (or (eq op 'copy) + (not (tramp-gvfs-info filename)))))) + + (if (or (not equal-remote) + (and equal-remote + (tramp-get-connection-property + v "direct-copy-failed"))) + ;; Propagate the error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (tramp-error-with-buffer + nil v 'file-error + "%s failed, see buffer `%s' for details" + msg-operation (buffer-name))) + + ;; Some WebDAV server, like the one from QNAP, + ;; do not support direct copy/move. Try a + ;; fallback. + (tramp-set-connection-property v "direct-copy-failed" t) + (tramp-gvfs-do-copy-or-rename-file + op filename newname ok-if-already-exists keep-date + preserve-uid-gid preserve-extended-attributes)))) + + (when (and t1 (eq op 'rename)) + (with-parsed-tramp-file-name filename nil + (tramp-flush-file-properties v localname))) + + (when t2 + (with-parsed-tramp-file-name newname nil + (tramp-flush-file-properties v localname))))))))))) (defun tramp-gvfs-handle-copy-file (filename newname &optional ok-if-already-exists keep-date @@ -2215,7 +2223,7 @@ connection if a previous connection has died for some reason." method '(("smb" . "smb-share") ("davs" . "dav") ("nextcloud" . "dav") - ("afp". "afp-volume") + ("afp" . "afp-volume") ("gdrive" . "google-drive"))) method) tramp-gvfs-mounttypes) diff --git a/tramp-sh.el b/tramp-sh.el index 98a4c7d90f..ef4ddee8a5 100644 --- a/tramp-sh.el +++ b/tramp-sh.el @@ -1853,7 +1853,10 @@ ID-FORMAT valid values are `string' and `integer'." ;; test. (tramp-check-remote-uname v tramp-bsd-unames) (= (file-attribute-group-id attributes) - (tramp-get-remote-gid v 'integer))))))))) + (tramp-get-remote-gid v 'integer)) + ;; FIXME: `file-ownership-preserved-p' tests also the + ;; ownership of the parent directory. We don't. + ))))))) ;; Directory listings. @@ -2125,123 +2128,129 @@ file names." (progn (copy-directory filename newname keep-date t) (when (eq op 'rename) (delete-directory filename 'recursive))) + (if (file-symlink-p filename) + (progn + (make-symbolic-link + (file-symlink-p filename) newname ok-if-already-exists) + (when (eq op 'rename) (delete-file filename))) + + ;; FIXME: This should be optimized. Computing `file-attributes' + ;; checks already, whether the file exists. + (let ((t1 (tramp-tramp-file-p filename)) + (t2 (tramp-tramp-file-p newname)) + (length (or (file-attribute-size + (file-attributes (file-truename filename))) + ;; `filename' doesn't exist, for example due + ;; to non-existent symlink target. + 0)) + (file-times (file-attribute-modification-time + (file-attributes filename))) + (file-modes (tramp-default-file-modes filename)) + (msg-operation (if (eq op 'copy) "Copying" "Renaming")) + copy-keep-date) + + (with-parsed-tramp-file-name (if t1 filename newname) nil + (tramp-barf-if-file-missing v filename + (when (and (not ok-if-already-exists) (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + (when (and (file-directory-p newname) + (not (directory-name-p newname))) + (tramp-error v 'file-error "File is a directory %s" newname)) - ;; FIXME: This should be optimized. Computing `file-attributes' - ;; checks already, whether the file exists. - (let ((t1 (tramp-tramp-file-p filename)) - (t2 (tramp-tramp-file-p newname)) - (length (file-attribute-size - (file-attributes (file-truename filename)))) - (file-times (file-attribute-modification-time - (file-attributes filename))) - (file-modes (tramp-default-file-modes filename)) - (msg-operation (if (eq op 'copy) "Copying" "Renaming")) - copy-keep-date) - - (with-parsed-tramp-file-name (if t1 filename newname) nil - (unless length - (tramp-error v 'file-missing filename)) - (tramp-barf-if-file-missing v filename - (when (and (not ok-if-already-exists) (file-exists-p newname)) - (tramp-error v 'file-already-exists newname)) - (when (and (file-directory-p newname) - (not (directory-name-p newname))) - (tramp-error v 'file-error "File is a directory %s" newname)) - - (with-tramp-progress-reporter - v 0 (format "%s %s to %s" msg-operation filename newname) + (with-tramp-progress-reporter + v 0 (format "%s %s to %s" msg-operation filename newname) - (cond - ;; Both are Tramp files. - ((and t1 t2) - (with-parsed-tramp-file-name filename v1 - (with-parsed-tramp-file-name newname v2 - (cond - ;; Shortcut: if method, host, user are the same for - ;; both files, we invoke `cp' or `mv' on the remote - ;; host directly. - ((tramp-equal-remote filename newname) - (setq copy-keep-date - (or (eq op 'rename) keep-date preserve-uid-gid)) - (tramp-do-copy-or-rename-file-directly - op filename newname - ok-if-already-exists keep-date preserve-uid-gid)) - - ;; Try out-of-band operation. - ((and - (tramp-method-out-of-band-p v1 length) - (tramp-method-out-of-band-p v2 length)) - (setq copy-keep-date - (tramp-get-method-parameter v 'tramp-copy-keep-date)) - (tramp-do-copy-or-rename-file-out-of-band - op filename newname ok-if-already-exists keep-date)) - - ;; No shortcut was possible. So we copy the file - ;; first. If the operation was `rename', we go - ;; back and delete the original file (if the copy - ;; was successful). The approach is simple-minded: - ;; we create a new buffer, insert the contents of - ;; the source file into it, then write out the - ;; buffer to the target file. The advantage is - ;; that it doesn't matter which file name handlers - ;; are used for the source and target file. - (t - (tramp-do-copy-or-rename-file-via-buffer - op filename newname ok-if-already-exists keep-date)))))) - - ;; One file is a Tramp file, the other one is local. - ((or t1 t2) (cond - ;; Fast track on local machine. - ((tramp-local-host-p v) - (setq copy-keep-date - (or (eq op 'rename) keep-date preserve-uid-gid)) - (tramp-do-copy-or-rename-file-directly - op filename newname - ok-if-already-exists keep-date preserve-uid-gid)) - - ;; If the Tramp file has an out-of-band method, the - ;; corresponding copy-program can be invoked. - ((tramp-method-out-of-band-p v length) - (setq copy-keep-date - (tramp-get-method-parameter v 'tramp-copy-keep-date)) - (tramp-do-copy-or-rename-file-out-of-band - op filename newname ok-if-already-exists keep-date)) + ;; Both are Tramp files. + ((and t1 t2) + (with-parsed-tramp-file-name filename v1 + (with-parsed-tramp-file-name newname v2 + (cond + ;; Shortcut: if method, host, user are the same + ;; for both files, we invoke `cp' or `mv' on the + ;; remote host directly. + ((tramp-equal-remote filename newname) + (setq copy-keep-date + (or (eq op 'rename) keep-date preserve-uid-gid)) + (tramp-do-copy-or-rename-file-directly + op filename newname + ok-if-already-exists keep-date preserve-uid-gid)) + + ;; Try out-of-band operation. + ((and + (tramp-method-out-of-band-p v1 length) + (tramp-method-out-of-band-p v2 length)) + (setq copy-keep-date + (tramp-get-method-parameter v 'tramp-copy-keep-date)) + (tramp-do-copy-or-rename-file-out-of-band + op filename newname ok-if-already-exists keep-date)) + + ;; No shortcut was possible. So we copy the file + ;; first. If the operation was `rename', we go + ;; back and delete the original file (if the copy + ;; was successful). The approach is simple-minded: + ;; we create a new buffer, insert the contents of + ;; the source file into it, then write out the + ;; buffer to the target file. The advantage is + ;; that it doesn't matter which file name handlers + ;; are used for the source and target file. + (t + (tramp-do-copy-or-rename-file-via-buffer + op filename newname ok-if-already-exists keep-date)))))) + + ;; One file is a Tramp file, the other one is local. + ((or t1 t2) + (cond + ;; Fast track on local machine. + ((tramp-local-host-p v) + (setq copy-keep-date + (or (eq op 'rename) keep-date preserve-uid-gid)) + (tramp-do-copy-or-rename-file-directly + op filename newname + ok-if-already-exists keep-date preserve-uid-gid)) + + ;; If the Tramp file has an out-of-band method, the + ;; corresponding copy-program can be invoked. + ((tramp-method-out-of-band-p v length) + (setq copy-keep-date + (tramp-get-method-parameter v 'tramp-copy-keep-date)) + (tramp-do-copy-or-rename-file-out-of-band + op filename newname ok-if-already-exists keep-date)) + + ;; Use the inline method via a Tramp buffer. + (t (tramp-do-copy-or-rename-file-via-buffer + op filename newname ok-if-already-exists keep-date)))) + + (t + ;; One of them must be a Tramp file. + (error "Tramp implementation says this cannot happen"))) + + ;; In case of `rename', we must flush the cache of the source file. + (when (and t1 (eq op 'rename)) + (with-parsed-tramp-file-name filename v1 + (tramp-flush-file-properties v1 v1-localname))) + + ;; NEWNAME has wrong cached values. + (when t2 + (with-parsed-tramp-file-name newname v2 + (tramp-flush-file-properties v2 v2-localname))) - ;; Use the inline method via a Tramp buffer. - (t (tramp-do-copy-or-rename-file-via-buffer - op filename newname ok-if-already-exists keep-date)))) + ;; Handle `preserve-extended-attributes'. We ignore + ;; possible errors, because ACL strings could be + ;; incompatible. + (when-let* ((attributes (and preserve-extended-attributes + (file-extended-attributes filename)))) + (ignore-errors + (set-file-extended-attributes newname attributes))) - (t - ;; One of them must be a Tramp file. - (error "Tramp implementation says this cannot happen"))) - - ;; In case of `rename', we must flush the cache of the source file. - (when (and t1 (eq op 'rename)) - (with-parsed-tramp-file-name filename v1 - (tramp-flush-file-properties v1 v1-localname))) - - ;; NEWNAME has wrong cached values. - (when t2 - (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties v2 v2-localname))) - - ;; Handle `preserve-extended-attributes'. We ignore - ;; possible errors, because ACL strings could be - ;; incompatible. - (when-let* ((attributes (and preserve-extended-attributes - (file-extended-attributes filename)))) - (ignore-errors - (set-file-extended-attributes newname attributes))) - - ;; KEEP-DATE handling. - (when (and keep-date (not copy-keep-date)) - (tramp-compat-set-file-times - newname file-times (unless ok-if-already-exists 'nofollow))) - - ;; Set the mode. - (unless (and keep-date copy-keep-date) - (set-file-modes newname file-modes)))))))) + ;; KEEP-DATE handling. + (when (and keep-date (not copy-keep-date)) + (tramp-compat-set-file-times + newname file-times (unless ok-if-already-exists 'nofollow))) + + ;; Set the mode. + (unless (and keep-date copy-keep-date) + (set-file-modes newname file-modes))))))))) (defun tramp-do-copy-or-rename-file-via-buffer (op filename newname _ok-if-already-exists _keep-date) @@ -3117,7 +3126,7 @@ will be used." ;; character to read. When a process does ;; not read from stdin, like magit, it ;; should set a timeout - ;; instead. See`tramp-pipe-stty-settings'. + ;; instead. See `tramp-pipe-stty-settings'. ;; (Bug#62093) ;; FIXME: Shall we rather use "stty raw"? (tramp-send-command @@ -5653,7 +5662,7 @@ Nonexistent directories are removed from spec." (lambda (x) (not (tramp-get-file-property vec x "file-directory-p"))) remote-path)))))) -;; The PIPE_BUF in POSIX [1] can be as low as 512 [2]. Here are the values +;; The PIPE_BUF in POSIX [1] can be as low as 512 [2]. Here are the values ;; on various platforms: ;; - 512 on macOS, FreeBSD, NetBSD, OpenBSD, MirBSD, native Windows. ;; - 4 KiB on Linux, OSF/1, Cygwin, Haiku. diff --git a/tramp-smb.el b/tramp-smb.el index 716c6245f0..57fdd61a4c 100644 --- a/tramp-smb.el +++ b/tramp-smb.el @@ -114,6 +114,7 @@ this variable \"client min protocol=NT1\"." "Read from server failed, maybe it closed the connection" "Call timed out: server did not respond" (: (+ (not blank)) ": command not found") + (: (+ (not blank)) " does not exist") "Server doesn't support UNIX CIFS calls" (| ;; Samba. "ERRDOS" @@ -597,66 +598,63 @@ KEEP-DATE has no effect in case NEWNAME resides on an SMB server. PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (setq filename (expand-file-name filename) newname (expand-file-name newname)) - (with-tramp-progress-reporter - (tramp-dissect-file-name - (if (tramp-tramp-file-p filename) filename newname)) - 0 (format "Copying %s to %s" filename newname) - (if (file-directory-p filename) - (copy-directory filename newname keep-date 'parents 'copy-contents) + (with-parsed-tramp-file-name + (if (tramp-tramp-file-p filename) filename newname) nil + (with-tramp-progress-reporter + v 0 (format "Copying %s to %s" filename newname) + + (if (file-directory-p filename) + (copy-directory filename newname keep-date 'parents 'copy-contents) + + (tramp-barf-if-file-missing v filename + ;; `file-local-copy' returns a file name also for a local + ;; file with `jka-compr-handler', so we cannot trust its + ;; result as indication for a remote file name. + (if-let* ((tmpfile + (and (tramp-tramp-file-p filename) + (file-local-copy filename)))) + ;; Remote filename. + (condition-case err + (rename-file tmpfile newname ok-if-already-exists) + ((error quit) + (delete-file tmpfile) + (signal (car err) (cdr err)))) + + ;; Remote newname. + (when (and (file-directory-p newname) + (directory-name-p newname)) + (setq newname + (expand-file-name + (file-name-nondirectory filename) newname))) + + (when (and (not ok-if-already-exists) (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + (when (and (file-directory-p newname) + (not (directory-name-p newname))) + (tramp-error v 'file-error "File is a directory %s" newname)) + + (unless (tramp-smb-get-share v) + (tramp-error + v 'file-error "Target `%s' must contain a share name" newname)) + (unless (tramp-smb-send-command + v (format "put %s %s" + (tramp-smb-shell-quote-argument filename) + (tramp-smb-shell-quote-localname v))) + (tramp-error + v 'file-error "Cannot copy `%s' to `%s'" filename newname)) - (unless (file-exists-p filename) - (tramp-error - (tramp-dissect-file-name - (if (tramp-tramp-file-p filename) filename newname)) - 'file-missing filename)) - - ;; `file-local-copy' returns a file name also for a local file - ;; with `jka-compr-handler', so we cannot trust its result as - ;; indication for a remote file name. - (if-let* ((tmpfile - (and (tramp-tramp-file-p filename) (file-local-copy filename)))) - ;; Remote filename. - (condition-case err - (rename-file tmpfile newname ok-if-already-exists) - ((error quit) - (delete-file tmpfile) - (signal (car err) (cdr err)))) - - ;; Remote newname. - (when (and (file-directory-p newname) - (directory-name-p newname)) - (setq newname - (expand-file-name (file-name-nondirectory filename) newname))) - - (with-parsed-tramp-file-name newname nil - (when (and (not ok-if-already-exists) (file-exists-p newname)) - (tramp-error v 'file-already-exists newname)) - (when (and (file-directory-p newname) - (not (directory-name-p newname))) - (tramp-error v 'file-error "File is a directory %s" newname)) - - (unless (tramp-smb-get-share v) - (tramp-error - v 'file-error "Target `%s' must contain a share name" newname)) - (unless (tramp-smb-send-command - v (format "put %s %s" - (tramp-smb-shell-quote-argument filename) - (tramp-smb-shell-quote-localname v))) - (tramp-error - v 'file-error "Cannot copy `%s' to `%s'" filename newname)) - - ;; When newname did exist, we have wrong cached values. - (when (tramp-tramp-file-p newname) - (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties v2 v2-localname)))))) - - ;; KEEP-DATE handling. - (when keep-date - (tramp-compat-set-file-times - newname - (file-attribute-modification-time (file-attributes filename)) - (unless ok-if-already-exists 'nofollow))))) + ;; When newname did exist, we have wrong cached values. + (when (tramp-tramp-file-p newname) + (with-parsed-tramp-file-name newname v2 + (tramp-flush-file-properties v2 v2-localname)))))) + + ;; KEEP-DATE handling. + (when keep-date + (tramp-compat-set-file-times + newname + (file-attribute-modification-time (file-attributes filename)) + (unless ok-if-already-exists 'nofollow)))))) (defun tramp-smb-handle-delete-directory (directory &optional recursive trash) "Like `delete-directory' for Tramp files." @@ -1308,46 +1306,45 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name (if (tramp-tramp-file-p filename) filename newname) nil - (unless (file-exists-p filename) - (tramp-error v 'file-missing filename)) - (when (and (not ok-if-already-exists) (file-exists-p newname)) - (tramp-error v 'file-already-exists newname)) - (when (and (file-directory-p newname) - (not (directory-name-p newname))) - (tramp-error v 'file-error "File is a directory %s" newname)) + (tramp-barf-if-file-missing v filename + (when (and (not ok-if-already-exists) (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + (when (and (file-directory-p newname) + (not (directory-name-p newname))) + (tramp-error v 'file-error "File is a directory %s" newname)) - (with-tramp-progress-reporter - v 0 (format "Renaming %s to %s" filename newname) - - (if (and (not (file-exists-p newname)) - (tramp-equal-remote filename newname) - (string-equal - (tramp-smb-get-share (tramp-dissect-file-name filename)) - (tramp-smb-get-share (tramp-dissect-file-name newname)))) - ;; We can rename directly. - (with-parsed-tramp-file-name filename v1 - (with-parsed-tramp-file-name newname v2 - - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v1 v1-localname) - (tramp-flush-file-properties v2 v2-localname) - (unless (tramp-smb-get-share v2) - (tramp-error - v2 'file-error - "Target `%s' must contain a share name" newname)) - (unless (tramp-smb-send-command - v2 (format "rename %s %s" - (tramp-smb-shell-quote-localname v1) - (tramp-smb-shell-quote-localname v2))) - (tramp-error v2 'file-error "Cannot rename `%s'" filename)))) - - ;; We must rename via copy. - (copy-file - filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid) - (if (file-directory-p filename) - (delete-directory filename 'recursive) - (delete-file filename)))))) + (with-tramp-progress-reporter + v 0 (format "Renaming %s to %s" filename newname) + + (if (and (not (file-exists-p newname)) + (tramp-equal-remote filename newname) + (string-equal + (tramp-smb-get-share (tramp-dissect-file-name filename)) + (tramp-smb-get-share (tramp-dissect-file-name newname)))) + ;; We can rename directly. + (with-parsed-tramp-file-name filename v1 + (with-parsed-tramp-file-name newname v2 + + ;; We must also flush the cache of the directory, because + ;; `file-attributes' reads the values from there. + (tramp-flush-file-properties v1 v1-localname) + (tramp-flush-file-properties v2 v2-localname) + (unless (tramp-smb-get-share v2) + (tramp-error + v2 'file-error + "Target `%s' must contain a share name" newname)) + (unless (tramp-smb-send-command + v2 (format "rename %s %s" + (tramp-smb-shell-quote-localname v1) + (tramp-smb-shell-quote-localname v2))) + (tramp-error v2 'file-error "Cannot rename `%s'" filename)))) + + ;; We must rename via copy. + (copy-file + filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid) + (if (file-directory-p filename) + (delete-directory filename 'recursive) + (delete-file filename))))))) (defun tramp-smb-action-set-acl (proc vec) "Set ACL data." diff --git a/tramp-sshfs.el b/tramp-sshfs.el index eb46258fcc..0efa7bd53f 100644 --- a/tramp-sshfs.el +++ b/tramp-sshfs.el @@ -250,6 +250,9 @@ arguments to pass to the OPERATION." (defun tramp-sshfs-handle-process-file (program &optional infile destination display &rest args) "Like `process-file' for Tramp files." + ;; STDERR is not impelmemted. + (when (consp destination) + (setcdr destination `(,tramp-cache-undefined))) (tramp-skeleton-process-file program infile destination display args (let ((coding-system-for-read 'utf-8-dos)) ; Is this correct? @@ -259,25 +262,18 @@ arguments to pass to the OPERATION." (tramp-unquote-shell-quote-argument localname) (mapconcat #'tramp-shell-quote-argument (cons program args) " "))) (when input (setq command (format "%s <%s" command input))) - (when stderr (setq command (format "%s 2>%s" command stderr))) - - (unwind-protect - (setq ret - (apply - #'tramp-call-process - v (tramp-get-method-parameter v 'tramp-login-program) - nil outbuf display - (tramp-expand-args - v 'tramp-login-args nil - ?h (or (tramp-file-name-host v) "") - ?u (or (tramp-file-name-user v) "") - ?p (or (tramp-file-name-port v) "") - ?a "-t" ?l command))) - - ;; Synchronize stderr. - (when tmpstderr - (tramp-cleanup-connection v 'keep-debug 'keep-password) - (tramp-fuse-unmount v)))))) + + (setq ret + (apply + #'tramp-call-process + v (tramp-get-method-parameter v 'tramp-login-program) + nil outbuf display + (tramp-expand-args + v 'tramp-login-args nil + ?h (or (tramp-file-name-host v) "") + ?u (or (tramp-file-name-user v) "") + ?p (or (tramp-file-name-port v) "") + ?a "-t" ?l command)))))) (defun tramp-sshfs-handle-rename-file (filename newname &optional ok-if-already-exists) diff --git a/tramp-sudoedit.el b/tramp-sudoedit.el index bd902a45fc..ff01eac5b9 100644 --- a/tramp-sudoedit.el +++ b/tramp-sudoedit.el @@ -244,84 +244,88 @@ absolute file names." (unless (memq op '(copy rename)) (error "Unknown operation `%s', must be `copy' or `rename'" op)) - (setq filename (file-truename filename)) (if (file-directory-p filename) (progn (copy-directory filename newname keep-date t) (when (eq op 'rename) (delete-directory filename 'recursive))) - - ;; FIXME: This should be optimized. Computing `file-attributes' - ;; checks already, whether the file exists. - (let ((t1 (tramp-sudoedit-file-name-p filename)) - (t2 (tramp-sudoedit-file-name-p newname)) - (file-times (file-attribute-modification-time - (file-attributes filename))) - (file-modes (tramp-default-file-modes filename)) - (attributes (and preserve-extended-attributes - (file-extended-attributes filename))) - (sudoedit-operation - (cond - ((and (eq op 'copy) preserve-uid-gid) '("cp" "-f" "-p")) - ((eq op 'copy) '("cp" "-f")) - ((eq op 'rename) '("mv" "-f")))) - (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) - - (with-parsed-tramp-file-name (if t1 filename newname) nil - (tramp-barf-if-file-missing v filename - (when (and (not ok-if-already-exists) (file-exists-p newname)) - (tramp-error v 'file-already-exists newname)) - (when (and (file-directory-p newname) - (not (directory-name-p newname))) - (tramp-error v 'file-error "File is a directory %s" newname)) - - (if (or (and (tramp-tramp-file-p filename) (not t1)) - (and (tramp-tramp-file-p newname) (not t2))) - ;; We cannot copy or rename directly. - (let ((tmpfile (tramp-compat-make-temp-file filename))) - (if (eq op 'copy) - (copy-file filename tmpfile t) - (rename-file filename tmpfile t)) - (rename-file tmpfile newname ok-if-already-exists)) - - ;; Direct action. - (with-tramp-progress-reporter - v 0 (format "%s %s to %s" msg-operation filename newname) - (unless (tramp-sudoedit-send-command - v sudoedit-operation - (tramp-unquote-file-local-name filename) - (tramp-unquote-file-local-name newname)) - (tramp-error - v 'file-error - "Error %s `%s' `%s'" msg-operation filename newname)))) - - ;; When `newname' is local, we must change the ownership to - ;; the local user. - (unless (tramp-tramp-file-p newname) - (tramp-set-file-uid-gid - (concat (file-remote-p filename) newname) - (tramp-get-local-uid 'integer) - (tramp-get-local-gid 'integer))) - - ;; Set the time and mode. Mask possible errors. - (when keep-date - (ignore-errors - (tramp-compat-set-file-times - newname file-times (unless ok-if-already-exists 'nofollow)) - (set-file-modes newname file-modes))) - - ;; Handle `preserve-extended-attributes'. We ignore possible - ;; errors, because ACL strings could be incompatible. - (when attributes - (ignore-errors - (set-file-extended-attributes newname attributes))) - - (when (and t1 (eq op 'rename)) - (with-parsed-tramp-file-name filename v1 - (tramp-flush-file-properties v1 v1-localname))) - - (when t2 - (with-parsed-tramp-file-name newname v2 - (tramp-flush-file-properties v2 v2-localname)))))))) + (if (file-symlink-p filename) + (progn + (make-symbolic-link + (file-symlink-p filename) newname ok-if-already-exists) + (when (eq op 'rename) (delete-file filename))) + + ;; FIXME: This should be optimized. Computing `file-attributes' + ;; checks already, whether the file exists. + (let ((t1 (tramp-sudoedit-file-name-p filename)) + (t2 (tramp-sudoedit-file-name-p newname)) + (file-times (file-attribute-modification-time + (file-attributes filename))) + (file-modes (tramp-default-file-modes filename)) + (attributes (and preserve-extended-attributes + (file-extended-attributes filename))) + (sudoedit-operation + (cond + ((and (eq op 'copy) preserve-uid-gid) '("cp" "-f" "-p")) + ((eq op 'copy) '("cp" "-f")) + ((eq op 'rename) '("mv" "-f")))) + (msg-operation (if (eq op 'copy) "Copying" "Renaming"))) + + (with-parsed-tramp-file-name (if t1 filename newname) nil + (tramp-barf-if-file-missing v filename + (when (and (not ok-if-already-exists) (file-exists-p newname)) + (tramp-error v 'file-already-exists newname)) + (when (and (file-directory-p newname) + (not (directory-name-p newname))) + (tramp-error v 'file-error "File is a directory %s" newname)) + + (if (or (and (tramp-tramp-file-p filename) (not t1)) + (and (tramp-tramp-file-p newname) (not t2))) + ;; We cannot copy or rename directly. + (let ((tmpfile (tramp-compat-make-temp-file filename))) + (if (eq op 'copy) + (copy-file filename tmpfile t) + (rename-file filename tmpfile t)) + (rename-file tmpfile newname ok-if-already-exists)) + + ;; Direct action. + (with-tramp-progress-reporter + v 0 (format "%s %s to %s" msg-operation filename newname) + (unless (tramp-sudoedit-send-command + v sudoedit-operation + (tramp-unquote-file-local-name filename) + (tramp-unquote-file-local-name newname)) + (tramp-error + v 'file-error + "Error %s `%s' `%s'" msg-operation filename newname)))) + + ;; When `newname' is local, we must change the ownership + ;; to the local user. + (unless (tramp-tramp-file-p newname) + (tramp-set-file-uid-gid + (concat (file-remote-p filename) newname) + (tramp-get-local-uid 'integer) + (tramp-get-local-gid 'integer))) + + ;; Set the time and mode. Mask possible errors. + (when keep-date + (ignore-errors + (tramp-compat-set-file-times + newname file-times (unless ok-if-already-exists 'nofollow)) + (set-file-modes newname file-modes))) + + ;; Handle `preserve-extended-attributes'. We ignore possible + ;; errors, because ACL strings could be incompatible. + (when attributes + (ignore-errors + (set-file-extended-attributes newname attributes))) + + (when (and t1 (eq op 'rename)) + (with-parsed-tramp-file-name filename v1 + (tramp-flush-file-properties v1 v1-localname))) + + (when t2 + (with-parsed-tramp-file-name newname v2 + (tramp-flush-file-properties v2 v2-localname))))))))) (defun tramp-sudoedit-handle-copy-file (filename newname &optional ok-if-already-exists keep-date diff --git a/tramp.el b/tramp.el index f34bb80dc6..ff34c5356d 100644 --- a/tramp.el +++ b/tramp.el @@ -7,13 +7,15 @@ ;; Maintainer: Michael Albinus <michael.albi...@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.7.2.2 +;; Version: 2.7.2.3 ;; Package-Requires: ((emacs 27.1)) ;; Package-Type: multi ;; URL: https://www.gnu.org/software/tramp/ -;; This is a GNU ELPA :core package. Avoid functionality that is not +;; This is also a GNU ELPA package. Avoid functionality that is not ;; compatible with the version of Emacs recorded in trampver.el. +;; Version and Package-Requires are place holders. They are updated +;; when the GNU ELPA package is released. ;; This file is part of GNU Emacs. @@ -124,9 +126,8 @@ :version "22.1" :link '(custom-manual "(tramp)Top")) -;; On MS-DOS, there is no process support. ;;;###autoload -(defcustom tramp-mode (not (eq system-type 'ms-dos)) +(defcustom tramp-mode (fboundp 'make-process) ; Disable on MS-DOS. "Whether Tramp is enabled. If it is set to nil, all remote file names are used literally." :type 'boolean) @@ -2099,7 +2100,7 @@ does not exist, otherwise propagate the error." `(condition-case ,err (progn ,@body) (error - (if (not (file-exists-p ,filename)) + (if (not (or (file-exists-p ,filename) (file-symlink-p ,filename))) (tramp-error ,vec 'file-missing ,filename) (signal (car ,err) (cdr ,err))))))) @@ -3538,12 +3539,19 @@ BODY is the backend specific code." (when (tramp-connectable-p ,filename) (with-parsed-tramp-file-name (expand-file-name ,filename) nil (with-tramp-file-property v localname "file-exists-p" - ;; Examine `file-attributes' cache to see if request can - ;; be satisfied without remote operation. - (if (tramp-file-property-p v localname "file-attributes") - (not - (null (tramp-get-file-property v localname "file-attributes"))) - ,@body)))))) + (cond + ;; Examine `file-attributes' cache to see if request can + ;; be satisfied without remote operation. + ((and-let* + (((tramp-file-property-p v localname "file-attributes")) + (fa (tramp-get-file-property v localname "file-attributes")) + ((not (stringp (car fa))))))) + ;; Symlink to a non-existing target counts as nil. + ;; Protect against cyclic symbolic links. + ((file-symlink-p ,filename) + (ignore-errors + (file-exists-p (file-truename ,filename)))) + (t ,@body))))))) (defmacro tramp-skeleton-file-local-copy (filename &rest body) "Skeleton for `tramp-*-handle-file-local-copy'. @@ -3767,10 +3775,13 @@ BODY is the backend specific code." tmpstderr (tramp-make-tramp-file-name v stderr)))) ;; stderr to be discarded. ((null (cadr ,destination)) - (setq stderr (tramp-get-remote-null-device v))))) + (setq stderr (tramp-get-remote-null-device v))) + ((eq (cadr ,destination) tramp-cache-undefined) + ;; stderr is not impelmemted. + (tramp-warning v "%s" "STDERR not supported")))) ;; t (,destination - (setq outbuf (current-buffer)))) + (setq outbuf (current-buffer)))) ,@body @@ -3806,7 +3817,7 @@ BODY is the backend specific code." ;; We cannot add "file-attributes", "file-executable-p", ;; "file-ownership-preserved-p", "file-readable-p", ;; "file-writable-p". - '("file-directory-p" "file-exists-p" "file-symlinkp" "file-truename") + '("file-directory-p" "file-exists-p" "file-symlink-p" "file-truename") (tramp-flush-file-properties v localname)) (condition-case err (progn ,@body) @@ -4148,10 +4159,9 @@ Let-bind it when necessary.") (defun tramp-handle-file-directory-p (filename) "Like `file-directory-p' for Tramp files." ;; `file-truename' could raise an error, for example due to a cyclic - ;; symlink. We don't protect this despite it, because other errors - ;; might be worth to be visible, for example impossibility to mount - ;; in tramp-gvfs.el. - (eq (file-attribute-type (file-attributes (file-truename filename))) t)) + ;; symlink. + (ignore-errors + (eq (file-attribute-type (file-attributes (file-truename filename))) t))) (defun tramp-handle-file-equal-p (filename1 filename2) "Like `file-equalp-p' for Tramp files." @@ -5462,8 +5472,22 @@ support symbolic links." (insert-file-contents-literally error-file nil nil nil 'replace)) (delete-file error-file))))) - (display-buffer output-buffer '(nil (allow-no-window . t))))) - + (if async-shell-command-display-buffer + ;; Display buffer immediately. + (display-buffer output-buffer '(nil (allow-no-window . t))) + ;; Defer displaying buffer until first process output. + ;; Use disposable named advice so that the buffer is + ;; displayed at most once per process lifetime. + (let ((nonce (make-symbol "nonce"))) + (add-function + :before (process-filter p) + (lambda (proc _string) + (let ((buf (process-buffer proc))) + (when (buffer-live-p buf) + (remove-function (process-filter proc) + nonce) + (display-buffer buf '(nil (allow-no-window . t)))))) + `((name . ,nonce))))))) ;; Insert error messages if they were separated. (when (and error-file (not (process-live-p p))) (ignore-errors diff --git a/trampver.el b/trampver.el index af22093e04..2c5095debc 100644 --- a/trampver.el +++ b/trampver.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albi...@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.7.2.2 +;; Version: 2.7.2.3 ;; Package-Requires: ((emacs "27.1")) ;; Package-Type: multi ;; URL: https://www.gnu.org/software/tramp/ @@ -40,7 +40,7 @@ ;; ./configure" to change them. ;;;###tramp-autoload -(defconst tramp-version "2.7.2.2" +(defconst tramp-version "2.7.2.3" "This version of Tramp.") ;;;###tramp-autoload @@ -76,7 +76,7 @@ ;; Check for Emacs version. (let ((x (if (not (string-version-lessp emacs-version "27.1")) "ok" - (format "Tramp 2.7.2.2 is not fit for %s" + (format "Tramp 2.7.2.3 is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x)))